天天短讯!【Spring源码】- 02 Spring IoC容器启动之refresh方法

2023-03-29 18:37:02 来源: 腾讯云

register

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[] 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 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集合,启动解析。

refresh

前面分析了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

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()这两句代码。PropertySourceSpring中代表一组变量,即类似对应于一个配置文件,比如@PropertySource("test01.properties")这个常用的注解就是将配置文件解析成一个PropertySource对象。

initPropertySources()方法主要用于扩展配置来源,比如可以从网络、物理文件、数据库等加载配置信息。StandardEnvironment在创建时,会自动将系统变量System.getProperties()和应用变量System.getenv()加载进来,所以initPropertySources默认只提供的是空实现,主要用于子类扩展使用。

initPropertySources方法主要有两个常见扩展场景:

1、可以在该类中扩展PropertySource来源,如:getEnvironment().getPropertySources().addXXX(PropertySource ps),可以参见GenericWebApplicationContext#initPropertySources()2、可以在方法中添加必要属性验证,一些属性对于应用来说是必要的,缺失则会影响系统的正常逻辑,如:getEnvironment().setRequiredProperties("DB_IP"),下一步就会从context environment上验证是否存在该属性,如果没有则会抛出异常并退出Spring应用

getEnvironment().validateRequiredProperties()这句主要是对setRequiredProperties()方法设置的属性进行必要性检查,如果某个必要属性环境中不存在,则抛出异常退出应用。

obtainFreshBeanFactory

BeanFactory才是Spring中基本的IoC容器,ApplicationContext其实内部包装了一个BeanFactory,并对其进行了增强,使其更智能、更好用。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这句主要意思是:通知Context,我要开始使用IoC容器进行初始化工作了,请提供给我一个BeanFactory容器。这个方法比较简单,基本没有需要扩展的,就不再仔细研究。

prepareBeanFactory

上面获取获取的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设置ClassLoaderEL表达式解析器等;添加一个BeanPostProcessorApplicationContextAwareProcessor,这个主要完成对*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,即:加载时织入。AOPOOP一样,是一种编程思想,按照织入时机可以分为三类:编译时织入、类加载时织入和运行时织入。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

postProcessBeanFactory(beanFactory)默认是空实现,主要是留给子类进行扩展,从名称上看该方法主要用于添加BeanFactoryPostProcessorAnnotationConfigApplicationContext已经在前面注册了一个ConfigurationClassPostProcessor,主要用于完成对Spring配置类的处理,其它子类可以重新这个方法增加其它BeanFactoryPostProcessor对象,实现功能扩充。

invokeBeanFactoryPostProcessors

前面巴拉巴拉一大堆,基本还是各种配置、填充工作,这一步就到了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方法核心就是执行BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor,但是涉及到执行优先级、执行后可能会产生新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

registerBeanPostProcessors方法主要是将BeanDefinition对应的BeanPostProcessor实例化并通过beanFactory.addBeanPostProcessor()方法注册进来。前面分析过AnnotationConfigUtils.registerAnnotationConfigProcessors会向容器注册几个Spring内置的BeanPostProcessor,这步主要是将应用中引入的BeanPostProcessor注册进来。

上步invokeBeanFactoryPostProcessors执行完成后,Spring会将所有的Bean解析成BeanDefinition注册到容器中,其中就可能包含BeanPostProcessorBeanDefinition信息,这个方法就是把这些BeanPostProcessor对应的BeanDefinition通过getBean方式实例化,并通过addBeanPostProcessor()注册进来,这样这些BeanPostProcessor才能起作用。

这个方法代码巴拉巴拉一大堆,流出总结起来还是很清晰,这里就不再上代码:

获取实现PriorityOrdered接口的BeanPostProcessor,然后通过getBean()方法实例化,排序后注册到容器中;获取实现Ordered接口的BeanPostProcessor,然后通过getBean()方法实例化,排序后注册到容器中;获取常规没有实现PriorityOrderedOrdered接口BeanPostProcessor,然后通过getBean()方法实例化,注册到容器中;上述步骤中MergedBeanDefinitionPostProcessor类型会单独存储到internalPostProcessors集合中,排序后保证放到末尾;最后移除ApplicationListenerDetector重新追加到最末尾。

注意:这里有个细节就是要保证高级别优先级的BeanPostProcessor全部实例化完成后,才可以进行下一个优先级类型的BeanPostProcessor,因为BeanPostProcessor主要就是围绕Bean实例化进行扩展,这样就可以保证高优先级的BeanPostProcessor可以参与到对低优先级的BeanPostProcessor实例化过程中。

和上步invokeBeanFactoryPostProcessors不同的是,这里只是把所有的BeanPostProcessor注册进来,并没有去执行,因为这也很好理解:BeanPostProcessor是围绕在Bean实例化周围的扩展点,这里服务Bean存储在容器中基本都还是BeanDefinition,还没有进行实例化。

initMessageSource

initMessageSource方法主要是处理国际化相关工作,后台开发中很少涉及,这里就不展开分析。

initApplicationEventMulticaster

initApplicationEventMulticaster是上下文环境中初始化一个事件广播器,用于事件发布,后续分析Spring事件机制再整体分析。

onRefresh

onRefresh默认是空实现,模板模式设计主要用于子类扩展。可以参照SpringBootServletWebServerApplicationContext这个类,重写了onRefresh()方法,在这个方法中完成内嵌Servlet容器的创建:TomcatJettyUndertow,将程序内嵌一个Servlet容器后,就可以独立运行。

registerListeners

registerListeners方法主要完成事件监听器注册,将实现了ApplicationListener接口的监听器bean注册到ApplicationEventMulticaster上,在注册完以后,还会将其前期的事件发布给相匹配的监听器。后续分析Spring事件机制再整体分析。

标签:

上一篇 :

下一篇 :

天天短讯!【Spring源码】- 02 Spring IoC容器启动之refresh方法

AnnotationConfigApplicationContext构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法:register(co

03-29 18:37:02

【全球聚看点】万顺叫车app怎么开发票 万顺叫车app开发票教程

万顺叫车app怎么开发票万顺叫车app开发票教程,

03-29 17:11:06

全球快资讯:石基信息宣布对旗下支付技术解决方案进行重组

2017年6月21日,经石基信息总裁办公会审议通过,同意北海石基采用派生分立的方式,以其第三方支付项目部...

03-29 16:08:50

报道:平稳开局 2023年前2月长三角三省一市经济运行回暖向好

平稳开局2023年前2月长三角三省一市经济运行回暖向好,外贸,制造业,经济运行,财政收入

03-29 15:03:08

今日热讯:临危受命 星夜驰援 ——放射科介入团队急诊手术抢救阳逻院区消化道出血患者

临危受命星夜驰援——放射科介入团队急诊手术抢救阳逻院区消化道出血患者---介入团队立即投入抢救,与阳...

03-29 14:18:18

天天最资讯丨易极:3-29黄金1966区域做多

交易的核心不是单笔就能赚多少,而是能否做到长期持续稳定获利。昨天黄金在一小时支撑位和一小时压力位...

03-29 12:52:59

当前看点!敦煌网将于3月28日推出“纠纷无忧宝”产品

电商报快讯:3月29日消息,敦煌网日前发布纠纷无忧宝上线通知。公告称,为帮助卖家快速处理纠纷,提升卖...

03-29 12:34:32

视讯!树立全局意识做好保障 强化责任意识履职尽责

2023年以来,运营科技部在农发行秦皇岛市分行党委的正确领导下,认真贯彻落实上级行信息科技工作总体部...

03-29 11:07:01

全球视讯!京东白条逾期200元会怎么样?会被起诉吗?

京东白条想必大家都不会陌生,作为京东金融旗下的产品大家对此也有很大的熟悉,如果用户一旦有资金周转...

03-29 10:40:58

【世界聚看点】裙子拉链不好拉怎么办_拉链不好拉怎么办

1、拉拉链的尾部,拉直,然后从下往上拉,看是否顺滑。如果不光滑,可以找一种蜡涂在拉链表面。这种蜡可...

03-29 09:54:40

焦点消息!福州高新区有个“智慧大脑” 一屏呈现项目建设等信息

安防、应急、交通高空全景AR,高空抛物专用监控摄像机,一键报警求助杆……这样看似科幻的生活场景,在...

03-29 09:05:40

最新资讯:呵护老人健康 守护儿童成长(两会后探落实·关注基层治理和民生保障⑥)

核心阅读廷坪乡是福建省福州市闽侯县的一个小山乡,留守老人和儿童较多。为服务好“一老一幼”,廷坪乡...

03-29 06:55:07

环球观速讯丨迈克生物(300463):3月28日北向资金增持7.75万股

3月28日北向资金增持7 75万股迈克生物。近5个交易日中,获北向资金增持的有3天,累计净增持38 79万股...

03-29 04:34:59

环球观速讯丨比海绵还软的马拉糕,用面粉就能做,松软弹性大,早餐吃它就顶饱

比海绵还软的马拉糕,用面粉就能做,松软弹性大,早餐吃它就顶饱。女儿很喜欢吃马拉糕,每次我蒸一大盘...

03-29 00:12:43

全球观天下!“竞争永不停歇”!瑞信(CS.US)高管试图打消瑞士客户对合并交易的担忧

瑞信(CS US)在瑞士的高管试图打消当地客户对瑞银(UBS US)收购交易的担忧,并强调了瑞士业务对合并后的...

03-28 22:08:23

世界讯息:厉害了!宁波这所学校在全国大赛中获得两个一等奖

【来源:宁波市教育局_教育新闻】近日,2023年世界头脑奥林匹克全国赛获奖名单公布。宁波高新区实验学校...

03-28 20:39:58

快报:大众探岳的变速箱质量怎么样 大众探岳的变速箱是什么?

大众探岳的变速箱是属于大众推出DSG系统。放眼全球厂商中算是一款比较优秀的变速箱,综合的表现控制比较...

03-28 19:19:18

环球速读:喜讯:舞蹈《老街》入选全国我最喜爱的“村晚”节目榜单

喜讯:舞蹈《老街》入选全国我最喜爱的“村晚”节目榜单

03-28 18:35:34

天天观焦点:“白头鹰”现形记|毒品合法化在美国,一桩“好买卖”!

美国是全世界毒品问题最严重的国家,“贡献”了12%的全球吸毒人数。过去12个月,有1010万美国人至少吸食...

03-28 17:48:26

世界看热讯:南京共有产权房新政策怎样的啊,政策都有哪些规定的啊?

(一)携带相关申购材料至市住保办提出申请;(二)市住保办集中审核:审核通过的名单予以公示,经公示无异议...

03-28 16:48:44

聚焦:被质疑“山寨”的狮王口腔:定位OEM,因牙膏菌落超标被罚

该负责人认为,狮王口腔使用与“狮王日用化工(青岛)有限公司”相似的名称,或为“山寨”公司,已引起...

03-28 16:09:31

环球关注:海宁盐官潮水时间表今日_海宁盐官潮水时间表

1、14 00,因天气等因素影响,请提前半个小时。2、春夏秋冬潮汐潮汐潮汐潮汐十五11:45

03-28 14:58:41

全球新动态:未否认英特尔转让5G基带技术消息,广和通称以英特尔发布新闻为准

App3月28日消息,针对英特尔拟转让5G基带技术的消息,记者今日致电广和通证券部求证,公司人士称“所有...

03-28 13:12:51

世界今亮点!DNF改版后格兰迪收益一览,9图收益不如7图收益高!

DNF地下城与勇士11月29日更新了发出了一则“经济系统相关调整公告”,该公告中明确指出格兰迪翻牌金币转...

03-28 12:06:28

热点!你的 SaaS,给个价吧

定价是产品商业化变现的必经之路

03-28 10:51:29

世界视讯!小孩脸上长黑点图片_脸上长黑点图片

1、脸上的黑斑除了自然斑,大多是内分泌失调,睡眠不好造成的。这个时候首先要养成良好的生活作息,不要...

03-28 09:51:43

环球快看:通策医疗:3月27日融资买入3556.3万元,融资融券余额15.45亿元

3月27日,通策医疗(600763)融资买入3556 3万元,融资偿还2947 08万元,融资净买入609 22万元,融资余额15 31亿元。

03-28 08:26:39

天天快消息!英超裁判安排:胡珀执法第29轮曼城红军 泰勒执法红军蓝军补赛

英超官方公布第29轮以及第7、第8、第25轮多场补赛裁判安排。第29轮曼城vs利物浦的比赛由西蒙-胡珀执法,...

03-28 06:33:05

今日要闻!Prometheus的使用

Prometheus是一个开放性的监控解决方案,用户可以非常方便的安装和使用Prometheus并且能够非常方便的对...

03-28 02:19:04

热点在线丨华宇软件:旗下法律科技产品将通过百度智能云接入文心一言的能力

华宇软件3月27日在投资者互动平台表示,持续引入新技术,结合公司行业业务知识和相关能力,围绕客户应用...

03-27 22:57:23

当前快报:金壮龙:促进大中小企业融通发展,激发涌现更多专精特新企业

金壮龙:促进大中小企业融通发展,激发涌现更多专精特新企业

03-27 20:47:52

天天要闻:上海社保2023年缴费基数及比例是多少?一个月要交多少钱?

上海社保2023年缴费基数从2022年7月1日-2023年6月30日,上海社保2023年缴费基准数上限为:34188元 月,...

03-27 19:06:12

速读:华仁药业拟定增募资不超13.4亿元 股价跌0.23%

中国经济网北京3月27日讯今日,华仁药业(300110 SZ)股价下跌,截至收盘报4 31元,跌幅0 23%。  3月...

03-27 18:07:15

天天新消息丨重启六大品牌体育赛事、设立专项支持资金……海南出台10条措施振兴文体会展活动

商报全媒体讯(椰网 海拔新闻记者张艺牛志远摄影报道)3月27日下午,海南省新闻办公室在海口举行《关于...

03-27 17:06:58

【全球独家】中国林学会联合中国科技馆举办“美丽中国”主题院士科学人文课

绿色中国北京3月26日电(特约记者马莎)3月26日,中国林学会-中国科技馆“美丽中国”主题联动科普活动在...

03-27 16:01:05

当前视讯!纽卡斯尔联历史总进球排名:1. 阿兰·希勒 19...

纽卡斯尔联历史总进球排名:1 阿兰·希勒1996-2006206球2 杰基·米尔本1943-57200球3 兰·怀特1953-62153球4

03-27 14:15:05

焦点简讯:广誉远:坚持以龟龄集、定坤丹、安宫牛黄丸和牛黄清心丸等作为核心产品的经营方向不变

每经AI快讯,有投资者在投资者互动平台提问:请问公司开始卖醋,又是从哪方面想的?广誉远(600771 SH)3...

03-27 12:37:12

聚焦:沙赞主演责怪凯文·费奇,对他进行误导,还耽误了他

《沙赞2》的主演扎瑞克·莱维,在电影扑街后,似乎开始了四处责怪别人,此前他还不满巨石强森没有客串《...

03-27 11:26:56

今日热门!HousAfrica获得40万美元战略投资

HousAfrica是一家区块链房产科技服务商,为房地产开发商及其客户提供房地产数字化和透明度工具,该公司...

03-27 10:05:15

世界微资讯!扬州市养老金能提前支取吗?

扬州市养老金能提前支取吗?下文就随社保君来简单的了解一下吧。一、扬州市养老金能提前支取吗根据现有...

03-27 09:00:34

天天快资讯丨红鸾记_关于红鸾记介绍

1、《红鸾记》是由阿健导演的、北京东方飞云国际影视公司投资制作的数字剧情电影,蒋方婷、王雪菁、萧浩...

03-27 07:39:56

天天最资讯丨树欲静而风不止子欲养而亲不待出自哪里-树欲静而风不止子欲养而亲不待是什么意思

1、应该是树欲静而风不止,子欲养而亲不待吧。2、树想静止不动,但是风让树不能静止,儿女想孝顺赡养父...

03-27 03:44:19

世界热头条丨大通湖:“桃花经济” 打开致富新路径

古韵表演。桃花集市。红网时刻益阳3月26日讯(通讯员刘钊作罗宏)古韵表演、“桃缘”青年交友行动、桃林...

03-26 23:08:13

每日快讯!佳能l100驱动_佳能l100

1、佳能RF100-500mmF5-1LISUSM镜头的整体风格依然是我们熟悉的样式。2、标志性的白色隔热涂料在

03-26 20:09:40

世界今日讯!腾讯云边缘安全加速(EdgeOne)之规则引擎

前几天,受邀体验了腾讯云边缘安全加速(EdgeOne)后,有感发了一篇开箱即用的文章。很多小伙伴表示对规...

03-26 18:18:53

新资讯:徐正溪个人资料作品介绍

1、徐正溪(JeremyJones),原名徐正曦,1985年5月5日出生于上海市,中国内地男演员。2、2005年,参加全...

03-26 16:30:28

世界热讯:女性消费引领市场升级 每年支配着近10万亿元的消费支出

【女性消费引领市场升级】女性是消费市场的主力军。从数量上看,我国有近4亿年龄在20岁至60岁的女性消费...

03-26 16:15:10

天天微头条丨厦门名小吃有哪些-厦门小吃有哪些

1、厦门独有小吃:  沙茶面、土笋冻、福建炒面线、厦门薄饼、姜母鸭、棺材板、五香卷、海蛎炸、面线糊...

03-26 13:48:14

前沿热点:50+的女人如何穿出时髦感?简约、宽松和质感是关键,高级又减龄

50+的女人,虽然没有了年轻时的曼妙身材,肌肤也不像以前一样白皙明亮,但是岁月让妈妈们变得更加优雅、...

03-26 10:59:03

环球速读:建安七子是谁

1、建安七子包括孔融、陈琳、王粲、徐干、阮瑀、应玚、刘桢。2、建安七子,是汉建安年间(196—220年)...

03-26 08:50:26

每日观察!“绿电”与“绿氢”灵活转换!我国首次实现固态氢能发电并网
【世界时快讯】为期一年!深圳将集中开展电线电缆产品质量专项整治提升工作
全球消息!流动性缺口率越高越好吗_流动性缺口率
环球微资讯!丰田铁心逼死马自达!昂克赛拉见了泣不成声,11万起或要迷倒一片
每日播报!gagman什么意思
每日热门:出游正当时 各地为游客提供一道道文旅大餐
环球最资讯丨这个大会上 武汉47个签约项目总金额达459亿元
世界热门:西宁交警5小时破获一起交通肇事逃逸致死案
全球速递!高粱烧酒制作方法
世界今日讯!王者归来!叶诗文二次复出再夺冠,4字寄语张雨霏:字字真言
【世界聚看点】闽清县气象台发布暴雨蓝色预警【Ⅳ级/一般】【2023-03-25】
世界热资讯!女性分泌物多怎么治疗_白带多怎么治疗
世界时讯:兰州新区制定今年强科技工作目标
全球热资讯!猫石对话每日运势
世界热点评!张玉宁结束海外疗伤下周回国 三支球队期待“满血复活”的他
天天实时:中国人保去年保险业务收入6258亿增6.9%,净利244亿增12.8%
每日播报!少将参加地方剪彩被举报,军队调查时发现异样,交给警方处理
天天视讯!【财经分析】美联储持续加息后 市场下行风险凸显
热头条丨开除员工的条件有什么?
环球今日报丨威海好玩的地方有哪些
世界热点评!深圳周末艺文指南(3月25日、26日)
天天头条:龙虎榜丨*ST科华今日涨停,上榜营业部席位合计成交1.99亿元
环球热推荐:产品畅销市场 产业迈向高端(两会后探落实·制造业一线看信心)
天天观热点:车上这4个按钮不懂就别乱碰,一不小心就会出事,劝你谨慎
天天快资讯:2022年教育事业成绩单公布,各级各类教育均取得显著进展 在“上好学”上迈出坚实步伐
环球今日讯!年报:2股减亏 1股扣非净利润-1.2亿
当前关注:烽火战国怎么刷声望
最新消息:提了20多年的“无假日医院”,为何实现不了?
天天热消息:青岛人才市场司机招聘信息_青岛人才市场
【报资讯】山西阳泉平定县:税惠政策助力艾草产业成长
世界新资讯:广昌县自然资源局发布地质灾害气象风险蓝色预警【IV级/一般】
天天实时:汉朝皇帝列表
全球简讯:首推开工审批30个有效工作日 泰州港经开区全速奔跑在项目建设“春天里”
世界即时看!进入稳定状态,静等花开!
天天最新:兵团大厦属于哪个街道_兵团大厦
世界今日报丨事发屯昌!女子网上邂逅假“军人”被骗33.57万元
全球简讯:众安贷是正规贷款吗
全球速读:广西贺州和展电子有限公司
全球快报:何为绿色猪肉?吃出健康身体
世界快讯:今明厦门暖湿依旧,冷空气后天就来!
【世界聚看点】尔康去了缅甸都回不来是什么梗
天天快资讯:3月23日生意社白卡纸基准价为5180.00元/吨
每日消息!资溪县气象台更新雷电黄色预警信号【III级/较重】【2023-03-23】
当前通讯!如何鉴别暖风机的质量好坏 暖风机怎么选购
世界观焦点:电脑一般都用什么杀毒软件啊
世界热点!香港金管局回应香港金融机构债权人清偿顺序
【当前热闻】奇点家具锁 | 嵌入式百搭不同拉手的指纹家具锁
每日播报!前追觅联合创始人吴鹏创业奶茶店自动化方向,新公司天使轮融了近 1 亿元丨36氪独家
天天快看点丨什么是海洋技术
今日最新!春分到,蛋儿俏~奉贤萌娃体验立蛋民俗
X 广告
资讯
X 广告

Copyright ©  2015-2022 西南畜牧网版权所有  备案号:皖ICP备2022009963号-8   联系邮箱:39 60 29 14 2@qq.com