Spring---ApplicationContext的refresh流程分析+hook类的产生时机和作用

mac2025-10-07  7

相信看过Spring源码的一定不会对AbstractApplicationContext.refresh()方法陌生,其主要作用在于刷新Spring容器,刷新的意思即把BeanFactory清空为初始状态,然后再按照程序意图填满各种Bean。

一、refresh流程

二、流程分析 

上面流程中提到了BeanPostProceesor、ApplicationEventMulticustor等,其主要作用在用在容器刷新过程前、中、后提供一些口子(hook函数)给开发者,让我们更加灵活的控制Bean的生成过程。

2.1 createApplicationContext

在SpringBoot启动方法org.springframework.boot.SpringApplication#run(java.lang.String...)中会创建应用上下文ApplicationContext,过程如下:

//org.springframework.boot.SpringApplication#createApplicationContext protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { //根据当前是否Web环境以及Web环境类型,通过反射实例化相应的ApplicationContext switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }

这里拿默认的AnnotationConfigApplicatonContext创建为例,看一下实例化过程中重要的几点。

1.创建BeanFactory

AnnotationConfigApplicatonContext继承自GenericApplicationContext

public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }

2.创建reader和scanner,用于扫描Bean

//org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext() public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } //org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment) public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); //这行代码将添加扫描@Component、@Bean等注解的BeanFactoryPostProcessor到容器中 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } //org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }

至此随着ApplicationContext实例化完毕,BeanFactory创建成功,且将ConfigurationClassPostProcessor加入了BeanDefinitionMap,该类的作用在下文分析。

2.2 obtainRefreshBeanFactory()

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //抽象方法由子类实现 //GenericApplicationContext仅仅设置BeanFactory的序列化ID //AbstractRefreshableApplicationContext会销毁当前已有的BeanFactory,初始化一个全新的 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }

2.3 prepareBeanFactory(BeanFactory)

1.设置beanFactory的类加载器,默认采用线程上下文类加载器

2.添加指定的BeanPostProseccsor到容器中,包括ApplicationListenerDetector,ApplicationContextAwareProcessor。ApplicationListenerDetector的作用就是判断某个Bean是否是ApplicationListener,如果是,加入到事件监听者队列。在后文将细说。

2.4 invokeBeanFactoryPostProcessors(beanFactory)

该方法将调用上文2.1中所讲的org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法扫描应用中所有Bean添加到容器之中。具体过程请看博文:Spring如何找到一个Bean并将其添加到容器。

2.5 registerBeanPostProcessors(BeanFactory)

我们程序中自定义的BeanPostProcessors将会在这一步被找到并实例化存储到beanFactory中。

2.6 initMessageSource()

找到我们自己定义的名为“messageSource”的Bean提供给ApplicationContext使用,使得ApplicationContext具有国际化能力。

2.7 initApplicationEventMulticaster

初始化ApplicationEventMulticaster,该类作为发布订阅模式实现的中介者,可以存储所有订阅者信息,并根据不同的事件,通知不同的订阅者。具体的方法为:

1.org.springframework.context.event.ApplicationEventMulticaster#addApplicationListener//添加事件监听者

2.org.springframework.context.event.ApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent)//发布指定事件给相应订阅者。

2.8 registerListeners

1.如果我们手动通过org.springframework.context.support.AbstractApplicationContext#addApplicationListener添加监听者,则将其添加到监听者队列。

2.发布earlyApplicationEvent事件给对应的监听者。

2.9 finishBeanFactoryInitialization(BeanFactory)

这一步会实例化并初始化“非懒加载”的Bean。至于如何进行Bean实例化和依赖注入请看博文:Spring---Bean实例化过程分析。我们在这里主要列举一下Bean实例化过程中的一些钩子函数的触发时机。

首先了解一下常见钩子函数的作用:

org.springframework.beans.factory.config.BeanPostProcessor

//Bean初始化之前可以对Bean进行处理,比如对Bean进行校验 @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } //Bean初始化之后可以对Bean进行处理,比如ApplicationListenerContactor判断Bean实现了ApplicationListener接口,则将其添加到监听者队列 @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

//Bean实例化之前进行处理,比如创建一个代理类 @Nullable default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; } //Bean实例化之后进行处理 default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; }

org.springframework.beans.factory.InitializingBean

//在Bean的所有属性设置完成之后进行调用,看过Dubbo源码的同学,可以知道ServiceBean实例了该接口,在 //属性设置完毕之后,暴露该服务到注册中心 void afterPropertiesSet() throws Exception;

org.springframework.beans.factory.Aware

常见的有ApplicationContextAware,我们可以通过该接口,感知Spring上下文信息。

//org.springframework.context.ApplicationContextAware //比如dubbo的ServiceBean实现该接口,获取Spring上下文,传到Dubbo自己的应用上下文里面,自己实现了 //一个简单的依赖注入 void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

常见的钩子函数如上,其调用顺序如下:

2.10 finishRefresh

在该方法中会发布应用上下文刷新完毕事件ContextRefreshedEvent给对应的时间监听者,Dubbo的ServiceBean同样监听了此事件,有兴趣的可以研究一下。

 

至此AbstractApplicationContext.refresh()方法和Spring常见的钩子函数已分析完毕,如有问题请指正。

最新回复(0)