ConfigurationClassPostProcessor是Spring Framework中的一个bean工厂后置处理器,而且还是一个registry后置处理器,Spring Framework和Spring Boot中的很多功能都是由该类来实现的,可以说该类十分强大。本文就来分析一下该类都做了哪些操作,以及是怎么做的。
registry后置操作
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
// 检查重复处理
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
// 保证不被二次处理
this.registriesPostProcessed.add(registryId);
// 处理配置
processConfigBeanDefinitions(registry);
}
主要的实现在processConfigBeanDefinitions方法中。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取bean工厂中的所有bean
String[] candidateNames = registry.getBeanDefinitionNames();
/*
* 遍历每一个bean
*/
for (String beanName : candidateNames) {
// 获取bean定义
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
/*
* 判断beanDef对应的class是否被@Configuration修饰,如果是并判断和设置配置的模式(full还是lite)
* 如果被@Configuration注解修饰,那么proxyTargetClass属性为true的话则是full模式,否则是lite模式
* 如果不是被@Configuration修饰(只能是lite模式),
* 那么再判断是否是其他情况,参考ConfigurationClassUtils#isConfigurationCandidate()方法。
* 所以这里可以看出,不是只有@Configuration的才是配置类。
*/
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 如果满足配置类的要求,那么加入到候选者集合中
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
// 如果没有配置类,那么直接返回
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
// 对配置类根据@Order进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 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,则加载默认的
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
// 创建解析配置类的解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 表示每次循环需要处理的配置类
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 记录已经解析过的的配置类,也就是执行过this.reader.loadBeanDefinitions方法的bean。
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
/*
* 核心处理逻辑
* 会解析其内部的注解,包括@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean
* 每个被@Configuration修饰的类都会生成一个ConfigurationClass
*/
parser.parse(candidates);
/*
* 校验配置类
* 如类不能被final修饰,@Bean标注的方法不能被private修饰
*/
parser.validate();
// 获取所有生成的ConfigurationClass,包含了之前处理过的,所以下面要移除掉
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 移除掉已经被处理过的配置类
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
/*
* 创建ConfigurationClassBeanDefinitionReader对象,用于扫描出ConfigurationClass中的BeanDefinition
*/
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
/*
* 加载ConfigurationClass中的beanDefinition并注册,主要有以下来源:
* @Import导入对象,该注解可导入下面四种类:(这一点好像有问题)
* 1、被@Configuration修饰的类;
* 2、实现了ImportSelector接口的类;
* 3、实现了ImportBeanDefinitionRegistrar接口的类;
* 4、其他普通component类
* @Configuration修饰的类中被@Bean注解修饰的方法
* @ImportSource注解导入的资源中配置的类
*
*
*/
this.reader.loadBeanDefinitions(configClasses);
// 添加到已经解析过的列表中,避免后续重复解析
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
// 清空列表,准备下一轮循环
candidates.clear();
// 前后数量不等,说明确实load到了bean
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 获取bean工厂中的所有bean的名称
String[] newCandidateNames = registry.getBeanDefinitionNames();
// 本次循环前的bean名称集合
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
// 已经处理过的配置类的类名集合
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
// 第一次筛选:筛选出本次do...while循环新加载到的bean,即不在旧列表中的bean
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
/*
* 第二次筛选:
* 如果又新加载进来了配置类,且不是之前已经处理过的(其实循环开头也是会remove掉已经处理过的配置类),
* 那么将其加入到candidates再次循环处理
*/
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// 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();
}
}
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());
}
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
// 存在factory-method的情况不算是配置类
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
// 获取目标类的元数据
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();
// 如果类属于下面几种,则不属于是配置类
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
// 根据Class来构建元数据
metadata = AnnotationMetadata.introspect(beanClass);
}
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;
}
}
// 如果存在@Configuration注解,那么获取注解内的proxyBeanMethods属性,并据此设置配置的模式(full还是lite)
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 如果存在@Configuration注解,且proxyBeanMethods属性为true,那么是FULL模式
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 如果没有@Configuration注解,但是类满足几点要求也算是配置类(具体是什么要求点进去看),不过是LITE模式
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
// 获取配置类的顺序,也就是类上@Order注解的value值
Integer order = getOrder(metadata);
if (order != null) {
// 设置顺序
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
这个方法非常长,但逻辑还是很清楚的。 首先获取当前bean工厂中的所有配置类,然后以该获取结果作为遍历的起点,在do...while循环中调用ConfigurationClassParser和ConfigurationClassBeanDefinitionReader来处理。前者主要是扫描配置类中的bean和其他配置类,后者主要是注册扫描到的bean。如果加载到有bean,那么筛选出新加载到的配置类,然后以此作为遍历对象再次循环处理。这个过程属于广度优先遍历(BFS)。 其实核心的实现在那两个类里面,请参考:
普通后置操作
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
// 判断是否已经处理过这个bean工厂了
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
// 判断有没有处理过配置类,其实在上面的postProcessBeanDefinitionRegistry方法中就已经处理过了,所以这里可以忽略
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
// 处理配置bean的定义
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// CGLIB提升
enhanceConfigurationClasses(beanFactory);
// 注册bean后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
主要的实现都在enhanceConfigurationClasses这个方法中。
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
// 遍历所有的bean名称
for (String beanName : beanFactory.getBeanDefinitionNames()) {
// 获取bean定义
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
/*
* 获取配置类的属性,该属性是在ConfigurationClassUtils的checkConfigurationClassCandidate方法中设置的,
* 有full和lite两种值。
*/
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
AnnotationMetadata annotationMetadata = null;
MethodMetadata methodMetadata = null;
// 获取元数据
if (beanDef instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
annotationMetadata = annotatedBeanDefinition.getMetadata();
methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
// or component class without @Bean methods.
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
// 如果bean的class不是属于java.lang.Class的子类型
if (!abd.hasBeanClass()) {
boolean liteConfigurationCandidateWithoutBeanMethods =
// 如果是lite模式
(ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
annotationMetadata != null &&
// 不含有bean方法
!ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
// 不是lite模式,或者含有bean方法
if (!liteConfigurationCandidateWithoutBeanMethods) {
try {
// 解析bean的class
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
}
// 如果是full模式
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
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)) {
}
// 将bean定义添加到集合中,便于下面统一处理
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
// 没有需要进行CGLIB提升的配置类,则直接返回
if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
// nothing to enhance -> return immediately
enhanceConfigClasses.end();
return;
}
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
// 遍历属于full模式的配置bean的定义
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
// 获取bean定义
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
// 获取配置类的Class对象
Class<?> configClass = beanDef.getBeanClass();
// 通过CGLIB创建一个配置类的子类
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
// 替换bean定义中的bean的类为CGLIB创建的子类
beanDef.setBeanClass(enhancedClass);
}
}
enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
}
这个方法筛选了所有模式为full的配置bean,什么样才算是full模式呢,具体参考上面给出的checkConfigurationClassCandidate方法的代码,在其尾部判断了类是否被@Configuration注解所修饰,且proxyBeanMethods属性是否是true,如果都是则认为是full模式,否则是lite模式。 然后对所有的full模式的配置类,利用CGLIB来生成代理类。full模式的配置类中的bean方法多次调用返回的是同一个对象,就是因为这里进行代理增强。
总结
本文分析了ConfigurationClassPostProcessor,可以说该类是官方提供的最重要和最强大的一个BeanFactoryPostProcessor都不为过,在该类中实现了大量Spring框架提供的功能。核心实现单独抽离到了单独的两篇文章中,这样显得本文的主题更为清晰。