spring
官方文档:spring
目录
IOC
IOC也称DI,IOC所提供的功能是由DI来实现的,可以认为它们是对同一个概念的不同角度的描述;
控制反转(IOC):将设计好的对象交给容器控制,而不是在对象内部直接控制;
依赖注入(DI):组件之间的依赖关系由容器在运行期决定;
容器加载
IOC加载过程(以AnnotationConfigApplicationContext
注解扫描容器作为入口说明,容器的顶层接口是BeanFactory
):
创建容器对象:在创建容器的过程会创建这些对象:
PathMatchingResourcePatternResolver
:用于解析类路径或者文件系统中的资源文件;DefaultListableBeanFactory
:也是一个容器,实现了BeanDefinitionRegistry
、BeanFactory
等接口;AnnotatedBeanDefinitionReader
:解析class为bean定义,用于扫描class下的bean定义;ClassPathBeanDefinitionScanner
:功能同上一个,用于扫描包下的bean定义;
注册bean定义:调用容器的register方法注册bean定义,实际就是调用上边AnnotatedBeanDefinitionReader
对象的register
方法,具体过程如下:
- 注册bean定义的过程中会解析
Lazy
、Primary
、DependsOn
、Role
、Description
等注解信息并保存到AnnotatedBeanDefinition
对象中; - 将解析到的bean定义信息保存到
BeanDefinitionHolder
- 判断
ScopedProxyMode
- 注册bean定义到容器中(
registerBeanDefinition
方法注册);- 校验bean定义;
- 判断容器中是否已有这个bean定义,如果有的话,根据allowBeanDefinitionOverriding配置确实覆盖bean定义还是抛异常;
- 获取并保存bean定义的别名
刷新容器:调用容器的refresh方法刷新容器,这个方法是整个容器加载的核心方法,大致流程如下:
- 使用
synchronized
对整个方法加锁; - 容器预处理,包含设置开始时间、容器状态、初始化配置的钩子方法、校验environment配置、初始化监听器容器(就是个空Set);
- 获取BeanFactory,就是上面创建容器时创建的
DefaultListableBeanFactory
; - 预处理BeanFactory,主要设置一些参数,具体在[这里](# beanFactory预处理);
- 预处理BeanFactory后置处理器:一个空的钩子函数;
- 执行BeanFactory后置处理器:
BeanFactoryPostProcessor
,这一步会将大量的bean定义加入到容器中,具体流程看[这里](# BeanFactory后置处理器); - 注册Bean后置处理器:
BeanPostProcessor
,注册过程在[这里](# Bean后置处理器) - 初始化messageSource:如果容器中有,则从容器中获取,如果没有,则创建
DelegatingMessageSource
,并放到容器中,用于国际化处理; - 初始化事件分发器;
- 执行空的钩子方法
onRefresh
;springboot中就是扩展的这个方法启动web容器; - 注册监听器;
- 实例化所有非懒加载的单实例bean,创建Bean的核心方法,在[这里](# Bean实例化);
- 发布相应的事件;
- 清除容器加载过程中的缓存信息,主要时反射元数据缓存;
beanFactory
功能说明
spring容器在创建容器对象时会创建一个beanFactory内置在容器中,本文是DefaultListableBeanFactory
,这个保存bean定义、注册并执行后置处理器等很多地方都有用到;
beanFactory预处理
beanFactory预处理内容:
- 类加载器;
- 表达式解析器(spel);
- 属性配置编辑器注册器:
ResourceEditorRegistrar
- 后置处理器:
ApplicationContextAwareProcessor
、ApplicationListenerDetector
、LoadTimeWeaverAwareProcessor
; - 忽略的Aware接口:
EnvironmentAware
、EmbeddedValueResolverAware
、ResourceLoaderAware
、ApplicationEventPublisherAware
、MessageSourceAware
、ApplicationContextAware
- 可用于解析的自动装配:
BeanFactory
、ResourceLoader
、ApplicationEventPublisher
、ApplicationContext
; - 配置信息等;
BeanFactory后置处理器
执行流程
BeanFactory后置处理器执行流程如下(这里的beanFactory就是容器创建时创建的容器):
- 获取容器对象中设置的beanFactoryPostProcessors作为入参;
- 判断beanFactory是否实现了BeanDefinitionRegistry接口(这里都是实现了的);
- 先处理入参的后置处理器,找到实现了
BeanDefinitionRegistryPostProcessor
接口的后置处理器,执行postProcessBeanDefinitionRegistry
方法; - 再处理容器中的后置处理器;
- 先通过
beanFactory.getBeanNamesForType
方法获取所有实现了BeanDefinitionRegistryPostProcessor
接口的bean名称 - 从这些后置处理器的bean中找到实现了
PriorityOrdered
接口的处理器,排序后依次执行postProcessBeanDefinitionRegistry
方法;(这里有一个重要的后置处理器ConfigurationClassPostProcessor
,业务中常用的@ComponentScan
、@PropertySources
、@Configuration
、@Bean
、@Component
、@Import
等注解就是在这里添加到beanDefinition中的,主要实现逻辑在:org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
) - 按上一步的逻辑处理实现了
Ordered
接口的后置处理器 - 再对剩下的
BeanDefinitionRegistryPostProcessor
进行类似的排序并执行; - 然后执行上面这些后置处理器的
postProcessBeanFactory
方法; - 从beanFactory中获取所有实现了
BeanFactoryPostProcessor
接口的bean; - 剔除掉上面已经执行过的
BeanDefinitionRegistryPostProcessor
; - 按上面类似的逻辑对这些后置处理器,分为实现了
PriorityOrdered
接口的、实现了Ordered
接口的和没有实现排序接口的三个list; - 对这三个list依次排序并执行
postProcessBeanFactory
方法; - 最后清理临时变量,执行结束;
小结
spring5.2.x中顶层的BeanFactoryPostProcessor
接口有两个:
BeanFactoryPostProcessor:在bean定义注册之后,bean创建之前执行,具体在上面的源码步骤分析中有;
接口定义,该接口有一个抽象方法,参数就是上面的BeanFactory,可以在这个方法中完成对Bean定义的修改以及属性的修改等,例如CustomAutowireConfigurer
就是通过这个接口添加@Qualifier
注解功能的,另外,强烈不建议在这里实例化bean,如果需要实例Bean,可以在BeanPostProcessor中完成:
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
BeanDefinitionRegistryPostProcessor:这个接口继承BeanFactoryPostProcessor
,也具有相应功能,其继承方法优先执行,同时它自身的抽象方法会在postProcessBeanFactory
方法之前执行;
接口定义,参数是BeanDefinitionRegistry
,可以完成对bean定义的增删改查,上面提到过ConfigurationClassPostProcessor
就是通过这个方法完成Bean定义的扫描的:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
Bean实例化
在spring容器中,单实例的非懒加载的bean的创建过程如下:
- 设置值解析器 —— 用于解析配置文件;
- 初始化LoadTimeWeaverAware;
- 设置参数(临时类加载器、允许缓存bean定义元数据);
- 遍历bean名称,执行后续步骤;
- 获取bean定义;
- 判断bean:不是抽象类、是单实例、不是懒加载、不是FactoryBean;
- 满足条件则调用
getBean
方法继续创建bean; - 如果是FactoryBean,则工厂bean名称前加
&
,原bean名称代表工厂bean返回的bean;
- 满足条件则调用
- 调用
getBean
方法开始获取bean - 解析bean名称 —— 处理有别名的情况;
- 尝试获取bean,获取到则直接返回这个bean,否则继续;
- 尝试从一级缓存获取bean(一级缓存实际就是个
ConcurrentHashMap
) - 如果获取失败并且bean正在创建中,则尝试从二级缓存获取(是一个HashMap);
- 如果又获取失败并且允许提前引用,则尝试从三级缓存获取(也是一个HashMap)—— 三个缓存是个ObjectFactory,在获取bean时会先执行后置处理器的
getEarlyBeanReference
方法,给后置处理器一个增强bean的机会;然后添加到二级缓存,然后将三级缓存的这个bean清除;
- 尝试从一级缓存获取bean(一级缓存实际就是个
- 如果获取失败,则检查bean是否正在创建,如果是则代表有循环依赖,抛出异常,否则继续创建;
- 检查bean定义是否存在父工厂中,如果是则调用父工厂的getBean方法,若不是则继续;
- 标记bean正在创建中;
- 获取并检查bean定义;
- 获取dependsOn,如果有,先检查如果有循环依赖,则抛出异常,否则对依赖的bean调用getBean方法;
- 判断是否单例bean,这里只讨论单例bean的情况,即调用getSingleton方法获取或创建bean;
- 加锁
- 尝试从一级缓存获取,成功则返回,否则继续
- 判断容器状态,如果已被销毁则抛异常;
- 如果是循环创建,则抛异常,否则继续;
- 调用入参对象ObjectFactory的
getObject
方法(入参是个lambda表达式,它是通过调用createBean
方法创建bean,这个方法在后面单独分析)获取或者创建bean; - 去掉bean创建中的标记
- 将bean从二、三级缓存中删除并添加到一级缓存,同时添加到已注册的bean列表中;
- 判断是否FactoryBean,如果是最终会调用
getObject
方法获取bean,否则直接返回当前bean; - 到此,一个bean就创建完成,可以开始创建下一个bean了;
- 再遍历一次bean:判断是否实现了
SmartInitializingSingleton
接口,若是则执行afterSingletonsInstantiated
方法 - 到此,单实例非懒加载的bean就创建完成了;
这里再简单分析下创建bean的方法的大概流程:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
:
- 解析并检查bean定义;
- 遍历所有的
BeanPostProcessor
- 如果找到
InstantiationAwareBeanPostProcessor
后置处理器,则执行postProcessBeforeInstantiation
方法; - 如果后置处理器方法返回值不为空,则直接返回后置处理器返回的对象,然后继续遍历
BeanPostProcessor
执行postProcessAfterInitialization
,改方法返回值作为最终bean返回 —— 相当于该方式创建的bean不需要在初始化了;否则继续调用doCreateBean
方法创建bean,后面的步骤都是在这个方法中实现的; - 检查是否是public的bean;
- 检查instanceSupplier、getFactoryMethodName等;
- 判断是否有
SmartInstantiationAwareBeanPostProcessor
后置处理器,如果有则执行determineCandidateConstructors
方法获取构造器 - 如果找到了构造器会设置解析构造参数赋值然后创建对象,这里不深入讨论,如果没有找到合适的构造器,则继续调用instantiate方法实例化对象;
- instantiate方法中,会判断bean中是否有覆盖方法(即是否有实现接口):
- 没有:通过Class对象获取构造方法,然后通过
BeanUtils.instantiateClass
方法实例化对象; - 有:通过
CglibSubclassCreator
静态内部类创建cglib代理对象;
- 没有:通过Class对象获取构造方法,然后通过
- 将创建好的对象包装到
BeanWrapper
对象中 - 遍历找到
MergedBeanDefinitionPostProcessor
后置处理器,执行postProcessMergedBeanDefinition
方法 - 将bean封装到
ObjectFactory
(重写getObject方法,使用getEarlyBeanReference
方法封装,使得在获取bean之前会执行SmartInstantiationAwareBeanPostProcessor
后置处理器的getEarlyBeanReference
方法,AOP代理就是利用这个方法解决循环依赖下的增强对象),并添加到三级缓存,将bean名称添加注册表; - 后面开始初始化bean;
- 获取
InstantiationAwareBeanPostProcessor
后置处理器并执行postProcessAfterInstantiation
方法 - 获取
InstantiationAwareBeanPostProcessor
后置处理器并执行postProcessProperties
方法(这里有一个重要的后置处理器AutowiredAnnotationBeanPostProcessor
,就是在这个方法中完成注入的,逻辑比较长,大概的注入步骤就是解析依赖封装到InjectedElement
,然后判断并检查依赖类型,然后调用上面的getBean
方法获取Bean,即回到了上面的第7步(调用getBean获取bean),然后反射赋值:ReflectionUtils.makeAccessible(field);field.set(bean, value);
) - 如果bean实现了
BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
接口,则调用对应方法; - 找到
BeanPostProcessor
后置处理器,执行postProcessBeforeInitialization
方法 - 执行初始化方法:先判断如果实现了
InitializingBean
接口,则执行afterPropertiesSet
方法;在判断如果有初始化方法,则执行初始化方法; - 找到
BeanPostProcessor
后置处理器,执行postProcessAfterInitialization
方法 - 再次尝试从缓存中获取当前bean;用于验证缓存中是不是当前bean;
- 判断是否DisposableBean,是的话就注册;
- 到此一个bean的创建步骤就完成了
从上面的过程中可以看出,当产生循环依赖时,原始对象会拥有循环依赖的代理对象,代理对象只会持有原始对象,使用spring注入的对象都是代理对象;另外当调用代理对象方法时,代理对象最终会调用原始对象的方法,在原始对象中this是指向自己的,因此直接使用this调用会导致代理失效;具体如图:
Bean后置处理器
注册过程
注册过程(这里的beanFactory也是容器创建时创建的容器):
- 通过
beanFactory.getBeanNamesForType
方法获取容器中所有的后置处理器; - 按照执行BeanFactory后置处理器的类似逻辑对这些bean,分为实现了
PriorityOrdered
接口的、实现了Ordered
接口的和没有实现排序接口的三个list; - 依次对这三个list排序,然后注册到beanFactory中(注册过程实际就是调用
beanFactory.addBeanPostProcessor
方法添加到成员变量中); - 最后将
ApplicationListenerDetector
后置处理器也注册到beanFactory;
beanPostProcessor是在创建bean的过程中执行的,在上面bean的创建过程中其实已经设计到其执行过程,这里做一些小结;
小结
spring5.2.x中顶层的BeanPostProcessor
接口有五个:
BeanPostProcessor:有两个抽象方法,分别是在调用初始化方法之前和之后执行,后面的几个后置处理器接口都继承自这个接口;
接口定义:
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
InstantiationAwareBeanPostProcessor:实例化bean后置处理器,其包含4个抽象方法:
postProcessBeforeInstantiation
:会在创建bean对象之前执行,如果这个方法返回值不为空,则会将该返回值作为bean注册到容器中,跳过原始bean创建步骤中的实例化和初始化过程;也就是说这个方法给后置处理器一个机会来提前创建自定义的bean;postProcessAfterInstantiation
:在bean对象被创建并封装到ObjectFactory后执行;其返回值代表后续是否需要为这个bean的属性赋值,也就是是否需要初始化;postProcessProperties
:可以bean的属性值进行修改,上面提到的AutowiredAnnotationBeanPostProcessor
后置处理器,就是在这个方法中调用metadata.inject(bean, beanName, pvs);
完成注入的;postProcessPropertyValues
:5.1以后已被弃用,用上面的方法代替;
SmartInstantiationAwareBeanPostProcessor:这个接口继承自InstantiationAwareBeanPostProcessor
接口,添加了3个抽象方法:
predictBeanType
:用于预测bean的类型determineCandidateConstructors
:在实例化bean之前如果有这个方法,会尝试通过这个方法选择合适的构造器getEarlyBeanReference
:从三级缓存中获取bean之前就会执行这个方法;这个方法在处理循环依赖、代理对象时非常有用
MergedBeanDefinitionPostProcessor:AutowiredAnnotationBeanPostProcessor
这个重要的后置处理器也实现了这个接口,他有两个方法:
postProcessMergedBeanDefinition
:在bean实例化后,放入三级缓存之前执行;一般可以用于获取当前bean及其父类中的所有信息;AutowiredAnnotationBeanPostProcessor
就是在里获取和检查InjectionMetadata
信息的;resetBeanDefinition
:用于清除bean定义信息;
DestructionAwareBeanPostProcessor:bean销毁前回调的后置处理器,有两个方法:
postProcessBeforeDestruction
:bean销毁之前的回调处理方法requiresDestruction
:决定当前bean是否需要销毁
常用注解小结
bean注解
bean常用注解:
@Bean
:配置bean,id默认是方法名@Scope
:设置作用域,@Lazy-bean
:设置懒加载(第一次调用时加载)initMethod
:指定初始化方法(单实例:默认启动时执行,多实例:在获取时执行)destroyMethod
:指定销毁方法(单实例:在关闭时执行(默认会检测close和shutdown方法),多实例:不执行)
@Conditional
:按照条件注册bean(使用方式是实现Condition
接口,在matches方法中编写具体条件,springboot中大量使用的注解,且扩展许多类似功能的注解,如@ConditionalOnBean
、@ConditionalOnClass
、@ConditionalOnMissingBean
等);@Import
:快速导入bean,功能类似@Bean
,id默认是全类名- value除了可以有要导入的类,还可以有实现了
ImportSelector
接口或者ImportBeanDefinitionRegistrar
接口的实现类,用于筛选或添加要导入的bean;
- value除了可以有要导入的类,还可以有实现了
@PostConstruct
:用在方法上,表示该方法会在bean会在创建并赋值完成后执行;@PreDestroy
:用在方法上,表示该方法会在销毁bean之前执行;
赋值注解
赋值常用注解:
@Value
:赋值,主要有下面三种用法:- 直接配置值;
- spel表达式赋值(
#{}
); - 取配置文件中的值(
${}
);
@PropertySource
:加载外部配置文件;@Profile
:可以根据当前环境动态的激活和切换组件功能;- 用在bean上,表示满足指定环境时才注入Bean
- 用在类上,表示满足指定环境时才加载类;
- 没有环境标识注解,则在任何环境下都加载;
- 可以通过启动参数:
-Dspring.profiles.active=
指定环境; - 也可以调用容器的setActiveProfiles方法设置环境(几乎不用);
注入注解
注入常用注解:
@Autowired
:自动注入依赖,- 默认优先按照类型在容器中查找对应组件,如果找到多个,则将属性名称作为id在容器中查找;
- 默认至少要有一个可注入的bean,否则会报错(可以关闭);
@Qualifier
:按名称注入bean;- 可以用在属性、普通方法、@bean方法(可以省略)、构造方法(如果只有一个有参构造方法,则可以省略)上;
- spring底层组件也可以注入
@Primary
:@Autowired
注入时,默认首选要装配的bean;@Resource
:按名称注入(Java规范注解);@Inject
:同@Autowired
(Java规范注解,需要javax.inject依赖);
其他常见接口
bean
bean创建相关的常用接口:
FactoryBean
:也可以注册Bean,使用方法是实现FactoryBean接口并配置到容器中,然后在getObject
方法中返回实际需要注册的Bean即可(此时通过id调用getBean方法就可以返回对应的bean,如果要获取BeanFactory,需要在id前加&
);InitializingBean
:实现该接口的bean会在创建并赋值完成后调用afterPropertiesSet
方法初始化bean;DisposableBean
:实现该接口的bean会在bean销毁时调用destroy
方法;BeanPostProcessor
:bean的后置处理器,即在初始化前后执行(创建并赋值后,init方法的前后执行);(这个接口在spring源码中有多处使用,如上面的@PostConstruct
生命周期注解、@Autowired
注解、Aware接口、参数校验、bean赋值等);BeanFactoryPostProcessor
:beanFactory后置处理器,在BeanFactory初始化之后执行,即,所有bean已经加载但还未创建的时候执行;可以使用这个接口添加一些自定义的bean到容器中;ApplicationListener
:监听容器中的发布事件;
Aware
Aware
:如果想在自定义组件中使用spring底层组件,可以实现对应的xxxAware接口,实现相关方法即可:
ApplicationContextAware
:注入容器对象;BeanNameAware
:注入bean的名字;EmbeddedValueResolverAware
:注入spring字符串解析器(解析功能类似@Value
);ApplicationEventPublisherAware
:容器事件发布器ServletContextAware
:用于web容器,注入ServletContext;ServletConfigAware
:用于web容器,注入ServletConfigMessageSourceAware
:用于国际化处理ResourceLoaderAware
:注入资源加载器BeanFactoryAware
:注入beanFactory;BeanFactoryAware
:注入环境变量,可用于读取配置;ImportAware
:注入AnnotationMetadata
,可以处理一些注解信息;BeanClassLoaderAware
:注入加载bean的类加载器: