世界快报:【Spring源码】- 02 Spring IoC容器启动之refresh方法
AnnotationConfigApplicationContext构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法:register(co
AnnotationConfigApplicationContext
构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法:register(componentClasses)
。
之前使用XML
方式:new ClassPathXmlApplicationContext("classpath:spring.xml");
,构造方法中需要指定xml
配置文件路径,然后就可以解析xml
文件中
、
等配置进行IoC
启动初始化。同理,使用注解方式也需要给Context
指定一个起始配置源头,使用配置类代替xml
配置文件,然后根据这个起始配置类一步步的解析下去。
@Configuration@ComponentScan(basePackageClasses = {TestConfig.class})@Import(TestService03.class)public class TestConfig { @Bean public TestService01 testService01(){ return new TestService01(); }}
通过这个配置类,Spring
就可以解析@ComponentScan
、@Import
、@Bean
等这些注解,实现Bean
注入到IoC
容器中。@Configuration
注解定义的配置类就相当于之前xml
配置文件,不过由于现在Spring
主流都推荐注解方式,xml
方案使用的概率会越来越低。
【资料图】
跟踪register(componentClasses)
方法,核心逻辑在:AnnotatedBeanDefinitionReader#doRegisterBean
:
private void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class extends Annotation>[] qualifiers, @Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[] customizers) { //先把此实体类型转换为一个BeanDefinition AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); /** * abd.getMetadata()元数据包括注解信息、是否内部类、类Class基本信息等等 * 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类 * 大体逻辑为:必须有@Configuration修饰,然后解析一些Condition注解,看是否排除~ */ if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(supplier); // 解析Scope ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); // 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator) String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // 设定一些注解默认值,如lazy、Primary等等 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) {// 解析qualifiers,若有此注解 则primary都成为true了 for (Class extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) {// 自定义定制信息(一般都不需要) for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } // 下面解析Scope是否需要代理,最后把这个Bean注册进去 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}
就是将传入的配置类解析成解析成BeanDefinition
,注册到IoC
容器中,后续ConfigurationClassPostProcessor
这个BeanFactory
后置处理器在IoC
开始真正初始化时,可以获取到这些配置类的BeanDefinition
集合,启动解析。
前面分析了AnnotationConfigApplicationContext
构造方法中前两个,这两个方法基本都是IoC
启动的前戏:为IoC
容器的启动做热身准备;真正的IoC
容器启动初始化流程是在refresh()
方法中,这是了解IoC
容器启动流程最关键、核心的一个方法。
refresh
方法定义在AbstractApplicationContext
,采用模板模式,定义好IoC
启动的流程以及每个步骤的作用,并提供基础实现,其它子类可以重写进行扩展。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //Context进行刷新前的准备工作 prepareRefresh(); // 创建并初始化 BeanFactory,这步会将BeanDefinition载入到BeanFactory中 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /** * 填充BeanFactory功能 * 上面获取获取的 BeanFactory其实还不能投入生产,因为还少配置了一些东西,比如 context的 ClassLoader 和 后置处理器等等。 */ prepareBeanFactory(beanFactory); try { /** * 默认空实现,留给子类扩展使用 * 可以参照:AbstractRefreshableWebApplicationContext#postProcessBeanFactory() */ postProcessBeanFactory(beanFactory); /** * 调用BeanFactory后置处理器(包括BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor) */ invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); //初始化消息源 initMessageSource(); //初始化应用上下文事件广播器 initApplicationEventMulticaster(); //初始化其它特殊的Bean,由具体子类实现 onRefresh(); //注册事件监听器 registerListeners(); //初始化所有单实例Bean,使用懒加载模式的Bean除外 finishBeanFactoryInitialization(beanFactory); //完成刷新并发布容器刷新事件 finishRefresh(); } catch (BeansException ex) { ...//省略 } finally { resetCommonCaches(); } }}
下面就来分析下每个方法作用,以了解IoC
容器的启动流程。
prepareRefresh
从方法名称可以看出,该方法主要在refresh
执行前进行一些简单的准备工作,如设置Context
的启动时间、状态,以及系统属性相关扩展。
/** * 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验,如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,重写initPropertySources方法就好了 * * 该方法主要是做一些准备工作,如: * 1、设置 context 启动时间 * 2、设置 context 的当前状态 * 3、初始化 context environment 中占位符 * 4、对属性进行必要的验证 */ protected void prepareRefresh() { //设置启动时间 this.startupDate = System.currentTimeMillis(); //设置context当前状态 this.closed.set(false);//标志context状态:未关闭 this.active.set(true);//标志context状态:活跃中 /** * 初始化context environment(上下文环境)中属性源信息,默认这里是空实现,什么都没做,这里主要提供给子类扩展,采用模板设计模式 * 比如非web环境下,context environment是StandardEnvironment类型,只会在创建时初始化两类属性源:systemEnvironment(系统环境变量) * 和systemProperties(应用环境变量),通过@PropertySource注解等方式配置这时是还没有加载的 * * * 该方法主要有两个常见扩展: * 1、可以在该类中扩展PropertySource来源,如:getEnvironment().getPropertySources().addXXX(PropertySource ps),可以参见GenericWebApplicationContext#initPropertySources() * 2、可以在方法中添加必要属性验证,一些属性对于应用来说是必要的,缺失则会影响系统的正常逻辑, * 如:getEnvironment().setRequiredProperties("DB_IP"),下一步就会从context environment上验证是否存在该属性,如果没有则会抛出异常并退出Spring应用 */ initPropertySources(); /** * 对属性必要性进行校验,逻辑参见:AbstractPropertyResolver#validateRequiredProperties */ getEnvironment().validateRequiredProperties(); //早期事件监听器集合如果为空,就新建一个;如果不为空,就先清空事件监听器集合,然后将早期事件监听器整体放入事件监听器集合。 if (this.earlyApplicationListeners == null) { //默认情况下,earlyApplicationListeners为null this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } //保存容器中的一些早期事件,待事件派发器multicaster初始化完成后进行事件发布 this.earlyApplicationEvents = new LinkedHashSet<>();}
这里主要注意下initPropertySources()
和getEnvironment().validateRequiredProperties()
这两句代码。PropertySource
在Spring
中代表一组变量,即类似对应于一个配置文件,比如@PropertySource("test01.properties")
这个常用的注解就是将配置文件解析成一个PropertySource
对象。
initPropertySources()
方法主要用于扩展配置来源,比如可以从网络、物理文件、数据库等加载配置信息。StandardEnvironment
在创建时,会自动将系统变量System.getProperties()
和应用变量System.getenv()
加载进来,所以initPropertySources
默认只提供的是空实现,主要用于子类扩展使用。
1、可以在该类中扩展
initPropertySources
方法主要有两个常见扩展场景:
PropertySource
来源,如:getEnvironment().getPropertySources().addXXX(PropertySource ps)
,可以参见GenericWebApplicationContext#initPropertySources()
2、可以在方法中添加必要属性验证,一些属性对于应用来说是必要的,缺失则会影响系统的正常逻辑,如:getEnvironment().setRequiredProperties("DB_IP")
,下一步就会从context environment
上验证是否存在该属性,如果没有则会抛出异常并退出Spring
应用getEnvironment().validateRequiredProperties()
这句主要是对setRequiredProperties()
方法设置的属性进行必要性检查,如果某个必要属性环境中不存在,则抛出异常退出应用。
BeanFactory
才是Spring
中基本的IoC
容器,ApplicationContext
其实内部包装了一个BeanFactory
,并对其进行了增强,使其更智能、更好用。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这句主要意思是:通知Context
,我要开始使用IoC
容器进行初始化工作了,请提供给我一个BeanFactory
容器。这个方法比较简单,基本没有需要扩展的,就不再仔细研究。
上面获取获取的BeanFactory
容器其实还不能投入生产,因为还缺少一些配置信息,这里主要向BeanFactory
填充一些必要的配置。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 设置beanFactory的classLoader beanFactory.setBeanClassLoader(getClassLoader()); // 设置beanFactory的表达式语言处理器,Spring3开始增加了对语言表达式的支持,默认可以使用#{bean.xxx}的形式来调用相关属性值 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 为beanFactory增加一个默认的propertyEditor beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 添加一个ApplicationContextAwareProcessor类型的Bean后置处理器,该后置处理器用于处理*Aware接口的依赖注入 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); /** * 自动装配时如下接口中setter方法的依赖注入会被忽略 * 如:EnvironmentAware#setEnvironment()该setter不能用于自动装配时依赖注入方法, * 因为这些*Aware接口统一采用ApplicationContextAwareProcessor这个Bean后置处理器进行依赖注入 */ beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); /** * 设置几个自动装配的特殊规则 * DefaultListableBeanFactory#findAutowireCandidates(DependencyDescriptor ds)在查找依赖注入值时: * 1、首先会从resolvableDependencies容器中查找,如果有直接返回找到的bean进行依赖注入; * 2、如果没有,再从IoC容器中查找 * 所以,resolvableDependencies容器可以看成对常规IoC的一种扩充 */ beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); /** * 添加一个ApplicationListenerDetector类型的Bean后置处理器,将类型是ApplicationListener的bean添加到事件广播器,以便触发事件时被调用 */ beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); /** * 增加对AspectJ的支持 * 检查容器中是否包含名称为loadTimeWeaver的bean,实际上是增加Aspectj的支持 * AspectJ采用编译期织入、类加载期织入两种方式进行切面的织入 * 类加载期织入简称为LTW(Load Time Weaving),通过特殊的类加载器来代理JVM默认的类加载器实现 */ if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { // 添加BEAN后置处理器:LoadTimeWeaverAwareProcessor // 在BEAN初始化之前检查BEAN是否实现了LoadTimeWeaverAware接口, // 如果是,则进行加载时织入,即静态代理。 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 注册默认的系统环境bean // 这样应用程序中通过:getBean("environment")、getBean("systemProperties")、getBean("systemEnvironment") if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); }}
上面逻辑大致可以总结:
给BeanFactory
设置ClassLoader
、EL
表达式解析器等;添加一个BeanPostProcessor
:ApplicationContextAwareProcessor
,这个主要完成对*Aware
接口功能支持,实现的核心逻辑见下:判断是否实现了XXXAware
接口,如果实现则调用对应的setter
方法注入依赖值。private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}
ignoreDependencyInterface
方法设置一些忽略接口:自动装配时如遇到忽略接口中setter
方法的依赖注入会被忽略,因为这些*Aware
接口统一采用ApplicationContextAwareProcessor
这个后置处理器进行依赖注入。registerResolvableDependency
方法设置一些特殊的内置对象,DefaultListableBeanFactory#findAutowireCandidates(DependencyDescriptor ds)
在查找依赖注入值时:a、首先会从resolvableDependencies
容器中查找,如果有直接返回找到的bean
进行依赖注入;b、如果没有,再从IoC
容器中查找。因此,resolvableDependencies
容器可以看出是对IoC
容器的一种扩充,该容器中的对象是没有经过Spring
一系列容器创建流程,而是直接new
方式创建。再添加一个Bean
后置处理器:ApplicationListenerDetector
,将系统中实现ApplicationListener
接口的对象都统一存储到Set> applicationListeners
中,采用了典型的事件监听/发布模式;LTW
功能判断,LTW
全称LoadTimeWeaver
,即:加载时织入。AOP
和OOP
一样,是一种编程思想,按照织入时机可以分为三类:编译时织入、类加载时织入和运行时织入。AspectJ
实现就是编译时织入,采用的是一种特殊的编译器;Spring AOP
采用的动态代理实现(jdk
动态代理、cglib
动态代理),这是一种运行时织入,缺点就是必须纳入IoC
管理的Bean
才能被代理;而LTW
是类加载时织入,借助于JVM
提供的Instrumentation
技术,在JDK
加载类时织入增强逻辑。注册三个环境变量相关
Instrumentation
是在JVM
加载Class
时进行代码织入,对现有应用没有任何的侵入,APM Agent
开发中就比较常用该技术。
Bean
到容器中,这样应用中可以依赖注入到程序中进行使用;beanFactory.registerSingleton
方式把对象存储到singletonObjects
集合中,它类似于一个缓存,从IoC
获取Bean
时,首先会通过getSingleton
方法从缓存拿,如果缓存拿不到再去获取对应的BeanDefinition
进行实例化,然后实例化对象放到singletonObjects
集合中。postProcessBeanFactory(beanFactory)
默认是空实现,主要是留给子类进行扩展,从名称上看该方法主要用于添加BeanFactoryPostProcessor
,AnnotationConfigApplicationContext
已经在前面注册了一个ConfigurationClassPostProcessor
,主要用于完成对Spring
配置类的处理,其它子类可以重新这个方法增加其它BeanFactoryPostProcessor
对象,实现功能扩充。
前面巴拉巴拉一大堆,基本还是各种配置、填充工作,这一步就到了IoC容器开始真正干活的阶段了。invokeBeanFactoryPostProcessors(beanFactory)
方法主要就是完成对所有注册进来的BeanFactory
后置处理器执行调用,包括BeanFactoryPostProcessor
及其子类BeanDefinitionRegistryPostProcessor
。这里就会有个前面提到的Spring中非常重要的一个类:ConfigurationClassPostProcessor
开始被执行,它执行完成后,所有需要Spring
管理的Bean
都会被解析成BeanDefinition
注册进来。由于ConfigurationClassPostProcessor
非常的复杂,后续会单独分析这个类,这篇主要是对IoC
启动的流程有个大致的、直观印象。执行完这步,你只需要简单知道@Configuration
、@Bean
、@Import
、@ComponentScan
、@Component
等等相关配置注解会被处理,相关的Bean
也被解析成BeanDefinition
注册进来即可。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // LTW探测 if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}
getBeanFactoryPostProcessors()
获取到ApplicationContext.beanFactoryPostProcessors
集合中存储的BeanFactoryPostProcessor
,通过addBeanFactoryPostProcessor()
方法添加的,这里集合为空,因为从前面代码看并没有调用过该方法。
这里核心在invokeBeanFactoryPostProcessors()
方法。首先,看下if (beanFactory instanceof BeanDefinitionRegistry)
判断,如果容器不是BeanDefinitionRegistry
类型或子类,则表示当前容器不能向容器注册Bean
,所以只需要执行BeanFactoryPostProcessor
类型后置处理器即可,BeanDefinitionRegistryPostProcessor
后置处理器不需要执行,因为该后置处理器主要是用来向IoC
容器中注册Bean
,大部分我们使用的容器都是BeanDefinitionRegistry
类型,这样才能把我们业务Bean
纳入Spring
管理,所以基本上都是走if语句块
。
//判断我们的beanFactory是否实现了BeanDefinitionRegistryif (beanFactory instanceof BeanDefinitionRegistry) { ...//省略}else { invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}
invokeBeanFactoryPostProcessors
方法核心就是执行BeanDefinitionRegistryPostProcessor
和BeanFactoryPostProcessor
,但是涉及到执行优先级、执行后可能会产生新PostProcessor
等,所以这里的代码看起来比较长,总结下执行逻辑大致如下:
1、先执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法,其中BeanDefinitionRegistryPostProcessor执行优先级如下:a、addBeanFactoryPostProcessor()传入到优先级最高,因为不需要实例化,直接可以获取到对象进行执行;b、然后从IoC容器中获取PriorityOrdered接口的BeanDefinitionRegistryPostProcessor,实例化并排序后执行postProcessBeanDefinitionRegistry方法c、然后从IoC容器中获取Ordered接口的BeanDefinitionRegistryPostProcessor,实例化并排序后执行postProcessBeanDefinitionRegistry方法d、然后从IoC容器中获取剩余的BeanDefinitionRegistryPostProcessor,实例化后执行postProcessBeanDefinitionRegistry方法;注意这个处理步骤存在一个循环,主要是存在执行前面的BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法时,存在可能会向IoC容器中注册新的BeanDefinitionRegistryPostProcessor,通过循环保证都会被执行;2、然后执行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory方法,执行顺序参照步骤1中执行顺序;3、最后才会执行BeanFactoryPostProcessor#postProcessBeanFactory,执行优先级和BeanDefinitionRegistryPostProcessor一致:a、addBeanFactoryPostProcessor()传入到优先级最高,因为不需要实例化,直接可以获取到对象进行执行;b、然后从IoC容器中获取PriorityOrdered接口的BeanFactoryPostProcessor,实例化并排序后执行postProcessBeanFactory方法c、然后从IoC容器中获取Ordered接口的BeanFactoryPostProcessor,实例化并排序后执行postProcessBeanFactory方法d、然后从IoC容器中获取剩余的BeanFactoryPostProcessor,实例化后执行postProcessBeanFactory方法
这里有个细节,在执行
BeanFactoryPostProcessor#postProcessBeanFactory
方法是没有循环,而执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
中存在一个循环,主要是因为BeanFactoryPostProcessor#postProcessBeanFactory
方法是不会像IoC
中注册Bean
,这样执行过程中就不会产生新的BeanFactoryPostProcessor
。
上面写了一大堆,概况下就是:
1、方法优先级:BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
> BeanDefinitionRegistryPostProcessor#postProcessBeanFactory
> BeanFactoryPostProcessor#postProcessBeanFactory
;
2、同方法优先级:addBeanFactoryPostProcessor
> PriorityOrdered
> Ordered
> 非排序
registerBeanPostProcessors
方法主要是将BeanDefinition
对应的BeanPostProcessor
实例化并通过beanFactory.addBeanPostProcessor()
方法注册进来。前面分析过AnnotationConfigUtils.registerAnnotationConfigProcessors
会向容器注册几个Spring
内置的BeanPostProcessor
,这步主要是将应用中引入的BeanPostProcessor
注册进来。
上步invokeBeanFactoryPostProcessors
执行完成后,Spring
会将所有的Bean
解析成BeanDefinition
注册到容器中,其中就可能包含BeanPostProcessor
的BeanDefinition
信息,这个方法就是把这些BeanPostProcessor
对应的BeanDefinition
通过getBean
方式实例化,并通过addBeanPostProcessor()
注册进来,这样这些BeanPostProcessor
才能起作用。
这个方法代码巴拉巴拉一大堆,流出总结起来还是很清晰,这里就不再上代码:
获取实现PriorityOrdered
接口的BeanPostProcessor
,然后通过getBean()
方法实例化,排序后注册到容器中;获取实现Ordered
接口的BeanPostProcessor
,然后通过getBean()
方法实例化,排序后注册到容器中;获取常规没有实现PriorityOrdered
和Ordered
接口BeanPostProcessor
,然后通过getBean()
方法实例化,注册到容器中;上述步骤中MergedBeanDefinitionPostProcessor
类型会单独存储到internalPostProcessors
集合中,排序后保证放到末尾;最后移除ApplicationListenerDetector
重新追加到最末尾。注意:这里有个细节就是要保证高级别优先级的BeanPostProcessor
全部实例化完成后,才可以进行下一个优先级类型的BeanPostProcessor
,因为BeanPostProcessor
主要就是围绕Bean
实例化进行扩展,这样就可以保证高优先级的BeanPostProcessor
可以参与到对低优先级的BeanPostProcessor
实例化过程中。
和上步invokeBeanFactoryPostProcessors
不同的是,这里只是把所有的BeanPostProcessor
注册进来,并没有去执行,因为这也很好理解:BeanPostProcessor
是围绕在Bean
实例化周围的扩展点,这里服务Bean
存储在容器中基本都还是BeanDefinition
,还没有进行实例化。
initMessageSource
方法主要是处理国际化相关工作,后台开发中很少涉及,这里就不展开分析。
initApplicationEventMulticaster
是上下文环境中初始化一个事件广播器,用于事件发布,后续分析Spring
事件机制再整体分析。
onRefresh
默认是空实现,模板模式设计主要用于子类扩展。可以参照SpringBoot
中ServletWebServerApplicationContext
这个类,重写了onRefresh()
方法,在这个方法中完成内嵌Servlet
容器的创建:Tomcat
、Jetty
、Undertow
,将程序内嵌一个Servlet
容器后,就可以独立运行。
registerListeners
方法主要完成事件监听器注册,将实现了ApplicationListener
接口的监听器bean
注册到ApplicationEventMulticaster
上,在注册完以后,还会将其前期的事件发布给相匹配的监听器。后续分析Spring
事件机制再整体分析。
关键词:
AnnotationConfigApplicationContext构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法:register(co
1、山杏种源SX-10是属于蔷薇科李属植物。2、英文名ShangxingzhongyuanSX-10。3、产于内蒙
以下是滨海能源在北京时间3月28日11:13分盘口异动快照:3月28日,滨海能源盘中涨幅达5%,截至11点13分,报15 92元,成交5323 19万元,换手率1
3月24日,常州市武进区委宣传部举行融媒体新闻行动启动仪式。武进融媒体新闻行动启动仪式。胡国伟摄今年是常州市深入推进“532”发展战略、迈
晋园二手房购房政策+必备技巧,“候鸟”老人一定要看~晋园二手房还能不能买?三亚二手房增值空间大吗?晋园如何买到有升值空间的二手房?
3月27日,昆药集团(600422)融资买入1021 11万元,融资偿还2598 46万元,融资净卖出1577 35万元,融资余额2 91亿元。
1、《山东省旅游条例》(2005年5月27日山东省第十届人民代表大会常务委员会第十四次会议通过)是为了合理开发利用和有效
1、是真的。2、由于广电总局审核的问题本周六将重播我是歌手专场时间:2016-04-1620:20嘉宾:徐佳莹、黄致列
我想问一下,大家身边真有那种对内裤超级挑剔的男生吗?这期我们犹豫了很久很久,好不容易找到一个外贸内衣工厂,他们推荐给我们号称“内裤天
商报全媒体讯(椰网 海拔新闻记者许文玉)为完成《2023年海南省政府工作报告》中“义务教育专任教师中本科以上学历比例提高3个百分点”的目标
1、译文:早晨去放牛,赶牛去江湾;傍晚去放牛,赶牛过村落。2、披着蓑衣走在细雨绵绵的树林里,折支芦管躺在绿草地上吹小曲
大亚圣象于2023年3月28日披露年报,公司2022年实现营业总收入73 63亿元,同比下降15 9%;实现归母净利润4 2亿元,同比下降29 4%,降幅较去年同
按年龄增加养老金,70岁统一发放1000元,这种调整是否可行?下面跟社保网小编一起来看看具体详情吧!由于前三年的瘟疫,如今的居民消费水平已
第一公民银行接手硅谷银行
1、你可以边放音乐,边让学生讲他的父母给他们做的事情,我做了一个课件,但不知怎样传给你呢,我也是一个中学的班主任,我们年
国家发改委:基础设施REITs不得为商住项目变相融资-国家发改委网站24日发布《关于规范高效做好基础设施领域不动产投资信托基金(REITs)项目申报
财政部长刘昆:将继续把支持科技创新摆在优先位置,财政政策,财政部长,科技创新,财政部官员,刘昆(1956年)
开开心心在看《流浪地球》,当画面上出现领航员空间站时,心心叫道:“哇,这空间站好酷呀,哥哥,将来我也想到空间站里住一住。
3月24日,深交所针对鑫铂股份定增募资不超145亿元下发审核问询函。根据先前公告,本次发行拟募集不超过145亿元(含本数
段医生答疑在线??硝苯地平的注意事项??硝苯地平有三种剂型:普通片剂、缓释制剂、控释制剂,剂型不同,最适宜治疗的疾病不同,这是购买和服用