ps:bean初始化相关的内容实在太多,不得已只好将其分成上下两篇来讲
既然大家都是来看源码解析的,what is bean?这种问题显然有点小儿科的了,没有那个会告诉我意思是“小豆子”,那我就自问自答好了,springBean简单的概括:被Spring容器初始化、装配和管理的类,生命周期被spring支配。
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省略.... } 复制代码
在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> 复制代码
...上面的重复略过.... <!-- 创建一个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> ...下面的也重复略过.... 复制代码
随着业务量的增长,为了解决广大男同胞的单身问题,手动创建已经无法满足需求,创建工厂批量生产
public abstract class GirlFriend{ abstract String getName(); } 复制代码
萝莉
public class Loli extends GirlFriend { @Override String getName(){ return name; } } 复制代码
女王
public class Queen extends GirlFriend { @Override String getName(){ return name; } } 复制代码
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; } } } 复制代码
...上面的重复略过.... <!-- 创建一个bean,id:唯一表示 ,class:全路径名 ,factory-method:工厂方法 --> <bean id="loli" class="com.gyx.test.GirlFriendFactory" factory-method="getGirlFriend"> <!-- 传入参数 --> <construcort-arg value="queen"> </bean> ...下面的也重复略过.... 复制代码
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; } } } 复制代码
...上面的重复略过.... <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> ...下面的也重复略过.... 复制代码
@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省略.... } 复制代码
@Configuration public class BeanConfiguration{ @Bean public GirlFriend getGirlFriend(){ return new GirlFriend("cuihua",18); } } 复制代码
@Component public class MyGirlFriend implements FactoryBean<GirlFriend>{ @Override public GirlFriend getObject() throws Exception{ return new Loli(); } } 复制代码
@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","红太狼"); } } 复制代码
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); } } 复制代码
在前面的章节中,我们了解了9中创建bean的方式,那么SpringBoot到底是如何创建出这些GirlFriend的,“造人”???停停停,朗朗乾坤搞不得黄色。 创建bean、加载bean的过程,都是被封装在refresh方法中,我一般将这个方法称之为 “bean生命启点·spring启动关键·面试必问·refresh”
,之前对源码有所了解的小伙伴,肯定都听说过他的大名,不知道之前你们有没有完全弄懂这个方法,不过这都不要紧了!今天不要998,不要99.8!一篇文章直接带你一步到位,全面学懂refresh方法,话不多说!一起SpringBoot的内心深处吧!!
步骤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. } } } 复制代码
步骤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(); } } } 复制代码
步骤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方法实际上和前台小妹的工作是一样的,工作安排如下:
这里教大家怎么使用关键属性的校验,怎么添加一个关键属性 其实也很简单,在第一节课中我们学习了ApplicationContextInitializer接口,其实添加关键属性就是他隐藏的小功能
public class TestInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { //从上下文中获取到程序环境 ConfigurableEnvironment environment = applicationContext.getEnvironment(); //设置一个关键属性,进行设置后需要在SpringBoot的配置文件Application中定义这个属性,否则就会抛出异常 environment.setRequiredProperties("girlFriendName"); } } 复制代码
奇怪的知识增加了!
步骤9:获取bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //下面两个方法都是由GenericApplicationContext子类实现的,查看的时候记得是这个类 //设置bean工厂的属性 // 步骤10 refreshBeanFactory(); //获取bean工厂 // 步骤11 return getBeanFactory(); } 复制代码
这个方法比较简单,一共做了2件事情:
步骤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()); } } 复制代码
总结一波,这个方法看似挺长的,实则很干燥:
步骤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); } 复制代码
我们先要了解2个接口,这用有助于后续源码的阅读:
步骤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件事情:
步骤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)); } 复制代码
步骤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); } 复制代码