【Spring源码】- 02 Spring IoC容器启动之refresh方法|环球播报
AnnotationConfigApplicationContext构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法:register(co
2023-03-29AnnotationConfigApplicationContext构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法: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
2023-03-29
《金证研》南方资本中心冷云 作者易溪南江 风控回溯历史,欧美地区的童装产业链,已从早期简单的生产...
2023-03-28
就目前的市场状态而言,新能源车企经历过数次车轮战后,目前已经进入到了淘汰赛环节。无论是传统车企的...
2023-03-28
昨日公开做多波段,1963全部获利,今日再次公开1955做多黄金,1953再次加多,现在金价大涨至1964,获利...
2023-03-28
长沙养老保险有居民养老保险、职工养老保险,灵活养老保险,不同保险类型养老金领取不同,具体标准如下...
2023-03-28
记者:埃默森将于周四接受膝盖半月板的手术,手术,巴西,热刺队,德国足球,足球竞赛,膝盖半月板,足球运动员...
2023-03-28
万业企业(600641)03月28日在投资者关系平台上答复了投资者关心的问题。
2023-03-28
格隆汇3月28日丨嘉里物流(00636 HK)宣布,其建议根据将向独立股东寻求的特别授权向认购人发行本金总额...
2023-03-28
中国网财经3月28日讯(记者郭帅)3月26日,中国酒业协会第六届理事会第五次(扩大)会议暨中国酒业协会成立3...
2023-03-28
美国银行接连关闭影响持续发酵美媒称或导致经济衰退---据美国媒体27日报道,作为美联储12个区域性储备银...
2023-03-28
高盛集团认为,得益于类似ChatGPT的人工智能技术的突破,全球主要经济体四分之一的工作可能实现自动化。...
2023-03-28
美财政部国内金融部的副部长NellieLiang对话国会,监管机构随时准备重复最近银行倒闭后采取的非同寻常的...
2023-03-28
格隆汇3月28日丨联合能源集团(0467 HK)盘初一度大涨逾11%,5日连涨达26%走出反转行情,现报0 87港元创3
2023-03-28
1、3月27日,币安及其首席执行官赵长鹏因涉嫌违反交易规则被美国商品期货交易委员会起诉。2、他发文回应...
2023-03-28
东吴证券:估值具备性价比看好白酒板块配置价值:东吴证券最新研报表示,近期各名酒酒企陆续进入查价格...
2023-03-28
“永久化学物质”是全氟和多氟烷基物质(PFAS)的别称!详情
2023-03-28
1、( 《笑傲江湖》中令狐冲初会任盈盈时称呼她为: 婆婆。本文就为大家分享到这里,希望小伙伴们会喜欢。
2023-03-28
欢迎观看本篇文章,小勉来为大家解答以上问题。马兰花歌词,马兰花歌曲简介很多人还不知道,现在让我们...
2023-03-27
日前,萤石宣布,定于3月28日13点30分在浙江杭州举办2023ECDC萤石云开发者大会,本次活动的主题是云领未...
2023-03-27
2023年河南省省直公务员和省辖市公务员面试公告将陆续发布中,根据关于河南省2023年统一考试录用公务员...
2023-03-27
天津渔具展:关公、大长腿齐上阵!“内卷化”下休闲垂钓面临的困局。这可能是我见过最“卷”的一次渔具...
2023-03-27
1、空调漏水的原因通常是空调的偏差导致排水管不冲洗,或者支管拉高导致流水排不出去。排水管弯曲、变脆...
2023-03-27
中国质量新闻网讯3月22日是第三十一届“世界水日”,3月22-28日是第三十六届“中国水周”。为进一步宣传...
2023-03-27
最高奖30000元!重庆警方发布“通缉令”,看到这些人请立即报警
2023-03-27
1、跳丸2、跳丸也叫“弄丸”或“飞丸”,是杂技艺人用手熟练而巧妙地抛接玩弄丸铃的一种游戏。表演者快...
2023-03-27
3月27日11点2分,云游戏板块指数报1171 436点,跌幅达2%,成交154 51亿元,换手率5 12%。板块个股中...
2023-03-27
百度智能云相关“文心一言”应用产品发布会取消,文心一言,百度,智能云,新品发布会,文心
2023-03-27
来源:长江商报专注于大输液领域的华仁药业(300110 SZ)将再借资本力量实现产能扩张。日前,华仁药业...
2023-03-27
当患有胃病的时候,胃部就会出现相应的临床表现,胃疼就是其中一种,像生活中较常见的慢性胃炎、胃溃疡...
2023-03-27
深圳首家GLP实验室获国家认证标志着我市生物医药产业链技术服务平台全线贯通深圳特区报讯(记者易东)深...
2023-03-27
近日,香港羽姬爆料,60岁的王杰和34岁的梁洛施走到了一起。两人虽然年龄相差26岁,之前在英皇麾下也没...
2023-03-26
3月23日,在中国聚氨酯工业协会第21次年会暨2023中国聚氨酯行业发展论坛上,美思德被授予中国聚氨酯工业...
2023-03-26
日前,一汽-大众官方宣布,旗下2023款高尔夫GTI车型正式上市,共推出1款车型,售价为22 98万元。新车搭...
2023-03-26
减数是减法算式中从被减数中扣除的数。减法是数学中的基本运算之一,已知两个数a与b,如果存在一个数c,...
2023-03-26
我们联合合作伙伴:全国汽车交易与金融大数据服务平台车300,选取10款优惠车型其中一个版本的一年保值率...
2023-03-26
美国卓越能源公司位于明尼苏达州的一座核电站2022年11月底向监管部门报告泄漏大量含氚放射性水。该公司...
2023-03-26
央广网北京3月26日消息据中央广播电视总台中国之声《新闻和报纸摘要》报道,各地助力外贸企业积极开拓海...
2023-03-26
首先先酒精消毒将粉刺针消毒;用针头挑破表皮,使黑头、粉刺、痘痘翻起来挑破皮下部分纤维组织。然后挤...
2023-03-26
3月25日,由兰州市商务局、城关区人民政府主办的“2023春之约·活力金城欢乐购家电家居购物节”在东方红...
2023-03-26
欢迎观看本篇文章,小勉来为大家解答以上问题。五一出游朋友圈文案,五一出游朋友圈文案精选很多人还不...
2023-03-26
1、工作总结就说市场上遇到的问题,以及市场现在的现状。2、和你现在哪里有不足的地方,哪里需要改进。3...
2023-03-25
本年05月03日报道:告诉,光大证券(06178)发布音讯,该企业属下孙公司光大银行浸辉本钱办理(上海市)公司...
2023-03-25
1、风平浪静”的谜底是“宁波市”。宁波顾名思义就是宁静的波涛,也可以用“风平浪静”来形容。2、脑筋...
2023-03-25
雍正的死有什么蹊跷吗乾隆上位后为何着急抛清关系,对雍正和乾隆很感兴趣的小伙伴们,小编带来详细的文章...
2023-03-25
(记者许青青)东盟秘书长高金洪25日访问中山大学,并向师生作“在东盟——中国全面战略伙伴关系下合作发...
2023-03-25
1、利用Photoshop打开照片,然后导出为WEB格式,然后优化文件大小,再保存就可以把图片压缩到200K以下。...
2023-03-25
1、《国有土地使用证》是证明土地使用者(单位或个人)使用国有土地的法律凭证,受法律保护。办理对象主...
2023-03-25
截至2023年3月24日收盘,世龙实业(002748)报收于11 15元,较上周的11 06元上涨0 81%。本周,世龙实...
2023-03-25
上海红毯曝光:张嘉倪穿着暴露猛秀身材,刘亦菲现身害羞老外尖叫,文淇,杨洋,红毯,刘亦菲,张嘉倪,佟丽娅,...
2023-03-25
一、江西省赣州市天气预报1、寻乌县气象台2023年03月25日03时55分继续发布雷电黄色预警信号。2、预计未来6小时内
2023-03-25
1、诗词化剑,才气镇世界2、作者:我是秋枫3、简介4、穿越到平行世界,口中的诗词竟然成了杀敌利器,随...
2023-03-25
1、弼是一个汉字,左中右结构,部首为弓。本意是矫正弓弩的工具,引申指纠正、辅佐,也可用于指担任辅佐...
2023-03-24
点击观看视频3月下旬,新疆昆仑山腹地,冰雪刚刚开始消融。湖面、蓝天、白云和远处的冰川相互依托。通透...
2023-03-24
营收依赖单一产品、代工生产牙膏抽检菌落超标……登康口腔IPO背后存“隐忧”
2023-03-24
一般为20个工作日,不包括周末与节假日。参保女职工生育津贴的待遇如下:1 2020年1月1日以后生育的,按...
2023-03-24
他补充称,公司自有矿可以覆盖该次行动涉及的锂盐当量,仍将保持合理的利润水平
2023-03-24
中国网 中国发展门户网讯3月23日,世界银行执行董事会批准2 5亿美元贷款,用于帮助中国陕西省减少农村...
2023-03-24
2020年6月21日。父亲节起源于美国,是为感谢父亲而庆祝的节日,日期是每年公历6月的第三个星期日。父亲...
2023-03-24
第30届广州园林博览会3月24日开幕第30届广州园林博览会2023年3月24日正式拉开帷幕。这两天,多个主题作...
2023-03-24
24日同样有两场比赛,其中下午五点场济南RW侠交手北京WB,这也是小夜首次在S组正面交手暖阳,也是暖阳粉...
2023-03-24
大众网·海报新闻见习记者刘子琳通讯员张凡新济宁报道济宁任城区古槐街道北门社区曾存在设施老化、功能...
2023-03-24
精品VIP投研内容
2023-03-24
曹操的历史评价如何?为什么后世褒奖不一呢?感兴趣的读者可以跟着趣历史小编一起往下看。这对曹操和历...
2023-03-24
截至2023年3月23日收盘,易华录(300212)报收于32 4元,上涨6 02%,换手率9 97%,成交量63 87万手,成交额20 29亿元。
2023-03-24
惠普笔记本的保修期是:个人消费者凭发票及三包凭证享受整机保修一年,主要部件保修两年。主要部件包括...
2023-03-24
我身边有位朋友在知道这则消息之后问了我一个问题,现在市面销售的汽车,每家都说自己是新技术,归根结...
2023-03-24
今天小编肥嘟来为大家解答以上的问题。eva剧场版梳理,EVA剧场版顺序问题相信很多小伙伴还不知道,现在让...
2023-03-24
(资料图片)据报道,苹果(AAPL US)正在考虑竞购英超联赛的转播权。据悉,该公司此前曾与美国职业棒球大...
2023-03-23
目前在抖音开店在也要接受抖音平台的一些规则,因为现在抖音对于电商这一款是非常看重的,大家在抖音...
2023-03-23
1、红叶题诗:唐僖宗时的一天傍晚,年轻的于佑在城墙下漫步。时值“西风吹渭水,落叶满长安”的深秋,满...
2023-03-23
3月22日,恰逢第31届“世界水日”。由农业水资源高效利用全国重点实验室、中国农业大学水利与土木工程学...
2023-03-23
近年来云梦县将“四好农村路”建设作为助力乡村振兴的有力抓手县乡道持续改善农村交通出行水平显著提升...
2023-03-23
“欠他的10万块钱我都还了,你们凭什么抓我?”近日,上海宝山警方破获一起网购“练功券”还债的奇葩诈...
2023-03-23
乌鲁木齐市水磨沟区16个重大项目签约金额超125亿元涉及商贸物流、科教文化、医疗服务、信息金融等领域3...
2023-03-23
中新网3月23日电工信部23日发布2023年1-2月份通信业经济运行情况。1-2月份,信息通信行业整体运行平稳。...
2023-03-23
如今英雄联盟S8全球总决赛正在如火如荼的进行之中,入围赛首轮的比赛已经全部结束,EDG也在抽签中抽到了...
2023-03-23
看完《误杀2》彩蛋才知道,原来导演把所有人都骗了啊,小伙伴们看完电影之后一定要再等等哦,结尾的彩蛋...
2023-03-23
原标题:省市场监管局采取11项措施开展信用提升行动助企纾困为充分发挥信用机制对优化营商环境和推动高...
2023-03-23
为用户带来美好生活,一直以来都是推动帅康不断前行的初心。这些年,除通过持续创新产品,为用户解决厨...
2023-03-23
1、1—9级:魂士;2、10—19级:魂师;3、20—29级:大魂师;4、30—39级:魂尊;5、40—49级:魂宗;6
2023-03-23
来源|瞎说职场(ID:HRInsight)作者|SeanYe知乎上有一个火热话题:“三十岁还没有走到管理岗的人,后来...
2023-03-23
1、吞金兽全称是叫四脚吞金兽,是一个网络名词,源自部分宝爸宝妈对自己孩子的调侃。2、意思是指刚出生...
2023-03-23
度假村有:1、海口美视五月花高尔夫度假酒店。地址:位于海口市区的西部琼洲海峡度假村内2、海口金色阳...
2023-03-22
上海在无人驾驶领域更进一步,在市区开放全无人驾驶RoboTaxi(无人驾驶出租车)测试。AutoX安途获得上海...
2023-03-22
格隆汇3月22日丨安凯客车(000868 SZ)公布,2023年3月22日,公司收到深圳证券交易所(“深交所”)上市审...
2023-03-22
合诵榜样事迹以榜样力量汇聚社会文明新风尚---35部合诵作品展现北京榜样敬业奉献、热心公益、担当作为的...
2023-03-22
1、千岛湖鱼头。千岛湖有机鱼早已风靡全国,是第一个经过国家淡水鱼有机认证、纯天然野生放养、五年以上...
2023-03-22
1、差一步美满就牵着手走散是由歌手大壮演唱的《差一步》。2、歌曲信息:差一步-大壮词:高进曲:高进编...
2023-03-22
参考消息网3月22日报道据德国《焦点》周刊网站3月11日报道,福岛事件12年后,日本核电梦碎在即。报道称...
2023-03-22
南钢股份(600282)03月22日在投资者关系平台上答复了投资者关心的问题。
2023-03-22
上海法考主观题考点分布一览表2023(考试时间:3月26日)行政区考点地址浦东上海立信会计金融学院(浦东校...
2023-03-22
1、盛庆玉,男,昆曲架子花脸。2、行三,人称“盛三”。3、原籍山东登州府,先世业骡马商来京师。
2023-03-22
1、用超连接编辑Excel目录:举例来说,工作不中包含一个“登陆界面”表和若干个其他工作表。2、选择【插...
2023-03-22
1、盛定女,1932年生,浙江武义人。2、1957年毕业于上海外国语学院。3、毕业后曾先后在湖南冶金学院、中
2023-03-22
大型银行能否填补硅谷银行倒闭后留下的市场空白,还未可知。
2023-03-21
小米的生态链合作伙伴Viomi在中国推出了Super2Max净水器。新型Viomi净水器采用12000G双核高通量设
2023-03-21
中新网北京3月21日电(记者郭超凯张素)中国外交部发言人汪文斌3月21日主持例行记者会。有记者提问:美方...
2023-03-21
1、伦敦金属交易所=LMELondonMetalExchange也许你还会用到:芝加哥期货交易所=cbotC
2023-03-21
1、《晓之追迹》是由市川昆执导。2、池部良、伊藤雄之助主演的一部电影。文章到此就分享结束,希望对大...
2023-03-21
博菲电气(001255)03月21日在投资者关系平台上答复了投资者关心的问题。
2023-03-21Copyright © 2015-2022 亚太水产网版权所有 备案号:沪ICP备2020036824号-11 联系邮箱: 562 66 29@qq.com