前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring(下)

Spring(下)

原创
作者头像
用户8126523
修改2023-04-26 18:35:39
3770
修改2023-04-26 18:35:39
举报
文章被收录于专栏:code1029code1029

4. 基于XML管理Bean

4.13 FactoryBean

4.13.1 FactoryBean位置

4.13.2 实现

  • 项目结构
  • User
代码语言:javascript
复制
package com.example.bean;

public class User {
    private Integer id;

    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
  • UserFactoryBean
代码语言:javascript
复制
package com.example.factory;

import com.example.bean.User;
import org.springframework.beans.factory.FactoryBean;

public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
  • bean.xml
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.example.bean.User">
        <property name="id" value="1001"></property>
        <property name="name" value="admin"></property>
    </bean>

    <bean id="factory" class="com.example.factory.UserFactoryBean"></bean>
</beans>
  • UserFactoryBeanTest
代码语言:javascript
复制
import com.example.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserFactoryBeanTest {
    @Test
    public void testUserFactoryBean(){
        //获取IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        User user = (User) ac.getBean("factory");
        System.out.println(user);
    }
}

4.14 基于xml自动装配

  • 自动装配:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
  • 使用bean标签的autowire属性设置自动装配效果
  • 自动装配方式:byType

byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值 若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null 若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException

  • 自动装配方式:byName

byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值???

  • 实现

UserDao

代码语言:javascript
复制
package com.example.dao;

public interface UserDao {
    void saveUser();
}

UserDaoImpl

代码语言:javascript
复制
package com.example.dao.impl;

import com.example.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void saveUser(){
        System.out.println("save user....");
    }
}

UserService

代码语言:javascript
复制
package com.example.service;

public interface UserService {
    void saveUser();
}

UserServiceImpl

代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void saveUser() {
        userDao.saveUser();
    }
}

UserController

代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;

public class UserController {
    private UserService userService1;

    public void setUserService(UserService userService) {
        this.userService1 = userService;
    }

    public void saveUser(){
        userService1.saveUser();
    }
}

beanByType.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 自动装配 byType -->
    <bean id="userController" class="com.example.controller.UserController" autowire="byType"></bean>
    <bean id="userService" class="com.example.service.impl.UserServiceImpl" autowire="byType"></bean>
    <bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>

</beans>

beanByName.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 自动装配 byName -->
    <bean id="userController" class="com.example.controller.UserController" autowire="byName"></bean>

    <bean id="userService" class="com.example.service.impl.UserServiceImpl" autowire="byName"></bean>
<!--    <bean id="userServiceImpl" class="com.example.service.impl.UserServiceImpl" autowire="byName"></bean>-->

    <bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>
<!--    <bean id="userDaoImpl" class="com.example.dao.impl.UserDaoImpl"></bean>-->
</beans>

AutoTest

代码语言:javascript
复制
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutoTest {
    @Test
    public void testByType(){
        ApplicationContext app = new ClassPathXmlApplicationContext("beanByType.xml");
        UserController userController = app.getBean(UserController.class);
        userController.saveUser();
    }

    @Test
    public void testByName(){
        ApplicationContext app = new ClassPathXmlApplicationContext("beanByName.xml");
        UserController userController = app.getBean(UserController.class);
        userController.saveUser();
    }
}

4.15 工厂方法实例化

代码语言:javascript
复制
<!-- 工厂静态方法实例化-->
<bean id="userDaoStaticFactory" class="com.example.factory.UserStaticFactory" factory-method="getUserDao" scope="prototype"></bean>

<!-- 工厂动态方法实例化-->
<bean id="factory" class="com.example.factory.UserDynamicFactory" scope="prototype"></bean>
<bean id="userDaoDynamicFactory" factory-bean="factory" factory-method="getUserDao" scope="prototype"></bean>
  • UserStaticFactory
代码语言:javascript
复制
package com.example.factory;

import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;

public class UserStaticFactory {
    public static UserDao getUserDao(){
        System.out.println("StaticFactory:getUserDao...");
        return new UserDaoImpl();
    }
}
  • UserDynamicFactory
代码语言:javascript
复制
package com.example.factory;

import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;

public class UserDynamicFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

5. 基于注解管理Bean

5.1 组件扫描

5.1.1 基础

  • 开启组件扫描
代码语言:javascript
复制
<context:component-scan base-package="com.example"></context:component-scan>
  • type:扫描类型
  • context:exclude-filter标签:排除
代码语言:javascript
复制
<context:component-scan base-package="com.example">
    <!-- type="annotation",根据注解排除,expression中设置要排除的注解的全类名 -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>

    <!-- type="assignable",根据类型排除,expression中设置要排除的类型的全类名 -->
    <!--<context:exclude-filter type="assignable" expression="com.example.bean.User"/>-->
</context:component-scan>
  • context:include-filter标签:指定在原有扫描规则的基础上追加的规则
  • use-default-filters属性:取值false表示关闭默认扫描规则。要指定包含的注解,必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
代码语言:javascript
复制
<context:component-scan base-package="com.example" use-default-filters="false">
    <!-- type="annotation",根据注解包含,expression中设置要包含的注解的全类名 -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>

    <!-- type="assignable",根据类型包含,expression中设置要包含的类型的全类名 -->
    <!--  <context:include-filter type="assignable" expression="com.example.bean.User"/> -->
</context:component-scan>

5.1.2 实现

  • 项目结构
  • Person
代码语言:javascript
复制
package com.example.bean;

import org.springframework.stereotype.Repository;

@Repository
public class Person {
}
  • User
代码语言:javascript
复制
package com.example.bean;

import org.springframework.stereotype.Component;

@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • exclude-bean.xml
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
                          http://www.springframework.org/schema/beans
                          http://www.springframework.org/schema/beans/spring-beans.xsd
                          http://www.springframework.org/schema/context
                          https://www.springframework.org/schema/context/spring-context.xsd
                          ">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.example">
        <!-- type:设置排除或包含的依据 -->

        <!-- type="annotation",根据注解排除,expression中设置要排除的注解的全类名 -->
        <!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>  -->

        <!-- type="assignable",根据类型排除,expression中设置要排除的类型的全类名 -->
        <!-- <context:exclude-filter type="assignable" expression="com.example.bean.User"/> -->

    </context:component-scan>


</beans>
  • include-bean.xml
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
                          http://www.springframework.org/schema/beans
                          http://www.springframework.org/schema/beans/spring-beans.xsd
                          http://www.springframework.org/schema/context
                          https://www.springframework.org/schema/context/spring-context.xsd
                          ">
     <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.example" use-default-filters="false">

        <!--
            context:include-filter标签:指定在原有扫描规则的基础上追加的规则
            use-default-filters属性:取值false表示关闭默认扫描规则
            要指定包含的注解,必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
        -->

        <!-- type="annotation",根据注解包含,expression中设置要包含的注解的全类名 -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>

        <!-- type="assignable",根据类型包含,expression中设置要包含的类型的全类名 -->
        <!--  <context:include-filter type="assignable" expression="com.example.bean.User"/> -->

    </context:component-scan>


</beans>
  • ComponentScanTest
代码语言:javascript
复制
import com.example.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ComponentScanTest {
    @Test
    public void test(){
        ApplicationContext app = new ClassPathXmlApplicationContext("exclude-bean.xml");
        User user = app.getBean("user", User.class);
        user.setName("张三");
        System.out.println(user.getName());


        ApplicationContext app2 = new ClassPathXmlApplicationContext("include-bean.xml");
        User user2 = app2.getBean("user", User.class);
        user2.setName("李四");
        System.out.println(user2.getName());
    }
}

5.1.3 使用注解定义 Bean

Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。

注解

说明

@Component

该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。

@Repository

该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Service

该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Controller

该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

5.2 Autowired

  • 单独使用@Autowired注解,默认根据类型装配。【默认是byType】
代码语言:javascript
复制
package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

源码中有两处需要注意:

  • 第一处:该注解可以标注在:构造方法上、方法上、形参上、属性上、注解上
  • 第二处:该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。

5.2.1 属性上

  • UserDao
代码语言:javascript
复制
package com.example.dao;

public interface UserDao {
    void addUser();
}
  • UserDaoImpl
代码语言:javascript
复制
package com.example.dao.impl;

import com.example.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("add user....");
    }
}
  • UserService
代码语言:javascript
复制
package com.example.service;

public interface UserService {
    void addUser();
}
  • UserServiceImpl
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void addUser(){
        userService.addUser();
    }
}
  • property-bean.xml
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.example"></context:component-scan>
</beans>
  • AutowiredTest
代码语言:javascript
复制
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutowiredTest {
    @Test
    public void test(){
        ApplicationContext app = new ClassPathXmlApplicationContext("property-bean.xml");
        UserController userController = app.getBean(UserController.class);
        userController.addUser();
    }
}
  • 构造方法和setter方法都没有提供,仍然可以注入成功

5.2.2 方法上

  • UserServiceImpl
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}

5.2.3 构造方法上

  • UserServiceImpl
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}

5.2.4 形参上

  • UserServiceImpl
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserServiceImpl(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    public UserController(@Autowired UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}

5.2.5 只有一个有参构造函数,无@Autowired

  • UserServiceImpl
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}
  • 当有参数的构造方法只有一个时,@Autowired注解可以省略。有多个构造方法时,测试报错

5.2.6 @Autowired注解和@Qualifier注解联合

  • 新增文件 UserRedisDaoImpl
代码语言:javascript
复制
package com.example.dao.impl;

import com.example.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserRedisDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("UserRedisDaoImpl add user ...");
    }
}
  • 进行测试,报错=》有两个userDao,@Autowired注入的时候,根据类型注入,不知道用哪个
  • 解决:UserServiceImpl用@Autowired的同时,用@Qualifier注解指定bean的名字
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • 再次测试,通过

5.2.7 总结

  • @Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
  • 当带参数的构造方法只有一个,@Autowired注解可以省略。
  • @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。

5.3 @Resource注入

5.3.1 @Resource注解和@Autowired注解的区别

  • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
  • @Autowired注解是Spring框架自己的。
  • @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
  • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
  • @Resource注解用在属性上、setter方法上。
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

5.3.2 引入依赖

  • @Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖
  • JDK8不需要额外引入依赖
  • 高于JDK11或低于JDK8需要引入以下依赖
代码语言:javascript
复制
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

5.3.3 @Resource声明

代码语言:javascript
复制
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    String name() default "";
    String lookup() default "";
    Class<?> type() default java.lang.Object.class;
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}

5.3.4 实现

  • UserDao
代码语言:javascript
复制
package com.example.dao;

public interface UserDao {
    void out();
}
  • UserDaoImpl
代码语言:javascript
复制
package com.example.dao.impl;

import com.example.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository(value="myUserDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void out(){
        System.out.println("user dao....");
    }
}
  • UserService
代码语言:javascript
复制
package com.example.service;

public interface UserService {
    void out();
}
  • UserServiceImpl
代码语言:javascript
复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserServiceImpl implements UserService {
    @Resource(name="myUserDao")  // 根据name注入
    private UserDao UserDao1;

    @Resource
    private UserDao myUserDao; // name未知注入,根据属性名注入

    @Resource
    private UserDao userDao; // 属性名找不到,根据类型注入
                             // 当UserDao有多个实现会报错

    @Override
    public void out() {
        UserDao1.out();
        myUserDao.out();
        userDao.out();
    }
}
  • UserController
代码语言:javascript
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public void out(){
        userService.out();
    }
}
  • bean.xml
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.example"></context:component-scan>

</beans>
  • ResourceTest
代码语言:javascript
复制
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ResourceTest {
    @Test
    public void test(){
        ApplicationContext app = new ClassPathXmlApplicationContext("bean.xml");
        UserController bean = app.getBean(UserController.class);
        bean.out();
    }
}

5.4 全注解开发

  • 全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文
  • MainConfig
代码语言:javascript
复制
package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
//@ComponentScan({"com.example.controller","com.example.service","com.example.dao"})
@ComponentScan("com.example")
//@Import(DataSourceConfiguration.class) // 引入一个分配置
@Import({DataSourceConfiguration.class}) // 引入多个分配置
public class MainConfig {

}
  • DataSourceConfiguration
代码语言:javascript
复制
package com.example.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

// <context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
    @Value("${jdbc_driver}")
    private String driver;

    @Value("${jdbc_url}")
    private String url;
    @Value("${jdbc_username}")
    private String userName;
    @Value("${jdbc_password}")
    private String password;

    @Bean("dataSource") // Spring会将当前方法的返回值以指定名称存储到Spring容器中
    public DataSource f() throws PropertyVetoException {
        // TODO 手动创建c3p0数据源
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(userName);
        dataSource.setPassword(password);
        return dataSource;
    }
}

UserController

代码语言:javascript
复制
package com.example.controller;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Scope("prototype")
@Repository("myUserController")
public class UserController {
    private String name;

    public void out() {
        System.out.println("out running....");
    }

    @PostConstruct
    public void init(){
        System.out.println("init method....");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("destroy method....");
    }
}
  • AllAutoTest
代码语言:javascript
复制
import com.example.config.MainConfig;
import com.example.controller.UserController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MainConfig.class})
public class AllAutoTest {
    @Autowired
    private UserController userController;

    @Test
    public void test(){
        userController.out();
        System.out.println(userController);
    }
}

5.5 Java反射

  • Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。
  • 引入依赖:lombok不用写get、set、toString、构造函数
代码语言:javascript
复制
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
  • Car
代码语言:javascript
复制
package com.example.dao;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@ToString
@Data
public class Car {
    /**
     * 属性
     */
    private String name;
    private int age;
    private String color;

    /**
     * 私有方法
     */
    private void run() {
        System.out.println("run.....");
    }
}
  • CarReflectTest
代码语言:javascript
复制
import com.example.dao.Car;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class CarReflectTest {
    /**
     * 1. 获取Class对象多种方式
     */
    @Test
    public void test01() throws Exception {
        // 1. 类名.class
        Class clazz1 = Car.class;
        System.out.println("clazz1: " + clazz1);

        // 2. 对象.getClass()
        Class clazz2 = new Car().getClass();
        System.out.println("clazz2: " + clazz2);

        // 3. Class.forName("全路径")
        Class clazz3 = Class.forName("com.example.dao.Car");
        System.out.println("clazz3: " + clazz3);

        // 4. 实例化
        Car car = (Car)clazz3.getConstructor().newInstance();
        System.out.println(car);
    }

    /**
     * 2. 获取构造方法
     * @throws Exception
     */
    @Test
    public void test02() throws Exception {
        Class clazz = Car.class;
        // 1. 获取所有构造
        // 1.1 getConstructors()获取所有public的构造方法
        Constructor[] constructors = clazz.getConstructors();
        System.out.println(Arrays.toString(constructors));

        // 1.2 getDeclaredConstructors()获取所有的构造方法public  private
        Constructor[] constructors2 = clazz.getDeclaredConstructors();
        for (Constructor c:constructors2) {
            System.out.println("方法名称:"+c.getName()+" 参数个数:"+c.getParameterCount());
        }

        // 2. 指定有参数构造创建对象
        // 2.1 构造public
        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
        Car car1 = (Car)c1.newInstance("夏利", 10, "红色");
        System.out.println(car1);

        // 2.2 构造private
        Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        c2.setAccessible(true);
        Car car2 = (Car)c2.newInstance("捷达", 15, "白色");
        System.out.println(car2);
    }

    /**
     * 3. 获取属性
     */
    @Test
    public void test03() throws Exception {
        Class clazz = Car.class;
        Car car = (Car)clazz.getDeclaredConstructor().newInstance();

        // 获取所有public属性
        Field[] fields = clazz.getFields();
        System.out.println(Arrays.toString(fields));

        // 获取所有属性(包含私有属性)
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field:fields2) {
            if(field.getName().equals("name")) {
                // 设置允许访问
                field.setAccessible(true); // 不设置,会报错
                field.set(car,"五菱宏光");
                System.out.println(car);
            }
            System.out.println(field.getName());
        }
    }

    /**
     * 4. 获取方法
     * @throws Exception
     */
    @Test
    public void test04() throws Exception {
        Car car = new Car("奔驰",10,"黑色");
        Class clazz = car.getClass();

        // 1. public方法
        Method[] methods = clazz.getMethods();
        for (Method m1:methods) {
            System.out.println("Car Method: " + m1.getName());
            // 执行方法 toString
            if(m1.getName().equals("toString")) {
                String invoke = (String)m1.invoke(car);
                System.out.println("toString执行了:"+ invoke);
            }
        }

        // 2. private方法
        Method[] methodsAll = clazz.getDeclaredMethods();
        for (Method m:methodsAll) {
            // 执行方法 run
            if(m.getName().equals("run")) {
                m.setAccessible(true);
                m.invoke(car);
            }
        }
    }
}

5.6 实现Spring的IoC和DI

  • MyDI注解
代码语言:javascript
复制
package com.example.spring.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD}) // Method declaration
@Retention(RetentionPolicy.RUNTIME)
public @interface MyDI {
}
  • MyBean注解
代码语言:javascript
复制
package com.example.spring.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) // ElementType.TYPE: Class, interface (including annotation type), or enum declaration // 能修饰类、接口、注解、枚举
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBean {
}
  • ApplicationContext接口
代码语言:javascript
复制
package com.example.spring.core;

public interface ApplicationContext {
    Object getBean(Class clazz);
}
  • AnnotationApplicationContext
代码语言:javascript
复制
package com.example.spring.core.impl;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import com.example.spring.core.ApplicationContext;
import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;

public class AnnotationApplicationContext implements ApplicationContext {
    //存储bean的容器
    private HashMap<Class, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    /**
     * 根据包扫描加载bean
     * @param basePackage
     */
    public AnnotationApplicationContext(String basePackage) {
        try {
            String packageDirName = basePackage.replaceAll("\\.", "\\\\");
            Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String filePath = URLDecoder.decode(url.getFile(),"utf-8");
                rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
                loadBean(new File(filePath));
            }
            System.out.println(beanFactory);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //依赖注入
        loadDi();
    }

    private  void loadBean(File fileParent) {
        if (fileParent.isDirectory()) {
            File[] childrenFiles = fileParent.listFiles();
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    //如果是个文件夹就继续调用该方法,使用了递归
                    loadBean(child);
                } else {
                    //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //选中class文件
                    if (pathWithClass.contains(".class")) {
                        //    com.xinzhi.dao.UserDao
                        //去掉.class后缀,并且把 \ 替换成 .
                        String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        try {
                            Class<?> aClass = Class.forName(fullName);
                            //把非接口的类实例化放在map中
                            if(!aClass.isInterface()){
                                MyBean annotation = aClass.getAnnotation(MyBean.class);
                                if(annotation != null){
                                    Object instance = aClass.newInstance();
                                    //判断一下有没有接口
                                    if(aClass.getInterfaces().length > 0) {
                                        //如果有接口把接口的class当成key,实例对象当成value
                                        System.out.println("正在加载【"+ aClass.getInterfaces()[0] +"】,实例对象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass.getInterfaces()[0], instance);
                                    }else{
                                        //如果有接口把自己的class当成key,实例对象当成value
                                        System.out.println("正在加载【"+ aClass.getName() +"】,实例对象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass, instance);
                                    }
                                }
                            }
                        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private void loadDi() {
        for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
            //就是咱们放在容器的对象
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields){
                MyDI annotation = field.getAnnotation(MyDI.class);
                if( annotation != null ){
                    field.setAccessible(true);
                    try {
                        System.out.println("正在给【"+obj.getClass().getName()+"】属性【" + field.getName() + "】注入值【"+ beanFactory.get(field.getType()).getClass().getName() +"】");
                        field.set(obj,beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
  • Brand
代码语言:javascript
复制
package com.example.dao;

import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
import lombok.Data;
import lombok.ToString;

@MyBean
@Data
@ToString
public class Brand {
    private String name;
}
  • Car
代码语言:javascript
复制
package com.example.dao;


import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@ToString
@Data
@MyBean
public class Car {
    /**
     * 属性
     */
    private String name;
    private int age;
    private String color;

    @MyDI
    private Brand brand;

    /**
     * 私有方法
     */
    private void run() {
        System.out.println("run.....");
    }

}
  • IoCTest
代码语言:javascript
复制
import com.example.dao.Car;
import com.example.spring.core.ApplicationContext;
import com.example.spring.core.impl.AnnotationApplicationContext;
import org.junit.Test;

public class IoCTest {
    @Test
    public void test(){
        ApplicationContext app = new AnnotationApplicationContext("com.example");
        Car car = (Car) app.getBean(Car.class);
        System.out.println(car.getBrand());
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 4. 基于XML管理Bean
    • 4.13 FactoryBean
      • 4.13.1 FactoryBean位置
      • 4.13.2 实现
    • 4.14 基于xml自动装配
      • 4.15 工厂方法实例化
      • 5. 基于注解管理Bean
        • 5.1 组件扫描
          • 5.1.1 基础
          • 5.1.2 实现
          • 5.1.3 使用注解定义 Bean
        • 5.2 Autowired
          • 5.2.1 属性上
          • 5.2.2 方法上
          • 5.2.3 构造方法上
          • 5.2.4 形参上
          • 5.2.5 只有一个有参构造函数,无@Autowired
          • 5.2.6 @Autowired注解和@Qualifier注解联合
          • 5.2.7 总结
        • 5.3 @Resource注入
          • 5.3.1 @Resource注解和@Autowired注解的区别
          • 5.3.2 引入依赖
          • 5.3.3 @Resource声明
          • 5.3.4 实现
        • 5.4 全注解开发
          • 5.5 Java反射
            • 5.6 实现Spring的IoC和DI
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档