springIOC基础知识
spring家族包括很多产品和组件,比如spring-framework、springboot、springcloud等等,其中spring-framework是springboot的基础,而springboot又是springcloud的基础,本文就spring-framework5.x相关知识进行学习。本文主要以spring注解的方式进行学习和总结。
在spring-framework中,最为核心的组件为IOC和AOP,本文就IOC的基础知识进行学习和总结。文章下面所谓的spring 特指spring-framework。
IOC
IOC概念,是什么?
定义:IOC即依赖注入,将配置的对象及其所依赖的对象在系统启动时进行创建,并加载到spring的上下文中(准确的说是spring的bean工厂的单例池中),在需要使用时,直接从spring的上下文中获取对应的bean的过程就叫依赖注入。
为什么需要依赖注入?
一般在我们开发web项目时,需要为系统进行分层,如controller层,Service层,dao层,controller层依赖service层,service层依赖dao层,如果不使用spring的依赖注入,则当我们创建一个controller类的实例时,需要先创建一个service类实例,而创建一个service类实例时,我们需要先创建一个dao类实例,创建同一个controller类的另外一个实例时,也需要这同一个过程;如果创建N个controller类实例时,工作量将会进一步加大,大大的加重了开发人员的负担。
使用spring进行依赖注入时,我们需要将spring管理的类及其依赖进行相关配置(包括xml方式和注解方式),在spring启动时由spring负责创建和管理类及其类之间的依赖关系。
被spring创建并管理的类对象称为spring bean。
当我们需要某个bean时,直接从spring中获取,而不需要程序员自己去创建和管理,从而减轻开发人员的负担。
怎么做,即如何进行依赖注入?
依赖注入的方式:
- setter注入
- 构造器注入
注意,如果使用setter注入,必须为类提供一个无参构造方法和对应的setter、getter方法,因为spring在使用setter注入时,是先创建对象在调用setter方法设置属性值。
在注入类时,可以使用xml配置文件的方式进行(目前用得较少了),也可以使用注解的方式进行,如@Controller、@RestController、@Service、@Component等。
名词解释
- spring上下文:是spring中最大的内存单元,里面包含了spring的各种组件,如beanFactory、BeanFactoryPostProcessor池等
- spring的beanFactory:是spring上下文中重要的组件之一,里面包含了单例池、beanDefinetionMap以及各种BeanPostProcessor后置处理器。我们常说的IOC容器指的就是它。
- spring的单例池:是spring的bean工厂中重要的组件之一,我们用@Controller等注解的类最终会生成一个springbean,并存储在这个单例池中
- spring的BeanFactoryPostProcessor:它是spring上下文中的重要组件之一,通过实现BeanFactoryPostProcessor接口,并重写相关方法,可以获取并重新设置BeanDefinition对象。spring扫描、加载路径下的类就是该接口的一个实现类完成的。
- spring的BeanPostProcessor:它是spring的beanFactory中的重要组件之一,通过它,可以完成类的实例化、属性设置和注入、代理设置等一系列的工作。
相关名称的关系对应,如下图所示:
spring-framework 加载Javabean到IOC容器成为springbean过程
spring-framework是如何将配置和注解的类加载到spring容器中,并成为springbean的呢?
即如下代码执行的过程是什么呢?
@ComponentScan("com.xx")
public class MyApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext=new AnnotationConfigApplicationContext(MyApplication.class);
}
}
总体说来,spring将注解的类加载到spring容器中,使之成为springbean,需要经历如下过程:
- 首先将MyApplication类进行扫描和解析,生成BeanDefinition
- 初始化spring上下文以及spring的beanFactory等组件
- 扫描并加载类:扫描某些路径下的所有类,并将扫描到的类用classloader加载到内存。
如用@ComponentScan注解进行扫描路径的指定,如果是springboot项目,默认扫描main方法所在类路径及其子路径下的所有类 - 生成并缓存类的BeanDefinition对象:为扫描并加载到的每个类,生成一个BeanDefinition定义描述对象,
并放到beanFactory的beanDefinetionMap中通过阅读源码,发现扫描、加载类,以及生成类的BeanDefinition对象,
是通过一个叫ConfigurationClassPostProcessor的后置处理器来完成的。 - 初始化事件广播器,并向其添加各种需要事件监听
- 对象的实例化,这系列的操作主要是通过spring的各个BeanPostProcessor来完成的
spring从启动到启动完成,整个过程如下图所示:
spring处理循环依赖
在spring中,默认支持单例的循环依赖,也可以通过修改BeanFactory中allowCircularReferences属性的值,使程序不支持单例的循环依赖。
假设程序中有类A,需要注入属性B,而B类又需要注入属性A,这样就形成了循环的场景。
那么spring是怎么解决循环依赖的呢?具体见下图说明。
注意:上图中只是列出了spring是如何解决循环依赖的大概步骤,事实上在spring中解决循环依赖比图中描述的复杂得多。
执行各个BeanPostProcessor
那么默认情况下,spring为我们提供了如下几个BeanPostProcessor:
-
org.springframework.context.support.ApplicationContextAwareProcessor:回调Aware子类的相关方法,如ApplicationContextAware的setApplicationContext方法等是BeanPostProcessor的直接子类
-
org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor:处理@Import注解相关事宜,是InstantiationAwareBeanPostProcessor和SmartInstantiationAwareBeanPostProcessor的子类
-
org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker:对bean进行校验
-
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator:完成springAOP的BeanPostProcessor,是InstantiationAwareBeanPostProcessor和SmartInstantiationAwareBeanPostProcessor的子类
-
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor:对@PostConstruct和@PreDestroy注解的回调处理,对@Resource注解的注入处理是InstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor的子类
-
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:对@Autowired注解的注入处理
是InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor的子类 -
org.springframework.context.support.ApplicationListenerDetector:如果bean实现了ApplicationListener,则将其添加到监听器中
是MergedBeanDefinitionPostProcessor的子类
spring执行类的实例化过程比较复杂,主要是利用各种BeanPostProcessor的子类来完成,在实例化bean的过程中,依次执行如下步骤:
- InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation
- SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors 获取构造函数,并选择合适的构造函数并缓存起来
- MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition
- InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation
- InstantiationAwareBeanPostProcessor的postProcessProperties
- BeanPostProcessor的postProcessBeforeInitialization
- BeanPostProcessor的postProcessAfterInitialization
目前我看源码,只找到这几个,听说还有更多。