用于在容器启动过程中处理标注@Configuration
类的BeanFactoryPostProcessor 。在xml配置文件中使用<context:annotation-config/>
or <context:component-scan/>
都会注册这个后置处理器。这个Bean非常重要,因为在标注@Configuration
的类中包含了其他需要进行注册的Bean定义,所以在与其他相同类型后置处理器一起使用时,优先级较高,因此通过实现了接口PriorityOrdered来保证初始化的顺序性。
首先看一下这个类的结构图:
从这个图不难看出,通过多个Aware
{ResourceLoaderAware
, BeanClassLoaderAware
, EnvironmentAware
},引入了资源加载工具类ResoureLoader
和环境参数Environment
、类加载器ClassLoader
。当然最重要的还是BeanDefinitionRegistryPostProcessor
这个接口了。作为一个标准的BeanFactoryPostProcessor
的SPI扩展,允许在常规的BeanFactoryPostProcessor
起作用之前进行Bean的注册(通常也可以用于进行BeanFactoryPostProcessor
类型Bean的注册)。主要的方法如下所示:
/**
* 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.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
另外BeanDefinitionRegistryPostProcessor
也继承了BeanFactoryPostProcessor
,后者主要用于在Bean开始创建之前对Bean的定义进行修改操作的。其中最为人所知的就是PropertyResourceConfigurer
.这个接口定义的方法为
/**
* 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.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
在ConfigurationClassPostProcessor
中首先起作用的是那三个Aware方法,然后是postProcessBeanDefinitionRegistry
,最后是postProcessBeanFactory
。
注册的时机
那么ConfigurationClassPostProcessor
是何时注册到Spring容器中的呢?其实在Spring容器创建的时候就会注册一些基础的bean,ConfigurationClassPostProcessor
就是其中的一员。
参考博客Spring创建容器时就存在的5个Bean: https://blog.csdn.net/m0_37607945/article/details/106418334
执行时机
主要参考PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
首先会从Spring的Bean定义工厂中查找到ConfigurationClassPostProcessor
并进行初始化,ConfigurationClassPostProcessor
在Spring容器中也是作为一个Bean存在的。在这个Bean初始化的过程中,就执行到invokeAwareMethods(beanName, bean);
方法,此时就会到对应接口BeanClassLoaderAware
的方法、
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
另外两个Aware接口也是在Bean实例化过程中回调的,只不过在BeanClassLoaderAware后面,如下图所示,一个是在图中1位置,一个是在图中2位置。
通过一个类型为ApplicationContextAwareProcessor
的后置处理器来处理的。
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
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);
}
}
}
那么此处有一个问题,这个ApplicationContextAwareProcessor
是什么时候实例化的呢?难道还会在ConfigurationClassPostProcessor
之前实例化?我们前面不都提到过,ConfigurationClassPostProcessor
优先级比较高,而且在其他类型bean实例化之前就开始实例化并invoke调用了?在Spring容器中,BeanPostProcessor
也是在BeanFactoryPostProcessor
之后的。如下图所示:
但因为这个ApplicationContextAwareProcessor
地位重要(任何bean都可能实现ApplicationContextAware
接口),所示必须提前进行了初始化。如下图所示,ApplicationContextAwareProcessor
是在1里面进行实例化的,而ConfigurationClassPostProcessor
却要等到2里面进行实例化,而其他常规bean更要靠后才会初始化,所以这样才能达到实现了ApplicationContextAware
接口的bean都能被设置ApplicationContext
属性。
对应的源码如下所示:
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
// 此处添加了一个后置处理器,当所有Bean初始化的过程中就会进行回调,一些Aware接口就回起作用
// 直接new就可以了 Spring中的bean不一定都是反射的 也可以直接new出来
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
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());
}
}
在这里,有很多一些重要的设置,除了这个ApplicationListenerDetector之外,还注册了一些单例,比如如下几个名称的单例bean。
String ENVIRONMENT_BEAN_NAME = "environment";
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
为什么我们能够自动注入ApplicationContext的,秘密就在上面。
执行逻辑
一 :从Configuration类中提取Bean定义
- 首先通过两个Set集合保证postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法还未执行,也就是说processConfigBeanDefinitions方法只能执行一次
private final Set<Integer> registriesPostProcessed = new HashSet<>();
private final Set<Integer> factoriesPostProcessed = new HashSet<>();
/**
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 使用hashCode作为注册ID 使用这个ID来判断当前这个后置处理有没有进行过postProcessBeanDefinitionRegistry方法和postProcessBeanFactory,如果已经执行过,就会抛出异常,也就是说这个Bean只执行一次,保证的注册的Bean的唯一性
int registryId = System.identityHashCode(registry);
// 保证postProcessBeanDefinitionRegistry方法还未执行
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
// 保证postProcessBeanFactory还未执行
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
- 进行配置类型Bean的处理
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取已经注册的Bean定义名称
String[] candidateNames = registry.getBeanDefinitionNames();
此时能获取到的Bean名称如下所示:前面5个是在容器创建的时候定义的。可以参考本人博客:https://blog.csdn.net/m0_37607945/article/details/106418334
第6个,是程序的主类,是在org.springframework.boot.SpringApplication#prepareContext方法中注册的,可以参考博客:https://blog.csdn.net/m0_37607945/article/details/106447591
1. CachingMetadataReaderFactoryPostProcessor
最后一个Bean呢?在Spring Boot的类Spring Application在run时,会进行prepareContext,然后执行ApplicationContextInitializer
接口的实现类,而这些实现类是在SpringApplication对象过程中通过SPI机制从spring.factories中加载并实例化的。通过调用applyInitializers(context)
方法对每个实现类执行initialize方法。源码如下
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
这些实现类中有一个为SharedMetadataReaderFactoryContextInitializer
,在执行这个类的initialize方法时会注入的一个BeanDefinitionRegistryPostProcessor
.也就是CachingMetadataReaderFactoryPostProcessor
.这个类也实现了BeanDefinitionRegistryPostProcessor
接口和PriorityOrdered
接口。也就是它注册了上面我们说的最后的那个bean,源码如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
register(registry);
configureConfigurationClassPostProcessor(registry);
}
private void register(BeanDefinitionRegistry registry) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryBean::new)
.getBeanDefinition();
registry.registerBeanDefinition(BEAN_NAME, definition);
}
并且order为Ordered.HIGHEST_PRECEDENCE。而ConfigurationClassPostProcessor
的order是Ordered.LOWEST_PRECEDENCE, 道理来说,这两个Bean定义在注册后置处理器列表中ConfigurationClassPostProcessor
应该在前面执行的。但是在看CachingMetadataReaderFactoryPostProcessor
源码时竟然有如下的注释:
那这是为什么呢?另外这个类也与ConfigurationClassPostProcessor
有一些关系(属性),如下所示:
public static final String BEAN_NAME = "org.springframework.boot.autoconfigure."
+ "internalCachingMetadataReaderFactory"
private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
try {
BeanDefinition definition = registry
.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
}
catch (NoSuchBeanDefinitionException ex) {
}
}
下面我们来分析ConfigurationClassPostProcessor
与CachingMetadataReaderFactoryPostProcessor
的执行先后问题。
在上面注册SharedMetadataReaderFactoryContextInitializer
注册的时候我们忽视了一点,再看一下源码
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
直接实例化并添加到容器中的一个属性列表中,
/** BeanFactoryPostProcessors to apply on refresh. */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
这个beanFactoryPostProcessors
列表是Spring容器的一个属性。那ConfigurationClassPostProcessor
呢?在构造容器时,进行注册,存放到beanDefinitionMap
中的。然后在执行invokeBeanFactoryPostProcessors
方法时首先处理beanFactoryPostProcessors
,然后才是从容器中查找。
所以说,这二者并不是通过Order来比较先后执行顺序的。
遍历上面返回的所有的beanNames,其实也就就是遍历目前容器中已经定义的Bean定义了
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
2. 判断是否为目标类checkConfigurationClassCandidate
判断FullConfiguration还是LiteConfiguration(目标是那些会引入bean定义的类),full类型就是注解@configuration
的类,而其他引入bean定义的方式(比如@Component
)的则为lite类型。Spring容器在判断一次之后,会设置为对应beandefinition
的属性值,这样下次就可以不用再才判断了(查找注解是通过反射来进行的,比较消耗资源)。所以下面的逻辑是首先判断对应beandefinition
中是不是有这个属性,如果不存在,才会去查找。(类似于缓存)
private static final String CONFIGURATION_CLASS_FULL = "full";
private static final String CONFIGURATION_CLASS_LITE = "lite";
private static final String CONFIGURATION_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
/**
* Determine whether the given bean definition indicates a full {@code @Configuration}
* class, through checking {@link #checkConfigurationClassCandidate}'s metadata marker.
*/
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
/**
* Determine whether the given bean definition indicates a lite {@code @Configuration}
* class, through checking {@link #checkConfigurationClassCandidate}'s metadata marker.
*/
public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
从ConfigurationClassPostProcessor中获取configurationClass属性值,看是否等于full或是lite。
/**
* Return an attribute name qualified by the given enclosing {@link Class}.
* For example the attribute name '{@code foo}' qualified by {@link Class}
* '{@code com.myapp.SomeClass}' would be '{@code com.myapp.SomeClass.foo}'
*/
public static String getQualifiedAttributeName(Class<?> enclosingClass, String attributeName) {
Assert.notNull(enclosingClass, "'enclosingClass' must not be null");
Assert.notNull(attributeName, "'attributeName' must not be null");
return enclosingClass.getName() + '.' + attributeName;
}
因此上面的属性名称应该是org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
,也就是说通过读取每一个上面获取到的bean定义,看看里面有没有定义这个属性,然后与full和lite进行比较。如果存在,则说明这个BeanDefinition已经被处理过了。
如果这些属性值为空,则检查当前bean定义是否是configuration
类以及full
或lite
类型。源码如下:
/**
* Check whether the given bean definition is a candidate for a configuration class
* (or a nested component class declared within a configuration/component class,
* to be auto-registered as well), and mark it accordingly.
* @param beanDef the bean definition to check
* @param metadataReaderFactory the current factory in use by the caller
* @return whether the candidate qualifies as (any kind of) configuration class
*/
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
- 如果是工厂方法定义的Bean则不处理
String className = beanDef.getBeanClassName();
// 1 工厂方法定义的Bean不是配置类
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
- 获取一个类的元数据,主要是通过
MetadataReaderFactory
来读取的
// 解析类定义的元数据
AnnotationMetadata metadata;
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
metadata = new StandardAnnotationMetadata(beanClass, true);
}
else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
- 根据元数据判断full或lite类型,如果是类上包含注解
@Configuration
则为full,如果是其他值(@Component、@ComponentScan、@Import、@ImportResource、
),或者有方法上包含@Bean
注解,都是lite,都是需要注册的类。
if (isFullConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (isLiteConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
判断full或lite类型
/**
* Check the given metadata for a full configuration class candidate
* (i.e. a class annotated with {@code @Configuration}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a full
* configuration class, including cross-method call interception
*/
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
private static final Set<String> candidateIndicators = new HashSet<>(8);
static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}
/**
* Check the given metadata for a lite configuration class candidate
* (e.g. a class annotated with {@code @Component} or just having
* {@code @Import} declarations or {@code @Bean methods}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a lite
* configuration class, just registering it and scanning it for {@code @Bean} methods
*/
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
try {
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
}
return false;
}
}
关于AttributeAccessorSupport
这个抽象类,几乎所有Bean定义类型都实现了这个抽象父类,方便设置bean的属性值。
4. 最后如果类上还有@Order
注解,则会在bean定义中添加属性org.springframework.context.annotation.ConfigurationClassPostProcessor.order
.
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
3. 针对目标集合排序
如果通过以上的方式判断出有full或者lite configuration的的class,首先会根据order进行排序
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
4. 判断是否有自定义的BeanName生成策略
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
5 ConfigurationClassParser解析并注册bean定义
主要涉及两个工具类:ConfigurationClassParser
和ConfigurationClassBeanDefinitionReader
。
前者将BeanDefinitionHolder
解析为Map<ConfigurationClass, ConfigurationClass>
,(此过程不会注册任何bean)
后者将ConfigurationClass
变成Set<Bedefinition>
(真正注册的地方)
- 通过
ConfigurationClassParser
解析然后存放到configurationClasses
Map属性当中,此过程不会注册任何bean,参考博客:ConfigurationClassParser解析@Configuration
类源码详解; - 进行验证,然后移除缓存中已经处理过的ConfigurationClass
- 通过
ConfigurationClassBeanDefinitionReader
加载configurationClasses
的bean定义(loadBeanDefinitions
),参考博客:@Configuration注册器ConfigurationClassBeanDefinitionReader,然后添加缓存 - 在目前已经注册过的所有bean中,找出尚未进行处理的
ConfigurationClass
类型的bean(一般情况不会有),重复以上步骤
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 获取所有已经注册的类名称
String[] newCandidateNames = registry.getBeanDefinitionNames();
// 在processConfigBeanDefinitions之前就已经存在的beanNames
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
// 已经处理过的ConfigurationClass
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
// 没有处理过的ConfigurationClass继续进行处理
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
通过该步骤,解析Java配置的bean定义并注册到容器当中
6. 注册额外bean以及清空元数据缓存
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
二 :对Configuration类进行增强操作(代理)
通过postProcessBeanDefinitionRegistry操作完成了bean定义的注册操作。
接下来需要针对部分bean进行增强操作。
这部分的逻辑是在postProcessBeanFactory
方法中实现的。执行时机在在处理完所有BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法之后。具体参考PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
方法。
/**
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 进行ConfigurationClasses的增强操作
enhanceConfigurationClasses(beanFactory);
// 添加一个bean后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
1. 进行ConfigurationClasses的增强操作
在BeanFactory中查找Configuration类型的bean定义
/**
* Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
* any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
* Candidate status is determined by BeanDefinition attribute metadata.
* @see ConfigurationClassEnhancer
*/
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
通过ConfigurationClassEnhancer进行增强
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
所谓的CGLIB增强,无非就是执行对应的回调方法,在ConfigurationClassEnhancer
中添加了三个Callback
实现类
// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
最后一个是空实现,前两个额外实现了另外两个接口MethodInterceptor
和ConditionalCallback
,分别对应回调方法和条件判断。
第一个用于处理加了@Scope
注解的@Bean
方法。
2. 添加ImportAwareBeanPostProcessor后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
通过以上增强之后,每个ConfigurationClass
(full mode)都是EnhancedConfiguration类型对象,因此在实例化的过程中都会被ImportAwareBeanPostProcessor进行后置处理,设置beanFactory。对应方法如下:
@Override
public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
// postProcessProperties method attempts to autowire other configuration beans.
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ImportAware) {
ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
AnnotationMetadata importingClass = ir.getImportingClassFor(bean.getClass().getSuperclass().getName());
if (importingClass != null) {
((ImportAware) bean).setImportMetadata(importingClass);
}
}
return bean;
}
之所以需要进行增强,主要是在通过java方法注册Bean的时候会存在依赖或者FactoryBean的情形,此时通过BeanMethodInterceptor
来进行拦截并相应处理,具体可以参考博客:
@Bean注册Bean,你有多了解?
总结
ConfigurationClassPostProcessor作为Spring中最重要的后置处理器,一点也不为过。
- 作为
BeanDefinitionRegistryPostProcessor
,在postProcessBeanDefinitionRegistry
方法中完成了解析(BeanDefinitionHolder
->ConfigurationClass
)和注册(ConfigurationClass
->BeanDefinition
)两个动作,这其中通过各种数据结构(LinkedHashSet、LinkedHashMap,甚至提供了DeferredImportSelector
接口),当然Spring或Spring Boot为了保证顺序性不只这些,还有@Order
、@AutoConfigureOrder
等。 - 作为
BeanFactoryPostProcessor
,在postProcessBeanFactory
方法中增对带有注解@Configuration
注解的bean进行了增强,为什么要进行增强,因为我们通常都是在这些类中去定义需要进行注册的Bean对象的,获取实例的方式就是去反射调用对应的方法,但是方法引用设置其他的bean,必须要保证单例,调用FactoryBean类型的时候,要返回getObject对象,这一块需要结合整个Spring来说才有意义了。