文章目录

  • 1. 自动配置原理
  • 1. 手写一个简单的自动装配示例
  • 2. 手写一个 @Autowired 注解的简单实现
  • 3. 示例小结
  • 2. 简单的 IOC 原理图
  • 3. 容器演变过程
  • 4. Spring 框架的架构设计
  • 5. DeBug 源码验证上述流程
  • 准备工作
  • 开始 Debug
  • 1. 获取并解析 Environment 环境变量
  • 2. ==最核心的 refresh() 方法==
  • 3. BeanFactory 创建过程
  • 4. BeanFactoryPostProcessor 的处理
  • 5. BeanPostProcessor 的处理
  • 6. 注册监听器
  • 7. 实例化


1. 自动配置原理

  • 自动装配本质上就是利用 反射 实现的

1. 手写一个简单的自动装配示例

  • 这是一个很简单的示例
  • 在这个示例中,自动装配的对象是一个写死的对象,主要理解思想
  • 代码实现
  1. 先写一个 UserService ,简单示例,里面就不写业务了
public class UserService {
}
  1. 再写一个需要使用到自动装配的类,UserController
    为了简单,这里也不写什么业务了,只写一个私有属性,和对应的 Getter、Setter
    Getter,为了查看自动注入的效果。
    Setter,为了方便实现注入。
public class UserController {
    @AutoWired
    private UserService userService;

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
  1. 最后就是自动装配的实现类,IOCTest
public class IOCTest {
    @Test
    public void test() throws Exception {
        UserController userController = new UserController();
        UserService userService = new UserService();
        // 获得 userController 对于的 Class 对象
        Class<? extends UserController> clazz = userController.getClass();
        // 获取 userController 类中的所有属性
        Field field = clazz.getDeclaredField("userService");
        // 设置可访问
        field.setAccessible(true);
        // 通过 Setter 方法设置属性
        String fieldName = field.getName();
        // 拼接 Setter 方法名称
        //  1. 得到 UserService
        fieldName = fieldName.substring(0,1).toUpperCase() + fieldName.substring(1, fieldName.length());
        //  2. 得到 setUserService
        String setUserService = "set" + fieldName;
        // 通过方法注入属性对象
        Method method = clazz.getMethod(setUserService, UserService.class);
        // 执行反射
        method.invoke(userController, userService);
        System.out.println("[Controller 中的对象] 是否等于 [创建的对象] " +
                            userController.getUserService().equals(userService));
    }
}
  1. 启动测试
  2. spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗

  3. 可以看到,注入进去的对象和实现准备好的对象是同一个。

2. 手写一个 @Autowired 注解的简单实现

  1. 还是同样的 UserServiceUserController
    不过这里的 Setter 就已经不需要了,
    Getter 还是留着查看结果。
  2. 自定义一个 @Autowired 注解
// 这是用来设置该注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
// 这是设置该注解的适用范围
@Target({ElementType.FIELD})
public @interface AutoWired {
}
  1. UserController 的属性上加上,自定义的 @Autowired 注解

此时该注解还不能起到任何作用,下面来编写具体的装配代码。

  1. 自动装配的类,IOCTest2
public class IOCTest2 {
    @Test
    public void test() throws Exception {
        UserController userController = new UserController();
        // 获得 userController 对于的 Class 对象
        Class<? extends UserController> clazz = userController.getClass();
        // 使用流式计算,遍历所有的 field 属性
        Stream.of(clazz.getDeclaredFields()).forEach(field -> {
            // 获取 AutoWired 注解
            AutoWired annotation = field.getAnnotation(AutoWired.class);
            // 判断是否存在 AutoWired 注解
            if (annotation != null){
                field.setAccessible(true);
                // 获取属性的类型
                Class<?> type = field.getType();
                try {
                    // 根据属性的类型创建对应的对象
                    Object o = type.newInstance();
                    // 设置 field 属性的值为 刚创建的类型对象
                    field.set(userController, o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println(userController.getUserService());
    }
}
  1. 启动测试
  2. spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_02

  3. 也是可以得到一个 UserService 的实例的

3. 示例小结

  • 这个示例虽然和 Spring 底层不一样,但是原理、流程大致相同了,只是缺少了更多完善的异常处理
  • 通过这个示例可以大致了解 Spring IOC 的自动装配的流程:
    1、获得需要进行装配的类的对象
    2、通过这个对象获取到其中的所有属性
    3、遍历所有属性,筛选有注解 @Autowired 的属性
    4、获得有注解 @Autowired 的属性的类型
    5、通过得到的类型,反射生成对应的对象
    6、通过 set() 把这个属性值注入进去

2. 简单的 IOC 原理图

spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_03

3. 容器演变过程

  • Spring IOC 的核心 :通过反射创建对象、操作对象
  1. 最开始创建对象都是使用 new ……
  2. 然后开始使用工厂模式
  3. 现在是 反射 + 工厂模式
  • 有了容器后,基本上就不使用 new 的方式创建对象了
  • 只有 FactoryBean 的 getObject() 方法中,一般自己 new 对象

4. Spring 框架的架构设计

spring 类里边可以注入自身吗 spring中自己注入本身_spring_04

5. DeBug 源码验证上述流程

准备工作

  • 先准备好一个配置文件,我用了一个简单的 jdbcTemplate.xml
<?xml version="1.0" encoding="UTF8" ?>
<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">

<!--    DataSource -->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis_test?useSSL=true&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
<!--  创建 JdbcTemplate 实例 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--    注入 DataSource-->
        <property name="dataSource" ref="datasource"/>
    </bean>
</beans>
  • 然后写一个测试类
public class MyTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("jdbcTemplate.xml");
    }
}

在这句话上打个断点

开始 Debug

1. 获取并解析 Environment 环境变量

spring 类里边可以注入自身吗 spring中自己注入本身_bc_05


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_06

spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_07


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_08


spring 类里边可以注入自身吗 spring中自己注入本身_xml_09


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_10


spring 类里边可以注入自身吗 spring中自己注入本身_xml_11


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_12


spring 类里边可以注入自身吗 spring中自己注入本身_xml_13


spring 类里边可以注入自身吗 spring中自己注入本身_bc_14


spring 类里边可以注入自身吗 spring中自己注入本身_spring_15


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_16


spring 类里边可以注入自身吗 spring中自己注入本身_xml_17


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_18


spring 类里边可以注入自身吗 spring中自己注入本身_xml_19


spring 类里边可以注入自身吗 spring中自己注入本身_spring_20


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_21


spring 类里边可以注入自身吗 spring中自己注入本身_spring_22


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_23


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_24


2. 最核心的 refresh() 方法

spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_25


spring 类里边可以注入自身吗 spring中自己注入本身_bc_26


3. BeanFactory 创建过程

spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_27


spring 类里边可以注入自身吗 spring中自己注入本身_bc_28


spring 类里边可以注入自身吗 spring中自己注入本身_xml_29


spring 类里边可以注入自身吗 spring中自己注入本身_bc_30


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_31


spring 类里边可以注入自身吗 spring中自己注入本身_xml_32


spring 类里边可以注入自身吗 spring中自己注入本身_spring_33


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_34


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_35


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_36

spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_37

spring 类里边可以注入自身吗 spring中自己注入本身_bc_38


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_39


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_40


spring 类里边可以注入自身吗 spring中自己注入本身_bc_41


spring 类里边可以注入自身吗 spring中自己注入本身_xml_42


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_43


4. BeanFactoryPostProcessor 的处理

spring 类里边可以注入自身吗 spring中自己注入本身_spring_44


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_45


spring 类里边可以注入自身吗 spring中自己注入本身_spring_46

spring 类里边可以注入自身吗 spring中自己注入本身_bc_47

spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_48


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_49


5. BeanPostProcessor 的处理

spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_50


spring 类里边可以注入自身吗 spring中自己注入本身_xml_51

spring 类里边可以注入自身吗 spring中自己注入本身_bc_52


6. 注册监听器

spring 类里边可以注入自身吗 spring中自己注入本身_spring_53


spring 类里边可以注入自身吗 spring中自己注入本身_xml_54


spring 类里边可以注入自身吗 spring中自己注入本身_bc_55


7. 实例化

spring 类里边可以注入自身吗 spring中自己注入本身_xml_56


spring 类里边可以注入自身吗 spring中自己注入本身_spring_57

spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_58


spring 类里边可以注入自身吗 spring中自己注入本身_bc_59


spring 类里边可以注入自身吗 spring中自己注入本身_spring_60


spring 类里边可以注入自身吗 spring中自己注入本身_spring_61


spring 类里边可以注入自身吗 spring中自己注入本身_xml_62


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_63


spring 类里边可以注入自身吗 spring中自己注入本身_bc_64


spring 类里边可以注入自身吗 spring中自己注入本身_bc_65


spring 类里边可以注入自身吗 spring中自己注入本身_spring_66


spring 类里边可以注入自身吗 spring中自己注入本身_bc_67


spring 类里边可以注入自身吗 spring中自己注入本身_spring_68


spring 类里边可以注入自身吗 spring中自己注入本身_bc_69


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_70


spring 类里边可以注入自身吗 spring中自己注入本身_spring 类里边可以注入自身吗_71


spring 类里边可以注入自身吗 spring中自己注入本身_自动装配_72