ps:bean初始化相关的内容实在太多,不得已只好将其分成上下两篇来讲
- 上篇:主要讲解BeanFactory的相关内容,包括后置处理器的相关内容
- 下篇:主要讲解Bean的实例化
系列文章链接:
《SpringBoot源码初学者(一):SpringBoot功能扩展接口的使用与源码分析》
《SpringBoot源码初学者(二):SpringBoot事件监听器》
一、啥子是Bean???
既然大家都是来看源码解析的,what is bean?这种问题显然有点小儿科的了,没有那个会告诉我意思是“小豆子”,那我就自问自答好了,springBean简单的概括:被Spring容器初始化、装配和管理的类,生命周期被spring支配。
1、bean的配置方式(熟悉的小伙伴可以直接跳过)
(1)xml配置
xml配置是早期的配置方式,SpringBoot出现后逐渐被淘汰,配置项复杂繁多,看起来杂乱无章,有些小伙伴入坑时间比较短,甚至没有接触过xml的配置,简单的演示一下,大家看个热闹。
创建bean之前先要有个类,SpringBoot还不能无中生有,不知道大家有没有女票了,没有的小伙伴今天有福气了,今天一人发一个!!!ohhhhhhhhhhhh!!!开搞使用SpringBoot new一个GirlFriend,定制女友贼刺激。
public class GirlFriend{
private String name;
private Integer age;
private Integer height;
private Integer weight;
private List<String> hobby;
public GirlFriend(){}
public GirlFriend(String name,Integer age){
this.name = name;
this.age = age;
}
....getSet省略打发....
}
有了女朋友 还需要带回家,再定义一个Home
public class Home{
private GirlFriend girlFriend;
....getSet省略打发....
}
1)无参构造
在resources中创建一个xml文件,名字随意就好,叫first-love-girlfriend.xml好了
<?xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
做笔记了!!
上面那一大串子,主要功能是对当前的xml文档的格式做限制,什么节点可以出现什么节点不可以出现,这里只添加bean的校验
xmlns:关于初始化bean的格式文件地址
xmlns:xsi:辅助初始化bean
xsi:schemaLocation:用于声明了目标名称空间的模式文档
-->
<!-- 创建一个bean,id:唯一表示 ,class:全路径名-->
<bean id="girlFriend" class="com.gyx.test.GirlFriend">
<!-- 给属性赋值 name:属性名 value:注入的值 -->
<property name="name" value="cuiHua"/>
<!-- 男孩子都喜欢18岁的黄花大姑娘 -->
<property name="age" value="18"/>
<property name="hobby">
<list>
<value>看书</value>
<value>吃零食</value>
</list>
</property>
</bean>
<bean id="home" class="com.gyx.test.Home">
<!-- 使用ref来引用已经定义好的 bean对象 -->
<property name="girlFriend" ref="girlFriend"/>
</bean>
</beans>
2)有参构造
...上面的重复略过....
<!-- 创建一个bean,id:唯一表示 ,class:全路径名-->
<bean id="girlFriend" class="com.gyx.test.GirlFriend">
<!-- 有参构造器注入,index:参数的位置从0开始,value:参数值 -->
<construcort-arg index="0" value="cuiHua">
<construcort-arg index="1" value="18">
<property name="hobby">
<list>
<value>看书</value>
<value>吃零食</value>
</list>
</property>
</bean>
...下面的也重复略过....
3)静态工厂方法
随着业务量的增长,为了解决广大男同胞的单身问题,手动创建已经无法满足需求,创建工厂批量生产
i. 定义抽象类
public abstract class GirlFriend{
abstract String getName();
}
ii. 实现抽象类
萝莉
public class Loli extends GirlFriend {
@Override
String getName(){
return name;
}
}
女王
public class Queen extends GirlFriend {
@Override
String getName(){
return name;
}
}
iii. 实现静态工厂
public class GirlFriendFactory {
@Override
public static GirlFriend getGirlFriend(String type){
if("queen".equals(type)){
return new Queen();
} else if("loli".equals(type)) {
return new Loli();
}else {
return null;
}
}
}
iv. xml配置
...上面的重复略过....
<!-- 创建一个bean,id:唯一表示 ,class:全路径名 ,factory-method:工厂方法 -->
<bean id="loli" class="com.gyx.test.GirlFriendFactory" factory-method="getGirlFriend">
<!-- 传入参数 -->
<construcort-arg value="queen">
</bean>
...下面的也重复略过....
4)实例工厂方法
i. 创建实例工厂
public class GirlFriendFactory {
@Override
public GirlFriend getGirlFriend(String type){
if("queen".equals(type)){
return new Queen();
} else if("loli".equals(type)) {
return new Loli();
}else {
return null;
}
}
}
ii. xml配置
...上面的重复略过....
<bean name="girlFriendFactory" class="com.gyx.test.GirlFriendFactory">
<!-- 创建一个bean,id:唯一表示 ,factory-bean:工厂bean ,factory-method:工厂方法 -->
<bean id="loli" factory-bean="girlFriendFactory" factory-method="getGirlFriend">
<!-- 传入参数 -->
<construcort-arg value="loli">
</bean>
...下面的也重复略过....
(2)java代码方式配置bean
1)@Component注解配置Bean(@Service、@Controller是一样的)
@Component
public class GirlFriend{
private String name;
private Integer age;
private Integer height;
private Integer weight;
private List<String> hobby;
public GirlFriend(){}
public GirlFriend(String name,Integer age){
this.name = name;
this.age = age;
}
....getSet省略打发....
}
2)@Bean注解配置Bean
@Configuration
public class BeanConfiguration{
@Bean
public GirlFriend getGirlFriend(){
return new GirlFriend("cuihua",18);
}
}
3)使用FactoryBean接口配置Bean
@Component
public class MyGirlFriend implements FactoryBean<GirlFriend>{
@Override
public GirlFriend getObject() throws Exception{
return new Loli();
}
}
4)使用BeanDefinitionRegistryPostProcessor接口配置Bean
@Component
public class MyGirlFriend implements BeanDefinitionRegistryPostProcessor{
//注册一个bean对象
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException{
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Queen.class);
registry.registerBeanDefinition("queen",rootBeanDefinition);
}
//这个方法可以向bean对象中注入值
@Override
public void postProcessBeanFactory(ConfiguraleListableBeanFactory beanFactory) throws BeansException{
//获取到刚刚定义的 bean对象的定义
BeanDefinition queen = beanFactory.getBeanDefinition("queen");
//给对象添加属性值
MutablePropertyValues propertyValues = queen.getPropertyValues();
propertyValues.addPropertyValue("name","红太狼");
}
}
5)使用ImportBeanDefinitionRegistrar接口配置Bean
public class MyGirlFriend implements ImportBeanDefinitionRegistrar{
@Override
public void registerBeanDefinition(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry){
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Queen.class);
registry.registerBeanDefinition("queen",rootBeanDefinition);
}
}
二、BeanFactory的解析
在前面的章节中,我们了解了9中创建bean的方式,那么SpringBoot到底是如何创建出这些GirlFriend的,“造人”???停停停,朗朗乾坤搞不得黄色。
创建bean、加载bean的过程,都是被封装在refresh方法中,我一般将这个方法称之为“bean生命启点·spring启动关键·面试必问·refresh”
,之前对源码有所了解的小伙伴,肯定都听说过他的大名,不知道之前你们有没有完全弄懂这个方法,不过这都不要紧了!今天不要998,不要99.8!一篇文章直接带你一步到位,全面学懂refresh方法,话不多说!一起SpringBoot的内心深处吧!!
1、寻找refresh方法的位置
步骤1:照顾新朋友,我们还是从SpringBoot的启动类开始,一步步深入
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//进入run方法
SpringApplication.run(Application.class, args);
}
}
步骤2:ConfigurableApplicationContext类
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
//还是进入run方法
return run(new Class<?>[] { primarySource }, args);
}
步骤3:再次进入run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
//继续点击run方法
//是不是有小伙伴开始疑惑了,这里为什么要点run,构造方法里面又做了什么事情
//赶紧去补补这个系列的第一篇文章吧,答案就在里面
return new SpringApplication(primarySources).run(args);
}
步骤4:好啦!我们又来了SpringBoot的心脏方法,具体注释看这里https://blog.csdn.net/qq_34886352/article/details/104949485
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//这个名字看上去和目标方法很像,点击进去看看
//context是程序的上下文,配置的属性很多东西都在里面
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
步骤5:
refresh方法就在这里
private void refreshContext(ConfigurableApplicationContext context) {
//找到了!当当当!refresh方法就悄悄的躲在这里,毫不起眼,实际上暗藏杀机
refresh(context);
if (this.registerShutdownHook) {
try {
//这个方法会在jvm上注册一个钩子,当程序被关闭的时候,可以保证容器被正确的关闭掉
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
2、refresh方法中的千回百转
步骤6:refresh方法的第一层
protected void refresh(ApplicationContext applicationContext) {
//refresh方法不亏为军事要地!刚进来就碰上了守卫
//判断传入的参数是否为AbstractApplicationContext的子类,如果不是直接异常
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
//进行类型强转,多态的体现,继续点击refresh方法
//这里会发现有3个实现,点AbstractApplicationContext类的
((AbstractApplicationContext) applicationContext).refresh();
}
步骤7:
柳暗花明又一村,可以看出来refresh是一个boss级别的方法!不过大家别慌,方法虽多我们逐一击破
@Override
public void refresh() throws BeansException, IllegalStateException {
//这个方法是加锁的,在同一时间只需有一个线程执行当前方法
synchronized (this.startupShutdownMonitor) {
// 准备刷新!实际开工前的一些准备
// 步骤8
prepareRefresh();
// 获取bean工厂
// 步骤9
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对beanFactory做一些配置
//添加需要忽略的依赖、类加载器、后处理器、解析器等等,对了还有aop相关的后置处理器也是这里配置的
// 步骤12
prepareBeanFactory(beanFactory);
try {
// 在上下文中对BeanFactory进行一些后置的处理
//默认情况下是一个空的实现,但是我们主要会以web服务运行运行,就会走到AnnotationConfigServletWebServerApplicationContext类中,别走错方法了
// 主要是注册web请求相关的处理器、bean和配置
// 步骤13
postProcessBeanFactory(beanFactory);
//实例化并调用bean工厂注册的后置处理器,这步操作必须在创建单例bean之前执行
// 步骤15
invokeBeanFactoryPostProcessors(beanFactory);
//注册bean创建使用的后置处理器
//步骤17
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源,国际化处理
//messageSource是用来做国际化的
//判断BeanFactory是含有messageSource,如果没有就会创建一个
//步骤19
initMessageSource();
// 初始化事件广播器,spring监听器的一部分
//步骤20
initApplicationEventMulticaster();
// 根据上下文环境初始化特定的bean
//如果是web环境,将会进入到ServletWebServerApplicationContext的实现中
//这个方法主要是创建一个web容器,例如SpringBoot内嵌的Tomcat容器
//这里暂时跳过,在后续的更新中会进行详细的解析
onRefresh();
//注册监听器
//向广播器中添加监听器的实现
// 步骤21
registerListeners();
// 初始化单例bean
//这里的内容放到下一篇文章中讲解,敬请期待
//是非常重要的内容,也是面试中常问的内容
finishBeanFactoryInitialization(beanFactory);
// 清空缓存 并发送ContextRefreshedEvent事件
//步骤22
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例bean
destroyBeans();
// 改变 'active'属性的状态
cancelRefresh(ex);
// 抛出异常
throw ex;
}
finally {
// 删除掉所有的缓存,防止占用太大的内存,毕竟执行失败了,这些数据也没用了
resetCommonCaches();
}
}
}
(1)前期准备
步骤8:
准备刷新!实际开工前的一些准备
//有些朋友版本可能和我不一样,进来之后发现并不是这些内容,不要紧点击同名方法就行了
protected void prepareRefresh() {
//记录启动时间
this.startupDate = System.currentTimeMillis();
//修改上下文的状态,将状态切换到active,表示上下文要开始忙碌了,其他人不要来打扰他
this.closed.set(false);
this.active.set(true);
//在debug模式下会打印一些,反正也不会去看的日志
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment
//对属性进行初始化
//这里是2.1.0版本这个方法是空方法了,留下来做扩展的方法
initPropertySources();
// 关键属性的校验,如果必填的属性为空,就会抛出异常
// 详情查看:ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// 对earlyApplicationEvents进行初始化
//SpringBoot监听器相关的内容,用来存放监听器的事件,到对应的位置,这些事件会被逐一触发
//具体内容查看上期内容:https://blog.csdn.net/qq_34886352/article/details/105188150
this.earlyApplicationEvents = new LinkedHashSet<>();
}
prepareRefresh方法实际上和前台小妹的工作是一样的,工作安排如下:
- 早上打卡上班,记录下上班时间,把手机静音,切换到active状态,准备开始一天的工作
- 查看工作安排,由于调整,这段时间比较闲,所有的工作都丢给了别人
- 点名,看看员工是否到齐,逐一确认必填属性是否为空
- 拿出新的拜访登记册
这里教大家怎么使用关键属性的校验,怎么添加一个关键属性
其实也很简单,在第一节课中我们学习了ApplicationContextInitializer接口,其实添加关键属性就是他隐藏的小功能
public class TestInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//从上下文中获取到程序环境
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//设置一个关键属性,进行设置后需要在SpringBoot的配置文件Application中定义这个属性,否则就会抛出异常
environment.setRequiredProperties("girlFriendName");
}
}
奇怪的知识增加了!
(2)BeanFactory的初始化
步骤9:获取bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//下面两个方法都是由GenericApplicationContext子类实现的,查看的时候记得是这个类
//设置bean工厂的属性
// 步骤10
refreshBeanFactory();
//获取bean工厂
// 步骤11
return getBeanFactory();
}
这个方法比较简单,一共做了2件事情:
- 设置beanFactory的序列化id
- 获取beanFactory
步骤10:设置bean工厂属性
protected final void refreshBeanFactory() throws IllegalStateException {
//将refreshed属性设置为true,表明已经开始刷新
//使用CAS技术(compareAndSet),一种保证线程安全的防止无锁的机制,先比较再设置的方式,通过cpu底层完成的
//先比较值是不是false,如果是就改成true
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
//设置用于序列化的id,默认值为:application
this.beanFactory.setSerializationId(getId());
}
步骤11:获取bean工厂
public final ConfigurableListableBeanFactory getBeanFactory() {
//这里方法很简单直接获取的GenericApplicationContext的属性,就是下面这个属性
//属性的初始化是在构造方法中完成的,很简单无参构造方法new出来的
//private final DefaultListableBeanFactory beanFactory;
return this.beanFactory;
}
步骤12:
对bean进行设置,中间涉及部分aop相关的内容
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置表达式解析器 接配置文件中可能出现的SpEL表达式
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//设置属性的编辑器,用来做属性转换、绑定的
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 设置bean的后置处理器,这个是SpringBoot中一个比较重要的机制,后面会专门讲,当bean创建完成之后,会执行的回调方法
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//设置自动装配需要忽略的接口,为什么忽略这些接口,我们放到和后置处理器一起讲
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 给BeanFactory添加解析依赖,当beanFactory自身需要被解析、依赖的时候,可以指向自身
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
// 下面这三个也是一样的,当需要解析依赖的时候都指向自身
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 在添加一个后置处理器,用于检测bean是否为监听器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
//containsLocalBean方法会在bean的所有容器中判断,是否包含特定名称的bean
//LOAD_TIME_WEAVER_BEAN_NAME:代码织入的功能,就是aop相关的内容了,以后也会陆续讲到的
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
//在添加一个后置处理器,用来处理代码织入的功能
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// 添加一个零时的类加载器
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册一些默认的bean对象
//运行环境的bean对象
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
//如果包含,那么就创建一个单例bean
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
//系统属性的bean对象
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
//系统运行环境的bean对象
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
总结一波,这个方法看似挺长的,实则很干燥:
- 设置BeanFactory的一些属性
- 添加了几个重要的后置处理器
- 设置自动装配需要忽略的接口
- 手动注册了一些默认的bean
步骤13:这个方法存在于AnnotationConfigServletWebServerApplicationContext类中,是子类的实现,看名字就知道是处理注解配置web服务的上下文类
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//看起来这个类还不是很“成熟”,有事直接找家长,go!去找他的监护人
super.postProcessBeanFactory(beanFactory);
//是否设置了基础包,就是扫描注解的范围
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
//这个也是一样的,判断是否设置需要扫描的带注解的类
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
步骤14:此方法存在于ServletWebServerApplicationContext类中,也就是AnnotationConfigServletWebServerApplicationContext类的父类,不带有注解配置相关信息的上下文类
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//添加后置处理器,让web应用的bean可以获取(aware)到这个山下文
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));
//自动装配忽略ServletContextAware类型的对象
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
(3)使用BeanFactory注册bean的定义
我们先要了解2个接口,这用有助于后续源码的阅读:
- BeanDefinitionRegistryPostProcessor:bean定义注册器后置处理器,可以用于注册、删除bean的定义,同时还能修改bean的属性值
实现方法postProcessBeanDefinitionRegistry方法(注册bean定义)和postProcessBeanFactory方法(注入bean属性) - BeanFactoryPostProcessor:bean的后置处理器,能修改bean的属性值
实现方法postProcessBeanFactory方法(注入bean属性)
步骤15:
实例化并调用bean工厂注册的后置处理器,如果指定了顺序必须按顺序执行
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//getBeanFactoryPostProcessors方法,会获取bean工厂的后置处理器,后置处理器是通过初始化和监听器实现的添加,具体的可以点方法,然后寻找到添加属性的方法,在看方法的调用位置
//初始化注入的类叫做ConfigurationWarningsApplicationContextInitializer实现了ApplicationContextInitializer接口,是我们第一篇文章内容就讲到了,ApplicationContextInitializer接口的工作原理
//监听器的类叫做ConfigFileApplicationListener,第二篇文章的内容,好好翻翻前面的文章吧
//下面看一下invokeBeanFactoryPostProcessors方法,这个方法非常长,100多行,不过不要紧,原理很简单,我们一起看
// 步骤16
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 这里会检测是否有Aop的存在,如果有就会添加相关的后置处理器,用于后续的织入
//这个就是后续Aop相关的内容了,这里不做讨论
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
步骤16:
调用bean工厂的后置处理器
参数说明:
beanFactory:用来创建实例化bean的工厂对象
beanFactoryPostProcessors:当前这个工厂的后置处理器(对bean工厂进行加强)
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//processedBeans中存放着需要优先处理的bean,实现了PriorityOrdered接口或者Ordered接口的对象,
//防止这些对象被重复执行,客官往后看,后面解释
Set<String> processedBeans = new HashSet<>();
//判断beanFactory是否属于BeanDefinitionRegistry类型的
//BeanDefinitionRegistry主要有一下几个功能
//1.以key-value的形式注册bean,key为beanName,value为beanDefinition(bean的定义,含有bean几乎所有的信息)
//2.根据beanName获取或者删除掉beanDefiniation
//3.根据beanName判断beanDefinition是否存在
if (beanFactory instanceof BeanDefinitionRegistry) {
//进行类型转换
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//处理会在这里被细分归类
//regularPostProcessors用来存放普通的后置处理器
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//registryProcessors用来存放bean注册相关的处理器
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//循环后置处理器,并将它们归类
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//判断是否为bean注册相关的后处理器的方法很简单
//直接判断是否直接或间接的实现了BeanDefinitionRegistryPostProcessor接口
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
//将后置处理器进行类型转换
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//所有实现了BeanDefinitionRegistryPostProcessor接口的类,都需要实现postProcessBeanDefinitionRegistry这个方法
//SpringBoot启动到这一步的时候,这些实现类便可以获取到bean定义的注册表
//根据之前的注释可以知道BeanDefinitionRegistry有着所有bean的定义,那么就可以在这一步实现添加bean对象,删除bean对象的操作
//这正是上文中“java代码方式配置bean”的第四种方法的原理
registryProcessor.postProcessBeanDefinitionRegistry(registry);
//归类到对应的集合中
registryProcessors.add(registryProcessor);
}
else {
//除了bean注册相关的后置处理器,就是普通的处理器,直接通过else分类就好了
regularPostProcessors.add(postProcessor);
}
}
//currentRegistryProcessors中按照优先级顺序存放 bean定义注册表的后置处理器
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//从bean工厂根据类型获取bean的名称,三个参数分别的意思为
//第一个参数:查询beanName使用的类型
//第二个参数:true:从所有的bean中查找,false:从单例bean中查找
//第三个参数:可以简单的理解是否使用缓存机制
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//遍历获取到的bean定义注册表的后置处理器
for (String ppName : postProcessorNames) {
//判断当前后置处理器有没有实现PriorityOrdered接口,如果实现返回true
//这里有必要说明一下 PriorityOrdered接口 和 Ordered接口
//PriorityOrdered是Ordered的子类,两者都是用于设置调用的优先级,当是PriorityOrdered的优先度比Ordered优先度更高,永远先调用实现了PriorityOrdered的类
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//将当前bean实例化,并且存放到currentRegistryProcessors中,getBean方法后面会详细说明
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//将其添加到processedBeans中,优先处理他们
processedBeans.add(ppName);
}
}
//将currentRegistryProcessors根据优先级排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//将这些bean定义注册表的后置处理器,添加到registryProcessors中(里面存放的是所有和bean注册相关的后置处理器)
registryProcessors.addAll(currentRegistryProcessors);
//这个方法会依次调用集合中对象的方法
//忘记postProcessBeanDefinitionRegistry方法的小伙伴,全文搜索一下,上面有详细的解释
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//最后清空掉集合中的内容
currentRegistryProcessors.clear();
// 再次获取一边Bean定义注册表后置处理器
//不同的是上面处理的是实现了PriorityOrdered接口的对象,这里处理的是实现了Ordered接口的对象
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//这里和上面一样,将PriorityOrdered接口和Ordered接口的实现做一个分离
for (String ppName : postProcessorNames) {
//注意!!这次获取的是实现了Ordered接口的对象
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//一样的排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//一样的添加,registryProcessors集合中的对象是已经排序好的了
registryProcessors.addAll(currentRegistryProcessors);
//调用postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//然后清空currentRegistryProcessors
currentRegistryProcessors.clear();
// 最后,有些BeanDefinitionRegistryPostProcessor可能没有实现PriorityOrdered接口或者Ordered接口
//直接通过一个循环将这些对象调用了,不需要考虑执行顺序
//当所有的BeanDefinitionRegistryPostProcessor执行完毕后,reiterate为false
boolean reiterate = true;
while (reiterate) {
reiterate = false;
// 再次获取一边Bean定义注册表后置处理器
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//所有的都循环判断,然后执行
for (String ppName : postProcessorNames) {
//processedBeans方法最初创建的集合,用来排除之前执行过的BeanDefinitionRegistryPostProcessor对象
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
//到这里又和上面是一样的了,就不多说了,这都是第三遍了
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// 好了!!到这里位置,所有的BeanDefinitionRegistryPostProcessor对象都被调用过了
//上面处理的是BeanDefinitionRegistryPostProcessor接口的
//下面这两句处理的是BeanFactoryPostProcessor接口
//之前执行的实际上都是注册逻辑,真正的bean工厂的后置回调才刚刚开始
//invokeBeanFactoryPostProcessors循环调用集合对象中的postProcessBeanFactory方法
//registryProcessors和regularPostProcessors中的对象必然是实现了BeanFactoryPostProcessor接口的
//必然会实现postProcessBeanFactory方法,跑就玩了
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
//这个else是当bean工厂并非BeanDefinitionRegistry时进入的
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 这里会获取所有的bean工厂的后置处理器的beanName
//为什么这里又获取一次?因为当执行BeanDefinitionRegistryPostProcessor的时候,是很有可能会注册一个普通的bean工厂的后置处理器进来的
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 存放所有实现了PriorityOrdered接口的后置处理器
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 存放所有实现了Ordered接口的后置处理器
List<String> orderedPostProcessorNames = new ArrayList<>();
// 存放两个接口都没有实现的的后置处理器
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
//对后置处理器进行分类
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
//processedBeans中存放的是已经执行过的后置处理器的BeanName,可以用来判断是否已经执行了
//包含说明执行过,直接跳过
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//分离出实现了PriorityOrdered接口的对象,将其实例化,存放到对应集合中
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
//分离出实现了Ordered接口的对象,将BeanName存放到对应集合中
orderedPostProcessorNames.add(ppName);
}
else {
//剩下的自然是两个接口都没有实现的对象
nonOrderedPostProcessorNames.add(ppName);
}
}
// 那么和之前一样!先排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//然后按照顺序执行,不过这次执行是postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 接着轮到实现了Ordered接口的对象
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后是两个接口都没实现的对象
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清空掉bean工厂中的元数据缓存,getBean方法会产生缓存
beanFactory.clearMetadataCache();
}
一起来总结一下,若此之长的方法不过是做了2件事情:
- 调用BeanDefinitionRegistryPostProcessor的实现对象,往容器中添加新的bean定义
- 调用BeanFactoryPostProcessor的实现对象,往这些bean定义中添加属性
(4)Bean的后置处理器
步骤17:注册bean的后置处理器
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//PostProcessorRegistrationDelegate是用来专门处理后置处理器的工具类
//调用注册方法 步骤18
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
步骤18
:真正的开始注册bean的后置处理器
参数回顾!
beanFactory:bean的工厂类,bean的容器
applicationContext:应用程序的上下文,包含程序的环境信息等等
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//获取bean工厂的后置处理器
//别搞错了 之前获取的一直是BeanFactoryPostProcessor,现在要获取BeanPostProcessor
//是从所有的beanDefinition(bean的定义)中获取bean的后置处理器
//所以并不是之前用addBeanPostProcessor方法添加的后置处理器
//另外使用getBeanNamesForType方法获取到的只是bean的名称 并不是实例对象
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//添加一个独特的后置处理器BeanPostProcessorChecker
//BeanPostProcessorChecker是bean后置处理器的一个检测器
//在某个bean实例化的过程中,所有的bean后置处理器都会被应用到这个bean上
//这里说的“应用”,并不是一定要起到什么功能,后置处理器可能发现不是目标类型的bean便跳过了
//但是如果这个后置处理器不能正确的运作在当前bean上,BeanPostProcessorChecker就会检测出来,并且做下标记
//这里就是在计算bean的数量,是判断后置处理器的正确运转的条件之一
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
//将BeanPostProcessorChecker添加到后置处理器容器中
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 存放实现了priorityOrdered接口(优先处理)的后置处理器
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//存放MergedBeanDefinitionPostProcessor类型的后置处理器,特殊的后置处理器
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
//存放实现了ordered接口的后置处理器的beanName
List<String> orderedPostProcessorNames = new ArrayList<>();
//存放没有实现ordered接口的后置处理器的beanName
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
//遍历所有的后置处理器
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//实现了priorityOrdered接口(优先处理)的后置处理器,进入这里
//处理器直接被实例化
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
//添加对应的容器中
priorityOrderedPostProcessors.add(pp);
//MergedBeanDefinitionPostProcessor是个特殊的处理器,他会将bean的定义进行合并
if (pp instanceof MergedBeanDefinitionPostProcessor) {
//添加对应的容器中
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
//实现了Ordered接口(优先处理)的后置处理器,进入这里
orderedPostProcessorNames.add(ppName);
}
else {
//没有实现Ordered接口和priorityOrdered接口的后置处理器
nonOrderedPostProcessorNames.add(ppName);
}
}
// 对实现了priorityOrdered接口的后置处理器根据优先级进行排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//注册后置处理器,循环的将priorityOrderedPostProcessors中的后置处理器添加到BeanFactory的后置处理器容器中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 接着对实现了Ordered接口的后置处理器,实例化,并且分离出MergedBeanDefinitionPostProcessor
//存放实现了ordered接口的后置处理器的实例对象
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
//循环之前保存的beanName
for (String ppName : orderedPostProcessorNames) {
//实例化后置处理器
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
//存放到容器中
orderedPostProcessors.add(pp);
//判断是否为MergedBeanDefinitionPostProcessor(用于合并bean定义的特殊后置处理器)类型的对象
if (pp instanceof MergedBeanDefinitionPostProcessor) {
//添加到对应容器中
internalPostProcessors.add(pp);
}
}
//排序
sortPostProcessors(orderedPostProcessors, beanFactory);
//将讲后置处理器注册到BeanFactory中
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 现在开始处理,没有实现ordered接口也没有实现priorityOrdered接口的后置处理器
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
//再来一次基本套路
for (String ppName : nonOrderedPostProcessorNames) {
//实例化后置处理器
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
//存放到容器中
nonOrderedPostProcessors.add(pp);
//判断是否为MergedBeanDefinitionPostProcessor(用于合并bean定义的特殊后置处理器)类型的对象
if (pp instanceof MergedBeanDefinitionPostProcessor) {
//添加到对应容器中
internalPostProcessors.add(pp);
}
}
//不需要排序,直接将讲后置处理器注册到BeanFactory中
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 最后处理MergedBeanDefinitionPostProcessor类型的后置处理器
// 对MergedBeanDefinitionPostProcessor类型的后置处理器进行排序
sortPostProcessors(internalPostProcessors, beanFactory);
//将讲后置处理器注册到BeanFactory中
registerBeanPostProcessors(beanFactory, internalPostProcessors);
//这时候的后置处理器已经按照要求全部排序,并且进行实例化
// 还需要在所有的后置处理器的后面添加一个用于发现bean是否为监听器的后置处理器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
(5)SpringBoot的一些扩展功能
步骤19:初始化此上下文的消息源,messageSource是用来做国际化的
protected void initMessageSource() {
//获取到BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断BeanFactory中是否存在MessageSource
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
//实例化消息源的bean对象
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 判断是否是个多层的消息源
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
//进行强转,HierarchicalMessageSource为一个多层的消息源
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// 如果没有设定消息的父类,就获取父消息源,并赋值
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// DelegatingMessageSource基本上就是调用父级消息源的工具类,如果没有父级消息源,就什么都不会执行处理
DelegatingMessageSource dms = new DelegatingMessageSource();
//设置父级消息源
dms.setParentMessageSource(getInternalParentMessageSource());
//设置消息源
this.messageSource = dms;
//注册单例bean
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
别看里面的对象名称非常晦涩难懂,其实只是做了一个国家化的初始化工作
步骤20:初始化广播器
protected void initApplicationEventMulticaster() {
//获取BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断是否包含广播器的bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
//实例化广播器,并赋值
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//创建一个默认的广播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
//实例化,并赋值到BeanFactory中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
步骤21:向广播器中添加监听器的实现
protected void registerListeners() {
// 获取所有的监听器,并添加到广播器中
//广播器的初始化在 步骤20 中
//监听器的初始化和注册在上一篇文章中做个非常详细的说明,这里就不多说了
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 获取监听器类型的bean对象的beanName,但是这些对象不能在这里被实例化,因为我们需要让他们通过后置处理器进行处理
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
//添加到容器中缓存起来
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 这里有一个早期的广播器调用
//由于spring的监听器机制在此之前并没有创建完成,但是有可能容器已经触发了某些事件,这些事件会被缓存在earlyApplicationEvents中
//此刻监听器已经准备好了,可以执行之前缓存的事件了
//获取早期的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
//清空掉早期的事件
this.earlyApplicationEvents = null;
//执行刚刚获取的早期事件,一般情况下这里都是空的
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
//广播事件
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
步骤22:清空缓存 并发送ContextRefreshedEvent事件
protected void finishRefresh() {
// 清楚上下文中的缓存
clearResourceCaches();
// 初始化生命周期处理组件
initLifecycleProcessor();
// 启动生命周期处理组件(生命周期组件,先不做讲解,其实蛮简单,小伙伴们有空可以自己先看看)
getLifecycleProcessor().onRefresh();
// 广播ContextRefreshedEvent事件
publishEvent(new ContextRefreshedEvent(this));
// bean的展示视图,这里不是重点,只能算是个附加的功能,暂时不讨论
LiveBeansView.registerApplicationContext(this);
}