本文已收录 【修炼内功】跃迁之路
在 [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
- 提供扩展能力,并注册众多默认扩展能力
- ...
本文就扩展能力着重介绍
从上图中看到了熟悉的ClasspathXmlApplicationContext及AnnotationConfigApplicationContext,无论何种功能的ApplicationContext,在做完基本的初始化后均会调用AbstractApplicationContext#refresh,这也是今天的入口
从上图中似乎看到了一些熟悉的内容,Aware、BeanFactoryPostProcessor、BeanPostProcessor、等等,或许可以解释上篇 [spring-framework] [3] Bean是如何被创建的 及文章开始处的一些问题
准备上下文
AbstractApplicationContext#prepareRefresh
该部分主要实现对上下文的准备工作,其主要涉及到两个接口AbstractApplicationContext#initPropertySources及ConfigurablePropertyResolver#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基本步骤为
- 创建BeanFactory (DefaultListableBeanFactory)
- 设置BeanFactory
- 加载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
该会函数执行以下逻辑
- 设置BeanFactory的ClassLoader
- 注册默认BeanExpressionResolver,用于依赖注入时SpEL的支持
- 注册默认PropertyEditor,用于依赖注入时对参数的解析转换
- 注册几个特殊Aware的处理逻辑
- 注册AspectJ相关的几个处理器,用于AOP的支持
- 注册几个特殊的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呢?上面了解到,可以通过设置AbstractBeanFactory的propertyEditorRegistrars或者customEditors实现批量或者单个PropertyEditor的注册,这里Spring为开发者提供了CustomEditorConfigurer,我们只需要注册一个CustomEditorConfigurer类型的Bean,并设置其中的propertyEditorRegistrars或customEditors即可
// 注册
@Bean
public CustomEditorConfigurer myEditors() {
CustomEditorConfigurer editorConfigurer = new CustomEditorConfigurer();
// 设置CustomEditors,或者PropertyEditorRegistrars
editorConfigurer.setCustomEditors(new HashMap, 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方法将上述自定义的值设置到AbstractBeanFactory的propertyEditorRegistrars及customEditors中(继续向下阅读,了解BeanFactoryPostProcessor的作用)
public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {
// 自定义PropertyEditorRegistrar实现批量注册
@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars;
// 自定义PropertyEditor实现单个注册
@Nullable
private Map, Class extends PropertyEditor>> customEditors;
// ... setters & setters
}
注册特殊Aware的处理逻辑
参考上篇文章[spring-framework] [3] Bean是如何被创建的,在bean实例化并且注入依赖之后会执行AbstractAutowireCapableBeanFactory#initializeBean对bean进行最后的初始化,其中在在AbstractAutowireCapableBeanFactory#invokeAwareMethods内分别针对BeanNameAware、BeanClassLoaderAware及BeanFactoryAware进行了处理(调用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
- systemEnvironment - Environment#.getSystemEnvironment:Map
以上均可直接注入使用
激活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());
}
PropertySourcesPlaceholderConfigurer是 PropertyResourceConfigurer的增强,其内部加入了 Environment的读取支持
对于一些组件,可以将外部的Properties合并到 Environment,即可通过 @Value("${ ... }")注入
Q: 如何自定义 StringValueResolver并注册,解析特殊场景的字符串?
那类似PropertyResourceConfigurer之类的BeanFactoryPostProcessor,其postProcessBeanFactory方法是在什么时候调用的?
回到AbstractApplicationContext#invokeBeanFactoryPostProcessors,其代码虽然比较长,但内部逻辑比较清晰
这里涉及到两种类型,BeanDefinitionRegistryPostProcessor及BeanFactoryPostProcessor前者为后者的子类,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.*,便可以直接注入 DataSource、 JdbcTemplate等beanQ: 在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;
}
}
- postProcessBeforeInitialization方法在调用bean的init-method之前执行
- postProcessAfterInitialization方法在调用bean的init-method之后执行
- 任何一个方法可对现有bean实例做进一步的修改
- 任何一个方法可返回新的bean实例,用来替代现有的bean实例
详见[spring-framework] [3] Bean是如何被创建的
尤其是第4点,AOP既是使用该特性在postProcessAfterInitialization方法中生成当前bean实例的代理
除此之外还有一个特殊的BeanPostProcessor - InstantiationAwareBeanPostProcessor,其同样有两个方法,一个在创建bean实例之前调用,一个在创建bean实例之后、属性注入之前调用,其具体调用逻辑参见[spring-framework] [3] Bean是如何被创建的
回到AbstractApplicationContext#registerBeanPostProcessors,其内部逻辑与BeanFactoryPostProcessor的注册逻辑类似,这里不再画流程图
- 找到所有BeanPostProcessor并实例化
- 按照实现的Ordered接口分别放入priorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors并各自排序
- 如果实现了MergedBeanDefinitionPostProcessor则放入internalPostProcessors并排序
- 按顺序依次注册priorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors
- 最后注册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才会异步调用,不过这样的控制粒度比较粗,要么全部同步消费要么全部异步消费,比较细粒度的控制事件的消费有几种常用方法
- 使用@Async注解,独立控制某一listener异步消费(https://www.baeldung.com/spri...)
- 自行编码,将onApplicationEvent逻辑放在线程中执行
- 注册自定义的ApplicationEventMulticaster,内部实现自己的同步、异步Event处理逻辑
注册ApplicationListener
AbstractApplicationContext#registerListeners
这里的逻辑比较简单
- 在BeanFactory中找到ApplicationListener类型的bean并实例化
- 调用ApplicationEventMulticaster#addApplicationListenerBean方法将ApplicationListeners注册进去
初始化所有非Lazy Bean
AbstractApplicationContext#finishBeanFactoryInitialization
对于Singleton Bean而言,实例化发生在首次getBean,但你是否有疑惑,我们只是注册了众多Singleton Bean,但在Spring初始化完成后所有的Singleton Bean(Lazy Bean除外)均已经完成实例化
回到AbstractApplicationContext#finishBeanFactoryInitialization,该函数会实现几个逻辑
- 如果自定义了ConversionService(另一种注入类型转换的方式)类型bean且bean-name为conversionService,则将其注册到BeanFactory中
- 如果BeanFactory中不存在EmbeddedValueResolver(PropertyResourceConfigurer会注册一个PlaceholderResolvingStringValueResolver到BeanFactory中),则会注册一个默认的StringValueResolver用来处理
${ ... }
类型的值(Environment#resolvePlaceholders) -
找到所有非Lazy的Singleton BeanDefinition进行实例化(getBean)
- 如果是FactoryBean,则在bean name前加上’&’,并实例化该FactoryBean,随后实例化真实的bean
- 如果不是FactoryBean,则直接实例化该bean
- 执行SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
Refresh的后续动作
AbstractApplicationContext#finishRefresh
这里,除了一些中间状态需要清理外,还有两件比较特殊的地方
LifecycleProcessor
AbstractApplicationContext#initLifecycleProcessor
Spring提供了LifecycleProcessor用于监听BeanFactory的refresh及close,在BeanFactory的各阶段会调用LifecycleProcessor的onFresh及onClose方法
开发者可以自行注册LifecycleProcessor类型的bean,bean-name必须为“lifecycleProcessor”,否则Spring会提供一个默认的DefaultLifecycleProcessor
之后则会触发LifecycleProcessor的onFresh方法
除此之外,还可以监听 ContextRefreshedEvent及 ContextClosedEvent消息
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具体的销毁过程
- 发出ContextClosedEvent事件
- 触发LifecycleProcessor的onClose方法
- 销毁bean,细节参考[spring-framework] [3] Bean是如何被创建的
- 由子类实现的AbstractApplicationContext#closeBeanFactory及AbstractApplicationContext#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