文章目录
- 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. 手写一个简单的自动装配示例
- 这是一个很简单的示例
- 在这个示例中,自动装配的对象是一个写死的对象,主要理解思想
- 代码实现
- 先写一个 UserService ,简单示例,里面就不写业务了
public class UserService {
}
- 再写一个需要使用到自动装配的类,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;
}
}
- 最后就是自动装配的实现类,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));
}
}
- 启动测试
- 可以看到,注入进去的对象和实现准备好的对象是同一个。
2. 手写一个 @Autowired 注解的简单实现
- 还是同样的 UserService、UserController
不过这里的 Setter 就已经不需要了,
Getter 还是留着查看结果。 - 自定义一个 @Autowired 注解
// 这是用来设置该注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
// 这是设置该注解的适用范围
@Target({ElementType.FIELD})
public @interface AutoWired {
}
- 在 UserController 的属性上加上,自定义的 @Autowired 注解
此时该注解还不能起到任何作用,下面来编写具体的装配代码。
- 自动装配的类,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());
}
}
- 启动测试
- 也是可以得到一个 UserService 的实例的
3. 示例小结
- 这个示例虽然和 Spring 底层不一样,但是原理、流程大致相同了,只是缺少了更多完善的异常处理
- 通过这个示例可以大致了解 Spring IOC 的自动装配的流程:
1、获得需要进行装配的类的对象
2、通过这个对象获取到其中的所有属性
3、遍历所有属性,筛选有注解 @Autowired 的属性
4、获得有注解 @Autowired 的属性的类型
5、通过得到的类型,反射生成对应的对象
6、通过 set() 把这个属性值注入进去
2. 简单的 IOC 原理图
3. 容器演变过程
- Spring IOC 的核心 :通过反射创建对象、操作对象
- 最开始创建对象都是使用 new ……
- 然后开始使用工厂模式
- 现在是 反射 + 工厂模式
- 有了容器后,基本上就不使用 new 的方式创建对象了
- 只有 FactoryBean 的 getObject() 方法中,一般自己 new 对象
4. Spring 框架的架构设计
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
- 对应的 Debug 的流程图 :https://processon.com/view/5faf8cbdf346fb2d03b5865d
1. 获取并解析 Environment 环境变量
2. 最核心的 refresh() 方法
3. BeanFactory 创建过程
4. BeanFactoryPostProcessor 的处理
5. BeanPostProcessor 的处理
6. 注册监听器
7. 实例化