【修炼内功】[spring-framework] [4] ApplicationContext给开发者提供了哪些(默认)扩展

本文已收录【修炼内功】跃迁之路

spring-framework.jpg

林中小舍.png

[spring-framework] [3] Bean是如何被创建的 一文中介绍了Spring体系内bean的创建及销毁过程,也简单提到了Spring预留给开发者的一些扩展点

  • @Value中的表达式是如何解析的
  • 代理类是如何生成的(AOP)
  • 各种Aware的setter方法是如何被调用的
  • Event是如何被监听并处理的
  • 各种开箱即用的starter是如何动态注册bean的
  • ...

本文就Spring注册扩展点的方式、默认扩展点、自定义扩展点进行展开介绍,除此外也希望能通过Spring的代码设计,扩充自己在代码乃至系统设计上的能力

什么是ApplicationContext?

BeanFactory实现了IOC的基础能力,ApplicationContext又是什么?

ApplicationContext是BeanFactoryBean的子类,除了继承IOC的基础能力外

  • 支持国际化(MessageSource
  • 支持资源访问(ResourcePatternResolver,详见[spring-framework] [1] Resource
  • 事件机制(ApplicationEventPublisher
  • 默认初始化所有Singleton
  • 提供扩展能力,并注册众多默认扩展能力
  • ...

本文就扩展能力着重介绍

Context.ApplicationContext

从上图中看到了熟悉的ClasspathXmlApplicationContextAnnotationConfigApplicationContext,无论何种功能的ApplicationContext,在做完基本的初始化后均会调用AbstractApplicationContext#refresh,这也是今天的入口

Flowchart.refresh

从上图中似乎看到了一些熟悉的内容,Aware、BeanFactoryPostProcessor、BeanPostProcessor、等等,或许可以解释上篇 [spring-framework] [3] Bean是如何被创建的 及文章开始处的一些问题

准备上下文

AbstractApplicationContext#prepareRefresh

该部分主要实现对上下文的准备工作,其主要涉及到两个接口AbstractApplicationContext#initPropertySourcesConfigurablePropertyResolver#validateRequiredProperties

前者由子类实现,用于初始化PropertySource;后者用于对必要属性进行验证,如

public class MyClasspathXmlApplicationContext extends ClassPathXmlApplicationContext {
    @Override
    protected void initPropertySources() {
        super.initPropertySources();
        getEnvironment().setRequiredProperties("runtimeEnv");
    }
}

重写initPropertySources方法,并添加runtimeEnv为必须的环境变量属性,如此在系统启动的时候便会进行检测,对于不存在任何一个必要环境变量的情况均会抛出异常终止启动

加载BeanFactory

AbstractApplicationContext#obtainFreshBeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  // 子类实现
    refreshBeanFactory();
    return getBeanFactory();
}

该函数内部实现比较简单,重点在refreshBeanFactory,该函数同样由子类实现

☆ 对于AbstractRefreshableApplicationContext(),refreshBeanFactory基本步骤为

  1. 创建BeanFactory (DefaultListableBeanFactory)
  2. 设置BeanFactory
  3. 加载BeanDefinition

在第3步中,AbstractXmlApplicationContext的实现则是对xml配置文件的解析及加载(见[spring-framework] [3] Bean是如何被创建的);AnnotationConfigWebApplicationContext的实现则是对class文件的扫描并加载(基于注解的Bean扫描及加载逻辑会放在SpringBoot系列文章中);等其他基于AbstractRefreshableApplicationContext的ApplicationContext实现

☆ 对于GenericApplicationContext,BeanFactory的创建及BeanDefinition的加载在refresh调用之前早已完成,refreshBeanFactory的实现则是对BeanFactory加载状态的简单校验(AnnotationConfigApplicationContext的Bean扫描及加载逻辑会放在SpringBoot系列文章中)

填充部分扩展

AbstractApplicationContext#prepareBeanFactory

该会函数执行以下逻辑

  1. 设置BeanFactory的ClassLoader
  2. 注册默认BeanExpressionResolver,用于依赖注入时SpEL的支持
  3. 注册默认PropertyEditor,用于依赖注入时对参数的解析转换
  4. 注册几个特殊Aware的处理逻辑
  5. 注册AspectJ相关的几个处理器,用于AOP的支持
  6. 注册几个特殊的BeanDefinition

注册默认BeanExpressionResolver

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

StandardBeanExpressionResolve的作用在于使用SpEL解析 #{ ... }类型的值,具体的解析逻辑见StandardBeanExpressionResolver#evaluate,那Spring在什么时候使用StandardBeanExpressionResolve呢?还记得上篇文章[spring-framework] [3] Bean是如何被创建的介绍的,在解析依赖的值时DefaultListableBeanFactory#doResolveDependency

Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
    if (value instanceof String) {
        String strVal = resolveEmbeddedValue((String) value);
        BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                getMergedBeanDefinition(beanName) : null);
    // 使用StandardBeanExpressionResolve,利用SpEL,对 #{ ... } 类型的值进行解析
        value = evaluateBeanDefinitionString(strVal, bd);
    }
}
Q: Spring中默认的,除了可以处理 #{ ... } 外,还可以处理 ${ ... },后者的处理器是如何注册的?

注册默认的PropertyEditor

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

严格来讲,这里并没有直接注册PropertyEditor,而是注册PropertyEditorRegistrar,前者用于真正的类型转换,后者用于PropertyEditor的注册

PropertyEditor - supports a variety of different kinds of ways of displaying and updating property values. Most PropertyEditors will only need to support a subset of the different options available in this API.

PropertyEditorRegistry - Encapsulates methods for registering JavaBeans PropertyEditors. This is the central interface that a PropertyEditorRegistrar operates on.

addPropertyEditorRegistrar的逻辑非常简单,将需要注册的PropertyEditorRegistrar存放在AbstractBeanFactory#propertyEditorRegistrars,那何时使用呢?

还记得上篇文章中介绍的BeanWrapper么?在实例化bean之后属性依赖注入之前,会将实例化的bean包装为BeanWrapper并进行初始化(AbstractBeanFactory#initBeanWrapper),其内部会使用到AbstractBeanFactory#registerCustomEditors

// org.springframework.beans.factory.support.AbstractBeanFactory#registerCustomEditors 节选
if (!this.propertyEditorRegistrars.isEmpty()) {
  // 1. 使用 propertyEditorRegistrars 注册
    for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
            registrar.registerCustomEditors(registry);
  }
}
if (!this.customEditors.isEmpty()) {
  // 2. 使用 customEditors 注册
    this.customEditors.forEach((requiredType, editorClass) ->
            registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
}

回头看ResourceEditorRegistrar#registerCustomEditors,其一共注册了12种PropertyEditor(源码比较简单,不再贴出)

Type PropertyEditor
Resource ResourceEditor
Resource[] ResourceArrayPropertyEditor
ContextResource ResourceEditor
InputStream InputStreamEditor
InputSource InputStreamEditor
File FileEditor
Path PathEditor
Reader ReaderEditor
URL URLEditor
URI URIEditor
Class ClassEditor
Class[] ClassArrayEditor

AbstractBeanFactory#registerCustomEditors提供了两种注册方式

  • 使用AbstractBeanFactory#propertyEditorRegistrars批量注册
  • 使用AbstractBeanFactory#customEditors单个注册

Q: 是否可以自定义PropertyEditor注册?

那,PropertyEditor何时使用?这里就要再次回到解析依赖的值时的DefaultListableBeanFactory#doResolveDependency(参考[spring-framework] [3] Bean是如何被创建的

Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
    if (value instanceof String) {
        String strVal = resolveEmbeddedValue((String) value);
        BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                getMergedBeanDefinition(beanName) : null);
    // 使用StandardBeanExpressionResolve,利用SpEL,对 #{ ... } 类型的值进行解析
        value = evaluateBeanDefinitionString(strVal, bd);
    }
  TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
  // 使用PropertyEditors进行类型转换
    return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}

结合上篇文章,事情是否慢慢变得明朗起来?但,Spring提供给开发者的PropertyEditor仅仅以上12种么?如果仔细源码源码的话会发现,在TypeConverterDelegate#convertIfNecessary的逻辑中,如果在上述已注册的PropertyEditors中找不到合适的Editor时,则会在默认的PropertyEditors中继续匹配,默认的PropertyEditor逻辑在PropertyEditorRegistrySupport#createDefaultEditors,同样以表格形式列出

Type PropertyEditor
Charset CharsetEditor
Class ClassEditor
Class[] ClassArrayEditor
Currency CurrencyEditor
File FileEditor
InputStream InputStreamEditor
InputSource InputSourceEditor
Locale LocaleEditor
Path PathEditor
Pattern PatternEditor
Properties PropertiesEditor
Reader ReaderEditor
Resource[] ResourceArrayPropertyEditor
TimeZone TimeZoneEditor
URI URIEditor
URL URLEditor
UUID UUIDEditor
ZoneId ZoneIdEditor
Collection CustomCollectionEditor
Set CustomCollectionEditor
SortedSet CustomCollectionEditor
List CustomCollectionEditor
SortedMap CustomMapEditor
byte[] ByteArrayPropertyEditor
char[] CharArrayPropertyEditor
char CharacterEditor
Character CharacterEditor
boolean CustomBooleanEditor
Boolean CustomBooleanEditor
byte CustomNumberEditor
Byte CustomNumberEditor
short CustomNumberEditor
hort CustomNumberEditor
int CustomNumberEditor
Integer CustomNumberEditor
long CustomNumberEditor
Long CustomNumberEditor
float CustomNumberEditor
Float CustomNumberEditor
double CustomNumberEditor
Double CustomNumberEditor
BigDecimal CustomNumberEditor
BigInteger CustomNumberEditor
BigInteger[] StringArrayPropertyEditor
short[] StringArrayPropertyEditor
int[] StringArrayPropertyEditor
long[] StringArrayPropertyEditor

注册自定义的PropertyEditor

是否尝到了PropertyEditor的甜头,那如何注册自己的PropertyEditor呢?上面了解到,可以通过设置AbstractBeanFactorypropertyEditorRegistrars或者customEditors实现批量或者单个PropertyEditor的注册,这里Spring为开发者提供了CustomEditorConfigurer,我们只需要注册一个CustomEditorConfigurer类型的Bean,并设置其中的propertyEditorRegistrarscustomEditors即可

// 注册
@Bean
public CustomEditorConfigurer myEditors() {
  CustomEditorConfigurer editorConfigurer = new CustomEditorConfigurer();
  // 设置CustomEditors,或者PropertyEditorRegistrars
  editorConfigurer.setCustomEditors(new HashMap<Class<?>, Class<? extends PropertyEditor>> {{
    put(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy/MM/dd HH:mm"), false));
  }});
  return editorConfigurer;
}

// 使用
@Value("2020/04/19 15:09")
private Date now;

其原理在于CustomEditorConfigurer继承了BeanFactoryPostProcessor,Spring会自动调用CustomEditorConfigurer#postProcessBeanFactory方法将上述自定义的值设置到AbstractBeanFactorypropertyEditorRegistrarscustomEditors中(继续向下阅读,了解BeanFactoryPostProcessor的作用)

public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {
  // 自定义PropertyEditorRegistrar实现批量注册
  @Nullable
    private PropertyEditorRegistrar[] propertyEditorRegistrars;

  // 自定义PropertyEditor实现单个注册
    @Nullable
    private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;
  
  // ... setters & setters
}

注册特殊Aware的处理逻辑

参考上篇文章[spring-framework] [3] Bean是如何被创建的,在bean实例化并且注入依赖之后会执行AbstractAutowireCapableBeanFactory#initializeBean对bean进行最后的初始化,其中在在AbstractAutowireCapableBeanFactory#invokeAwareMethods内分别针对BeanNameAwareBeanClassLoaderAwareBeanFactoryAware进行了处理(调用setter方法设置相应的注入),除此之外Spring还有提供其他的Aware么?

AbstractApplicationContext#prepareBeanFactory中Spring会注册一个特殊的BeanPostProcessor

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

其实现了postProcessBeforeInitialization方法,其内部调用ApplicationContextAwareProcessor#invokeAwareInterfaces针对另外的几类Aware进行了处理

Aware Invoke From
EnvironmentAware ApplicationContextAwareProcessor#postProcessBeforeInitialization
EmbeddedValueResolverAware ApplicationContextAwareProcessor#postProcessBeforeInitialization
ResourceLoaderAware ApplicationContextAwareProcessor#postProcessBeforeInitialization
ApplicationEventPublisherAware ApplicationContextAwareProcessor#postProcessBeforeInitialization
MessageSourceAware ApplicationContextAwareProcessor#postProcessBeforeInitialization
ApplicationContextAware ApplicationContextAwareProcessor#postProcessBeforeInitialization
BeanNameAware AbstractAutowireCapableBeanFactory#invokeAwareMethods
BeanClassLoaderAware AbstractAutowireCapableBeanFactory#invokeAwareMethods
BeanFactoryAware AbstractAutowireCapableBeanFactory#invokeAwareMethods

除此之外,Spring会将上述几类Aware设置为ignoreDependencyInterface,这意味着以上几类Bean的注入只能通过Aware的方式而不能通过其他属性依赖注入的方式(属性注入、函数参数注入、等)

依赖注入有两种方式,其各有所长

  • 通过属性、方法参数注入
  • 通过Aware注入

Q: 是否可以自定义Aware并实现特殊依赖的注入?

注册特殊的Bean

在使用Spring时,是否有过直接注入BeanFactory亦或是ResourceLoader,这些bean正是在这里被Spring注册进去的,除以上外Spring还注入了

  • BeanFactory
  • ResourceLoader
  • ApplicationEventPublisher
  • ApplicationContext
  • Environment
  • systemProperties - Environment#.getSystemProperties:Map<String, Object>
  • systemEnvironment - Environment#.getSystemEnvironment:Map<String, Object>

以上均可直接注入使用

激活BeanFactoryPostProcessor

AbstractApplicationContext#invokeBeanFactoryPostProcessors

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

BeanPostProcessor在bean的实例化过程中起着重要的作用([spring-framework] [3] Bean是如何被创建的),BeanFactoryPostProcessor同样在BeanFactory的初始化过程中起着重要的作用

BeanFactoryPostProcessor的定义非常简单,其postProcessBeanFactory方法允许在bean实例化前对BeanFactory做一些额外的设置

public interface BeanFactoryPostProcessor {
    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

最典型的BeanFactoryPostProcessor便是PropertyResourceConfigurer

// org.springframework.beans.factory.config.PropertyResourceConfigurer
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  // SpringBoot中默认读取application.properties/yml及application-[env].properties/yml等并做合并
  Properties mergedProps = mergeProperties();
  convertProperties(mergedProps);
  // 将Properties封装为PlaceholderResolvingStringValueResolver
  // 注册到AbstractBeanFactory#embeddedValueResolvers
  processProperties(beanFactory, mergedProps);
}

PlaceholderResolvingStringValueResolver可以做什么?在注入依赖时处理${ ... }类型的值!什么时候调用?再再次回到解析依赖的值时的DefaultListableBeanFactory#doResolveDependency(参考[spring-framework] [3] Bean是如何被创建的

Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
    if (value instanceof String) {
    // 使用StringValueResolvers对特殊类型的字符串进行解析,如 ${ ... }
        String strVal = resolveEmbeddedValue((String) value);
        BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                getMergedBeanDefinition(beanName) : null);
    // 使用StandardBeanExpressionResolve,利用SpEL,对 #{ ... } 类型的值进行解析
        value = evaluateBeanDefinitionString(strVal, bd);
    }
  TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
  // 使用PropertyEditors进行类型转换
    return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
PropertySourcesPlaceholderConfigurerPropertyResourceConfigurer的增强,其内部加入了Environment的读取支持
对于一些组件,可以将外部的Properties合并到Environment,即可通过@Value("${ ... }")注入
Q: 如何自定义StringValueResolver并注册,解析特殊场景的字符串?

那类似PropertyResourceConfigurer之类的BeanFactoryPostProcessor,其postProcessBeanFactory方法是在什么时候调用的?

回到AbstractApplicationContext#invokeBeanFactoryPostProcessors,其代码虽然比较长,但内部逻辑比较清晰

Flowchart.invokeBeanFactoryPostProcessors

这里涉及到两种类型,BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor前者为后者的子类,BeanDefinitionRegistryPostProcessors提供了额外的接口postProcessBeanDefinitionRegistry,用于更加方便地动态地注册额外的BeanDefinition,如读取配置文件(json、properties、yml)并解析(或者任何其他的形式),并通过该接口注册相应的BeanDefinition,基于Spring Boot Starter的很多框架均使用该方式进行bean的注册

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    /**
     * Modify the application context's internal bean definition registry after its
     * standard initialization. All regular bean definitions will have been loaded,
     * but no beans will have been instantiated yet. This allows for adding further
     * bean definitions before the next post-processing phase kicks in.
     */
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
Spring Boot提供了众多开箱即用的starter,如spring-boot-starter-data-jpa,只需要在配置文件中设置spring.datasource.*,便可以直接注入DataSourceJdbcTemplate等bean

Q: 在Spring Boot中,各种starter是如何通过配置文件实现bean的动态注册的?

Q: 除了使用BeanDefinitionRegistryPostProcessor实现BeanDefinition的动态注册外,还有没有其他的方式?ImportBeanDefinitionRegistrar的实现逻辑是怎样的?

以上流程图可以看出,优先执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry,再执行BeanFactoryPostProcessor#postProcessBeanFactory,各自内部优先执行PriorityOrdered实现,再执行Ordered实现,最后执行无任何排序的实现

注册BeanPostProcessor

AbstractApplicationContext#registerBeanPostProcessors

PostProcessorRegistrationDelegate#registerBeanPostProcessors

先来认识一下BeanPostProcessor

public interface BeanPostProcessor {
    /**
     * Apply this BeanPostProcessor to the given new bean instance before any bean
     * initialization callbacks (like InitializingBean's afterPropertiesSet
     * or a custom init-method). 
     * The returned bean instance may be a wrapper around the original.
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * Apply this BeanPostProcessor to the given new bean instance after any bean
     * initialization callbacks (like InitializingBean's afterPropertiesSet
     * or a custom init-method).
     * The returned bean instance may be a wrapper around the original.
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
  1. postProcessBeforeInitialization方法在调用bean的init-method之前执行
  2. postProcessAfterInitialization方法在调用bean的init-method之后执行
  3. 任何一个方法可对现有bean实例做进一步的修改
  4. 任何一个方法可返回新的bean实例,用来替代现有的bean实例

详见[spring-framework] [3] Bean是如何被创建的

尤其是第4点,AOP既是使用该特性在postProcessAfterInitialization方法中生成当前bean实例的代理

除此之外还有一个特殊的BeanPostProcessor - InstantiationAwareBeanPostProcessor,其同样有两个方法,一个在创建bean实例之前调用,一个在创建bean实例之后、属性注入之前调用,其具体调用逻辑参见[spring-framework] [3] Bean是如何被创建的

回到AbstractApplicationContext#registerBeanPostProcessors,其内部逻辑与BeanFactoryPostProcessor的注册逻辑类似,这里不再画流程图

  1. 找到所有BeanPostProcessor并实例化
  2. 按照实现的Ordered接口分别放入priorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors并各自排序
  3. 如果实现了MergedBeanDefinitionPostProcessor则放入internalPostProcessors并排序
  4. 按顺序依次注册priorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors
  5. 最后注册internalPostProcessors

MergedBeanDefinitionPostProcessor是什么?其有一个接口postProcessMergedBeanDefinition,在bean实例化完成后属性注入之前被调用,可以用来对当前的BeanDefinition做进一步的修改,如增加PropertyValue等,实现特殊的属性依赖注入,可参考[spring-framework] [3] Bean是如何被创建的AutowiredAnnotationBeanPostProcessor

Q: @Value @Autowired @Inject等注解是如何处理的?

参考 InstantiationAwareBeanPostProcessor#postProcessProperties

  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor

初始化MessageSource

AbstractApplicationContext#initMessageSource

这里不详细展开,Spring的MessageSource提供了国际化能力,在开发者未注册MessageSource的情况下Spring会提供一个默认的DelegatingMessageSource

初始化ApplicationEventMulticaster

AbstractApplicationContext#initApplicationEventMulticaster

Spring提供了一套事件(ApplicationEvent)的发布&订阅机制,开发者可自定义事件(继承ApplicationEvent),注册事件监听器来订阅消费事件(实现ApplicationListener或使用@EventListener注解),并使用ApplicationEventPublisher(直接依赖注入或者使用ApplicationEventPublisherAware)发送事件,使用示例可参考https://www.baeldung.com/spri...

其实ApplicationContext实现了ApplicationEventPublisher,跟踪其publishEvent方法会发现,最终调用了AbstractApplicationContext#applicationEventMulticaster.multicastEvent,开发者可以自行注册一个ApplicationEventMulticaster,如果没有Spring会提供一个默认的SimpleApplicationEventMulticaster

SimpleApplicationEventMulticaster#multicastEvent的逻辑比较简单,会根据事件的类型找到可以处理的所有ApplicationListener,依次调用它们的onApplicationEvent方法消费事件

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
      // 设置了executor,则异步执行
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
      // 否则同步执行
            invokeListener(listener, event);
        }
    }
}

这里有一个比较有意思的地方,默认情况下会同步、顺序的调用listeners的onApplicationEvent方法,只有设置了executor才会异步调用,不过这样的控制粒度比较粗,要么全部同步消费要么全部异步消费,比较细粒度的控制事件的消费有几种常用方法

  1. 使用@Async注解,独立控制某一listener异步消费(https://www.baeldung.com/spri...
  2. 自行编码,将onApplicationEvent逻辑放在线程中执行
  3. 注册自定义的ApplicationEventMulticaster,内部实现自己的同步、异步Event处理逻辑

注册ApplicationListener

AbstractApplicationContext#registerListeners

这里的逻辑比较简单

  1. 在BeanFactory中找到ApplicationListener类型的bean并实例化
  2. 调用ApplicationEventMulticaster#addApplicationListenerBean方法将ApplicationListeners注册进去

初始化所有非Lazy Bean

AbstractApplicationContext#finishBeanFactoryInitialization

对于Singleton Bean而言,实例化发生在首次getBean,但你是否有疑惑,我们只是注册了众多Singleton Bean,但在Spring初始化完成后所有的Singleton Bean(Lazy Bean除外)均已经完成实例化

回到AbstractApplicationContext#finishBeanFactoryInitialization,该函数会实现几个逻辑

  1. 如果自定义了ConversionService(另一种注入类型转换的方式)类型bean且bean-name为conversionService,则将其注册到BeanFactory中
  2. 如果BeanFactory中不存在EmbeddedValueResolverPropertyResourceConfigurer会注册一个PlaceholderResolvingStringValueResolver到BeanFactory中),则会注册一个默认的StringValueResolver用来处理 ${ ... }类型的值(Environment#resolvePlaceholders
  3. 找到所有非Lazy的Singleton BeanDefinition进行实例化(getBean

    1. 如果是FactoryBean,则在bean name前加上’&’,并实例化该FactoryBean,随后实例化真实的bean
    2. 如果不是FactoryBean,则直接实例化该bean
  4. 执行SmartInitializingSingleton实现类的afterSingletonsInstantiated方法

Refresh的后续动作

AbstractApplicationContext#finishRefresh

这里,除了一些中间状态需要清理外,还有两件比较特殊的地方

LifecycleProcessor

AbstractApplicationContext#initLifecycleProcessor

Spring提供了LifecycleProcessor用于监听BeanFactory的refresh及close,在BeanFactory的各阶段会调用LifecycleProcessoronFreshonClose方法

开发者可以自行注册LifecycleProcessor类型的bean,bean-name必须为“lifecycleProcessor”,否则Spring会提供一个默认的DefaultLifecycleProcessor

之后则会触发LifecycleProcessoronFresh方法

除此之外,还可以监听ContextRefreshedEventContextClosedEvent消息

refresh事件

在BeanFactory初始化完成后,则会发出ContextRefreshedEvent事件

BeanFactory的销毁

AbstractApplicationContext#registerShutdownHook

该函数用来注册BeanFactory的销毁逻辑

public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        // No shutdown hook registered yet.
        this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
            @Override
            public void run() {
                synchronized (startupShutdownMonitor) {
                    doClose();
                }
            }
        };
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}

其直接使用了java的addShutdownHook函数,在jvm进程正常退出的时候触发

AbstractApplicationContext#doClose函数定义了BeanFactory具体的销毁过程

  1. 发出ContextClosedEvent事件
  2. 触发LifecycleProcessoronClose方法
  3. 销毁bean,细节参考[spring-framework] [3] Bean是如何被创建的
  4. 由子类实现的AbstractApplicationContext#closeBeanFactoryAbstractApplicationContext#onClose方法
Q: shutdownHook的注册逻辑由谁调用?

至此,我们理解了Spring BeanFactory的生命周期及Spring提供给开发者的(默认)扩展

小结

  • BeanDefinition的加载在AbstractApplicationContext#obtainFreshBeanFactory中实现
  • #{ ... }类型值的解析由StandardBeanExpressionResolve实现
  • ${ ... }类型值的解析由PlaceholderResolvingStringValueResolver实现
  • Spring提供了众多默认的PropertyEditor,若需要自定义PropertyEditor可以通过注册CustomEditorConfigurer实现
  • Spring提供了众多Aware,若需要自定义Aware可以通过BeanPostProcessor实现
  • BeanFactoryPostProcessor用于在实例化bean之前对BeanFactory做额外的动作

    如,PropertyResourceConfigurer用来将PlaceholderResolvingStringValueResolver注册到BeanFactory的embeddedValueResolvers中

  • BeanDefinitionRegistryPostProcessor用于在实例化bean之前(动态)注册额外的BeanDefinition
  • BeanPostProcessor用于在调用bean的init-method前后,对实例化完成的bean做一些额外的干预

    如,CommonAnnotationBeanPostProcessor用来处理@PostConstructor,AbstractAdvisingBeanPostProcessor用来实现AOP


订阅号

阅读 376

推荐阅读
林中小舍
用户专栏

工作中的坑点及经验

51 人关注
41 篇文章
专栏主页