Spring 详解
加载 bean
1 | // Spring framework |
context 容器中去获取对象
加载顺序为 类路径 ==> 构造函数 ==> 生成普通对象 ==> 依赖注入 (@AutoAwired) ==> 初始化前(@PostConstruct) ==> 初始化(实现
initializingBean 接口,重写 afterPropertiesSet() 方法)==> 初始化后(AOP) ==> 代理对象 ==> 调用
1 | public class Aa{ |
构造函数
若唯一构造器则则以唯一构造器构造对象;若多个构造器则以无参构造器构造对象,若无无参构造器则报错
先通过类型寻找,找到 Map<beanName, bean>
,再通过对象名去寻找
生成普通对象
当有参构造时,如构造器 Aa(Bb bb)
此时 spring 会查询 IOC 容器中是否有对应对象,查询顺序为 查询类名,若该类名下不止一个对象,则查询对象名,若皆不
匹配则报错
依赖注入
通过 @Autowired 等注解来判断属性是否需要赋值
初始化前
通过注解 @postConstruct,指明当前方法为初始化前执行
初始化
通过实现 initializingBean 接口,重写 afterPropertiesSet() 方法
初始化后
UserServiceProxy ==> 代理对象 ==> 代理对象.target = 普通对象
AOP 逻辑
- 查询所有切面 bean
- 查询所有切面方法
- 查询所有被切方法
- 通过匹配该类来判断是否需要生成代理对象
- 同时这步会生成缓存 map,用于存储切面方法
cglib 代理
- 继承代理类
- 重写切面方法
- 在切面方法中重新调用被切方法,此时为保证被代理对象的唯一性,会将被代理对象赋值给代理对象,作为其属性
1 | // 代理对象简写 |
事务逻辑
- 将 jdbcTemplate 与事务管理器赋值同一数据库连接 (此时必须使用 configuration 注解,保证注入同一数据库连接)
- 在代理对象
test
方法中,首先拿到通过事务管理器数据库连接,再将自动连接改为 false,且在最后进行手动提交- 在普通对象 (被代理对象) 的 test 方法中,因为用的是同一数据库连接,则也不会自动提交
事务失效
而在同类中的事务调用失效问题,即是因为
sx()
在调用在普通对象那一层,则 sx() 方法的调用对象为普通对象,而不是代理对象,所以并不能实现事务管理。解决方法可以选择新建类,实现不同类之间调用,也可以使用自己注入自己,即
1
2
3
4 public class Aa{
private Aa aa;
} 此时的
aa
则为代理对象,再调用aa
的sx()
方法即可
模拟 Spring 底层原理
1 | // Spring framework |
在容器创建时,会去加载非懒加载单例 bean
- 懒加载,通过 @Lazy 表明为懒加载,用时才加载
- 原型 bean(多例),通过 @Scope(“prototype”),每次调用都会新生成
简单流程
AnnotationConfigApplicationContext 创建流程
通过 AppConfig.class 获取需要扫描的包 ==> 通过包名和类加载器路径去获取 class 文件路径 ==> 遍历 class 文件 ==> 通过
class 文件获取基本信息 BeanDefinition,并存入 BeanDefinitionMap<beanName, BeanDefinition>
==> 如果是单例则直接创建
bean,存入 beanMap<beanName, bean>
,通过注解判断 ==> createBean 时依赖注入,通过 Autowired 注解,直接 getBean(
beanName) ==> 同时 aop 也在这一步,通过 BeanPostProcessor 接口,将所有 beanPostProcessor 类存入 BeanPostProcessorList
,
遍历执行 before 和 after 方法 ==> 通过 InitializingBean 接口,实现初始化时调用方法 afterPropertiesSet
核心概率解析
BeanDefinition
表示为 Bean 定义,存在多个属性描述 Bean :
- class, 表示 bean 类型
- scope,表示作用域
- lazyInit,是否为懒加载
- initMethodName,表示 Bean 初始化要执行的方法
- destroyMethodName,表示销毁时要执行的方法
生成 bean 对象方式:
- @Component 注解
- @Bean 注解
标签 - register 注册
BeanFactory 与 ApplicationContext 的区别
1. ApplicationContext 继承了 beanFactory 接口
2. ApplicationContext 还继承了很多其他接口,拥有兵工厂没有的功能,比如事件发布、获取环境化等功能
3. **DefaultListableBeanFactory** 最常用的类,ApplicationContext 中也有调用
Bean 生命周期源码解析
流程为:
生成 BeanDefinition
spring 启动时