IOC
- Java对象:开发者自己创建对象、管理对象,使用时自行管理依赖的注入,比如自行实现单例模式、工厂方法来创建特定的对象;
- SpringBean:由SpringIOC容器统一创建、管理、销毁的Java对象;开发者定义好Bean的配置信息、依赖,由Spring容器在启动时完成Bean的初始化和实例化,并且Bean的整个生命周期由IOC管理,IOC容器创建Bean的过程中会执行一系列回调方法,可由开发者干预和定制;
IOC容器的核心思想是:工厂模式 + 反射机制;
工作方式:Spring在启动时创建容器(本质是ConcurrentHashMap)来存储所有的Bean,根据开发者的注解或XML配置加载Java对象,并向这些Bean注入配置好的依赖属性,减少开发者自己创建对象、维护对象间依赖关系。
SpringBean的作用域
单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)等;
最常见的就是单例;那么使用单例Bean的注意事项:
- 保证Bean是无状态的:不存在可变状态的成员变量;一定要存储数据,使用局部变量或线程本地变量;
- 使用方法传递请求对象,而不是存储在成员变量中;
- 避免使用非线程安全的成员对象;比如SimpleDateFormat;
Bean的声明
首先开发者需要向Spring提供Bean的声明;告知要将哪些Bean注入到Spring容器中;一般的方式有:
- xml声明
- 注解声明
Spring将这些声明加载并封装为:
BeanDefinition
对象;
此对象定义了Bean的元数据信息、含有的依赖、bean的工程、初始化、销毁方法等等;
private Boolean lazyInit; // 是否懒加载 private String[] dependsOn; // 依赖 private volatile Object beanClass; // beanClass对象 private String initMethodName; // 初始化方法 private String destroyMethodName;// 销毁方法 private String factoryBeanName; // factory
Bean的注入方式
1. 字段注入
public class A { @Autowired private B b; }
- 通过反射直接注入特定的字段;
- 代码简洁,不需要构造函数、setter方法;但不利于测试,需要支持反射的测试框架或手动设置依赖;
- 支持自动处理循环依赖(三级缓存)
2. Setter注入
public class A { private B b; @Autowired public void setB(B b) { this.b = b; } }
- 从代码层面明确区分了实例化和初始化,可以在Bean创建完成后,执行Setter注入依赖;
- 封装性被破坏,运行时依赖可以被修改;
- 支持自动处理循环依赖(三级缓存)
3. 构造器注入
public class A { private B b; @Autowired public void setB(B b) { this.b = b; } }
- 强制初始化时,依赖必须存在;
- 强制不可变,不对外提供setter,Bean创建完成后,依赖则不可变;保证安全;
- 不支持自动处理循环依赖,若存在循环依赖,强制报错;可以使用这种注入来约束工程中不好的分层习惯;
Bean的循环依赖
循环依赖是一个不应该出现的、系统结构分层不合理的现象;
但是Spring还是在框架层面一定程度上为开发者解决了这个问题,为了实现:
理想设计
和现实开发
的一种平衡,Spring本身不鼓励循环依赖,鼓励使用构造器注入依赖;
因此Spring的态度是:
支持循环依赖但不鼓励
;
解决循环依赖的核心是:分离Bean的实例化和初始化;
- 完成Bean的创建,让未配置完成的Bean提前暴露出来,可以作为依赖来使用;
- 使用额外的容器,来存储这些提前暴露出来的Bean、未完成初始化的Bean的工厂;
- 因此构造器注入不支持循环依赖;
Bean的实例化和初始化
入口:
doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
- Bean的实例化
- Bean的提前暴露
- Bean的属性填充
- Bean的初始化
- 前置处理
- 初始化
- 后置处理
1. 实例化
Spring按照
BeanDefinition
开始创建Bean对象
调用:
createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法;
判断当前Bean是否有工厂方法、是否有指定的构造函数等;如果都没有,则使用反射通过无参构造函数创建Bean的空对象;
2. 提前暴露
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
3. 属性填充
调用:
populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
完成属性填充;
中间遇到依赖Bean,则填充用户定义的依赖、属性,并扫描Bean实现的Aware接口,回调Aware方法;
如果Bean需要从Spring上下文中获取一些基础设施信息,实现对应的Aware:
- BeenNameAware:获取Beanname;
- ApplicationContextAware:如果Bean要获取ApplicationContext对象;
- BeanClassLoaderAware:获取Bean的类加载器;
- EnvironmentAware:获取环境配置信息等;
4. 初始化Bean
调用:
initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // 调用bean实现的Aware方法 invokeAwareMethods(beanName, bean); // 执行bean的前置处理(如果有) wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); // 执行初始化方法(如果有) invokeInitMethods(beanName, wrappedBean, mbd); // 执行bean的后置处理(如果有,SpringAOP在这里执行) wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); return wrappedBean; }
4.1 前置处理
执行
BeanPostProcessor
中postProcessBeforeInitialization()
PropertyPlaceholderConfigurer
:XML中的占位符,在前置处理中替换为值;
@PostConstruct在前置处理后执行;
4.2 初始化
1、执行实现 InitializingBean 接口的
afterPropertiesSet()
方法(钩子函数)
2、执行用户自定义的
initMethod
初始化方法;
4.3 后置处理
执行
BeanPostProcessor
中postProcessAfterInitialization()
- AnnotationAwareAspectJAutoProxyCreator在此处执行wrapIfNecessary完成代理对象的创建;