Spring容器的IOC和DI概念
IOC(控制反转):对于组件的控制权进行了转移,传统的程序设计是由客户端new出对象,是程序主动创建所依赖的对象。而IOC是专门将对象的创建交给容器处理,组件的控制器交由到了IOC容器中。
DI(依赖注入):组件之间的依赖关系由容器在运行期决定,容器动态将某个依赖关系注入到组件中,主要为了提升组件的复用。
IOC侧重于实现了容器对于组件的管理,DI侧重于对于组件的依赖关系。
Bean加载过程
早期的Spring都是通过配置XML进行Bean加载的,过程大致如下:
XML是配置文件,定义了Spring标签定义;
Resource是Spring对于资源的抽象;
Document是从Resource中读取的XML定义解析为Document;
BeanDefinition是XML文件定义Java对象的一个过程;
Bean最后被实例化成Object对象;
Resource持有URL Resource,主要是为了读取XML的Resource。
读取到XML的Resource之后主要进行XML标签解析,也就是Resource -> Document -> BeanDefinition过程。
BeanDefinition是XML文档的一种表现形式。
IOC容器初始化
IOC容器初始化的核心流程主要有四个步骤:
Bean定义和定位,Bean可能放在XML中,或者一个注解,这些都可以被Resource定位,读取Resource获取BeanDefinition注册到Bean定义的注册表中。
第一次想容器getBean操作会触发Bean创建过程,实例化出一个Bean,根据BeanDefinition中类信息实例化Bean。
将实例化的Bean放到单例缓存中。
之后再次获取向容器getBean时从缓存取。
Bean生命周期
Bean生命周期主要经历四个阶段:
实例化:createBeanInstance方法,主要创建BeanWrapper;
属性赋值:将BeanDefinition中属性赋值到BeanWrapper中;
初始化和setter注入:利用BeanWrapper初始化Bean实例;
销毁:注册响应销毁方法,在容器关闭时触发Bean实例销毁操作;
在Bean实例化过程中,Spring为我们预留了好多API,我们可以在Bean的实例化前后,初始化前后做一些自己的逻辑。
1. 根据BeanDefinition信息,实例化对象,Constructor构造方法;
2. 根据BeanDefinition信息,配置Bean的所有属性(将bean的引用注入到bean对应的属性,*可能存在循环依赖问题);
3. 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName,参数为Bean的Id;
4. 如果Bean实现BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
5. 如果Bean实现ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
5. 如果存在类实现了BeanPostProcessor接口,执行这些实现类的postProcessBeforeInitialization方法,这相当于在Bean初始化之前插入逻辑 ;
6. 如果Bean实现InitializingBean接口, 执行afterPropertiesSet方法;
7. 如果Bean指定了init-method方法,就会调用该方法。例:\<bean init-method="init"> ;
8. 如果存在类实现了BeanPostProcessor接口,执行这些实现类的postProcessAfterInitialization方法,这相当于在Bean初始化之后插入逻辑 ;
9. 这个阶段Bean已经可以使用了,scope为singleton的Bean会被缓存在IOC容器中
10. 如果Bean实现了DisposableBean接口, 在容器销毁的时候执行destroy方法。
11. 如果配置了destory-method方法,就调用该方法。例:\<bean destroy-method="customerDestroy">
其他扩展接口
1.InitializingBean接口
InitializingBean接口中只有一个afterPropertiesSet方法,从方法的名称上很容易理解,这个方法是在Bean的属性都设置值后被调用,用于完成一些初始化工作。当然,在Spring的配置文件中init-method的配置也是在Bean的属性都设置值后被调用,用于完成一些初始化工作,不过在执行顺序上,接口的方法先于配置。值得注意的是,这两种方式都是用于完成一些初始化工作,所以相应的方法中不要编写一些复杂且执行时间很长的逻辑。
2.DisposableBean接口
DisposableBean接口中只有一个destroy方法,该方法会在Bean被销毁、生命周期结束之前被调用,用于做一些销毁的收尾工作。同样,在Spring的配置文件中destroy-method配置也完成同样的工作,不过在执行顺序上,接口的方法先于配置。
3.ApplicationContextAware接口
ApplicationContextAware中只有一个setApplicationContext方法。实现了ApplicationContextAware接口的类,可以在该Bean被加载的过程中获取Spring的应用上下文ApplicationContext,通过ApplicationContext可以获取Spring容器内的很多信息。
4.BeanFactoryAware接口
BeanFactoryAware接口中只有一个setBeanFactory方法。实现了BeanFactoryAware接口的类,可以在该Bean被加载的过程中获取加载该Bean的BeanFactory,同时也可以获取这个BeanFactory中加载的其它Bean。
5.FactoryBean接口
FactoryBean接口可以实现Bean实例化的个性定制,让Spring容器加载我们想要的Bean。实现了FactoryBean接口的类,可以通过实现getObject方法,实现加载我们想要的Bean。
6.BeanPostProcessor接口
BeanPostProcessor接口中有两个方法,分别为postProcessBeforeInitialization和postProcessAfterInitialization。实现了BeanPostProcessor接口的类,会在每个Bean初始化(即调用setter)之前和之后,分别调用这个类中的postProcessBeforeInitialization方法和postProcessAfterInitialization方法,实现初始化的逻辑控制。
7.InstantiationAwareBeanPostProcessor接口
InstantiationAwareBeanPostProcessor接口中,常用的方法是postProcessBeforeInstantiation和postProcessAfterInstantiation。每个Bean的实例化(即调用构造函数)之前和之后,会分别调用实现了该接口的类中的postProcessBeforeInstantiation和postProcessAfterInstantiation方法。
8.BeanFactoryPostProcessor接口
BeanFactoryPostProcessor接口中只有postProcessBeanFactory方法。实现了该接口的类,可以在Bean被创建之前,获取容器中Bean的定义信息,并且可以进行修改。实现类中的postProcessBeanFactory方法只会被执行一次,且先于BeanPostProcessor接口的方法。
Aware接口
LoadTimeWeaverAware:加载Spring Bean时织入第三方模块,如AspectJ
BootstrapContextAware:资源适配器BootstrapContext,如JCA,CCI
ResourceLoaderAware:底层访问资源的加载器
PortletConfigAware:PortletConfig
PortletContextAware:PortletContext
ServletConfigAware:ServletConfig
ServletContextAware:ServletContext
MessageSourceAware:国际化
ApplicationEventPublisherAware:应用事件
NotificationPublisherAware:JMX通知
Aware接口特点
都是Aware接口的子接口,即都继承了Aware接口
父接口Aware中没有定义任何方法
接口内均定义了一个set方法,set参数就是我们需要获取的对象
扩展:
https://www.jianshu.com/p/f78b4b4435c2
https://www.jianshu.com/p/b3e97123fcaf
https://www.jianshu.com/p/a184b5a89850