Spring 初识
spring 核心思想
- IOC/DI:一个意思,IOC 是思想,DI 是实现
- AOP:面向切面编程,OOP 是面向对象面呈
IOC 容器
- ApplicationContext 是顶级容器。ClassPathXmlApplicationContext 是 xml 方式配置的具体容器; AnnotationConfigApplicationContext 是注解实现的具体容器
- 底层依靠 BeanFactory 实现,内部有个 beanFactory 属性
- beanFactory.singletonObjects 属性,是一个 map,这个就是单例池,所有的完整的 bean 放在这里
- beanFactory.beanDefinitionMap 属性,也是一个 map,放的是所有的的 bean 定义对象(xml定义bean的信息,id,class,lazy,scope 等)
- beanFactory.factoryBeanObjectCache 属性,也是一个 map,放的是由 FactoryBean 方式创建的 bean
- 创建bean的方式是多样的,如果是 FactoryBean 方式,真实 bean 放在 factoryBeanObjectCache,此时 singletonObjects 放的是工厂对象
- 如果创建方式不是 FactoryBean,bean 就放在 singletonObjects 中
AOP
-
根本作用是增强 bean,生成 bean 的代理对象,后面调用的时候也是使用这个代理对象,从而达到扩展 bean 的目的,比如事物、日志
-
底层根据代理实现,可选的有 JDK 动态代理和 cglib
- 如果有接口,就使用 jdk 动态代理,也是 spring 默认的方式
- 如果没有接口,就只能使用 cglib 来创建,此时必须保证类没有被 final 修饰,因为创建的代理对象是类的子类的对象
-
AOP 也是一种思想,实现方式有 AspectJ 和 Advisor
- AspectJ 更强大更灵活 Advisor 功能更单一但是更方便
- spring 事物管理就是使用 Advisor 实现的,因为事物的功能就比较单一:开启事物、提交事物、回滚事物
- 如果自己要做 AOP 一般都是使用 AspectJ
DI
- 方式是多样的,可以构造注入、setter 注入、属性注入(属性注入最方便最主流,这里只说属性注入)
- @Value 注入基本类型,字符串、布尔值、整形、BigDecimal 等,也可以使用 SpEL 表达式读取 properties 和 yaml 配置
- @Autowired 和 @Resource 注入 bean
- @Autowired 是 spring 的注解,@Resource 是 java 的(spring 也提供了解析方法,所以也能用)
- @Autowired 先根据类型注入,如果发现多个再根据名称匹配。@Resource 相反,@Resource 先根据名称注入,如果找不到再根据类型注入
- @Autowired 如果有多个会报错,可以配合 @Qualifier(name = xxx) 指定名称,如果根据名称还是有多个依然会报错
- bean 可以使用使用 @Primary 修饰,提高优先级,@Autowired 如果有多个就不会报错了,优先使用这个 bean
- @Resource 可以指定名称 @Resource(name = xxx)
- @Autowired 和 @Resource 根据名称匹配 bean 时如果不指定 name 属性,都是属性名而不是类首字母小写
循环依赖
-
三种场景会产生
- bean 内部引入自己
- 两个 bean 互相依赖
- 多个 bean 互相依赖
-
解决方案是三级缓存
- 一级缓存:singletonObjects 最终放 bean 的单例池
- 二级缓存:earlySingletonObjects 半成本的 bean,已经有被引用了
- 三级缓存:singletonFactories 半成品的 bean,还未被引用,对象刚被创建就丢这里
-
三级缓存工作原理,需要知道 bean 生命周期才能理解,在后面的文章中再详细说
扩展点(这里只列出能扩展的方式,后面文章再说怎么具体扩展)
- BeanFactoryPostProcessor
- 各种 aware 回调接口
- beanPostProcessor
- InitializingBean
- 自定义 init 方法