目录
postProcessBeanDefinitionRegistry
种子类
也称配置类
在上一章AnnotationConfigApplicationContext容器介绍中提到,该容器提供两个成员变量对beanDefinition进行注册。
1、scanner: ClassPathBeanDefinitionScanner。扫描指定报下的class文件, 如果被component注解且是top level类,则注册。
2、reader: AnnotatedBeanDefinitionReader。注册指定的class文件。
这个容器看似太简单了,但其实基于注解的bean定义的主要部分并在在此容器的加载阶段完成。AnnotationConfigApplicationContext只是注册的bean只能被认为是一个 “种子类”,后面会针对这个“种子类”上的各种注解进行生根发芽,生成其他注解方式生成的BeanDefinition。
这个 “生根发芽” 的工作就是ConfigurationClassPostProcessor,完成的。ConfigurationClassPostProcessor实现了beanFactoryPostProcessor。它会在refresh()的invokeBeanFactoryPostProcessors阶段,完成“生根发芽”。
什么时候被定义
ConfigurationClassPostProcessor的bean定义什么以后加入到容器的?
1、AnnotatedBeanDefinitionReader的构造函数种会调AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
2、ClassPathBeanDefinitionScanner#scan种也会调用AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
3、在xml模式下如果配置<context:annotation-config/>,会通过其NameSpaceHandler解析并注册
实现的两个方法
postProcessBeanDefinitionRegistry:负责"生根发芽"。生成更多的beanDefinition。
postProcessBeanFactory: 在某些情况它会对被Configuration注解的类进行代理增强。
源码介绍:
postProcessBeanDefinitionRegistry
生根发芽
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 对加入进来的registry生成一个唯一Id, 说明它可以针对多个容器进行处理。
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);
}
// 记录已经处理过的registry
this.registriesPostProcessed.add(registryId);
// 开始"生根发芽"
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//第一步:寻找第一波种子
// 拿到所有bean定义的beanName作为候选name
String[] candidateNames = registry.getBeanDefinitionNames();
// 循环处理
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断这个BeanDefinition是不是全量配置, 或者是轻量配置
// 第一次进来,不会有这个标记的。
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 通过对类的AnnotationMetadata进行判断,是不是一个配置候选类,
// 并且这里判断之后, 会在BeanDefinition上打标记
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
如果是则加入configCandidates
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果没有配置类则返回
if (configCandidates.isEmpty()) {
return;
}
// 排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 获取一个bean名称的生成器
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();
}
// 生成一个配置类的解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 生成一个已解析的列表, 因为下面要进入一个循环体, 要记录那些已经被解析的ConfigurationClass
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
//第二步:从第一波种子开始进行生根发芽
do {
// 调用parser解析 candidates 是作为本次解析的配置类集合,理解为本次的 "种子"
parser.parse(candidates);
parser.validate();
// configClasses是经过本次生根发芽后的总的配置类集合 = "种子" + "种子生成的类"
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 剔除 已经被解析过的ConfigurationClass
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());
}
// 第三步: 将解析出来的configClasses进行注册。
this.reader.loadBeanDefinitions(configClasses);
// 同时将configClasses 加入到 alreadyParsed, 标记为已经处理过了
alreadyParsed.addAll(configClasses);
// 再将candidates进行清理
candidates.clear();
// 第四步 寻找下一波种子再次进行解析和注册
// 这个方法体的主要作用是判断本次生成的BeanDefinition, 有没有新的配置类,
// 如果有则加入candidates作为"种子", 进入下一次循环
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
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) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
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();
}
}
全量配置类和轻量配置类
ConfigurationClassUtils#checkConfigurationClassCandidate:通过对类的AnnotationMetadata进行判断,是不是一个配置候选类, 配置类分为:
全量配置类: 被Configuration注解的类
轻量配置类: 是否被Componet、ComponentScan、Import、ImportResource注解,或存在方法有Bean注解
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
// 尝试获得一个AnnotationMetadata
AnnotationMetadata metadata;
// 如果beanDef 实现了AnnotatedBeanDefinition 那么可以直接getMetadata
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
// 如果beanDef实现了AbstractBeanDefinition, 则获取它的class, new 出一个StandardAnnotationMetadata
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 {
// 最后尝试 通过SimpleMetadataReader 获取一个metadata,
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
// 其实是AnnotationMetadataReadingVisitor
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
}
return false;
}
}
// 判断metadata封装的类是否是一个全量配置, 就是判断是否配Configuration注解: metadata.isAnnotated(Configuration.class.getName())
if (isFullConfigurationCandidate(metadata)) {
// 那么则在bean定义种打上"全量配置"标记
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 判断metadata封装的类是否是一个轻量配置, 是否被Componet、ComponentScan、Import、ImportResource注解
// 或者存在方法上有Bean注解
else if (isLiteConfigurationCandidate(metadata)) {
// 那么则在bean定义上打上"轻量配置"标记
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.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
全量配置类:
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
轻量配置类:
ConfigurationClassParser
ConfigurationClassParser#parse(java.util.Set<BeanDefinitionHolder>)
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 传入Metadata进行解析
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
// 传入Class进行解析
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
// 传入className进行解析
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
这三种parse其实都是针对ConfigurationClass 的 metatada进行解析
如果是传入className,则将className作为资源,使用MetadataReader获取它的AnnotationMetadata
如果传入class,则将其封装成StandardAnnotationMetadata
如果传入metadata,则直接使用这个metadata
protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
public ConfigurationClass(MetadataReader metadataReader, String beanName) {
// 则将className作为资源,使用MetadataReader获取它的AnnotationMetadata
Assert.notNull(beanName, "Bean name must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
this.beanName = beanName;
}
public ConfigurationClass(Class<?> clazz, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
// 如果传入class,则将其封装成StandardAnnotationMetadata
this.metadata = new StandardAnnotationMetadata(clazz, true);
this.resource = new DescriptiveResource(clazz.getName());
this.beanName = beanName;
}
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
// 如果传入metadata,则直接使用这个metadata
this.metadata = metadata;
this.resource = new DescriptiveResource(metadata.getClassName());
this.beanName = beanName;
}
processConfigurationClass:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 先从缓存种判断一下
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 将configClass转换为SourceClass, SourceClass是在ConfigurationClass上的包装, 它多了一些方法,比如可以拿到其memberClasses
SourceClass sourceClass = asSourceClass(configClass);
do {
// 最后将configClass和sourceClass都传入进行处理, 并返回sourceClass的一个超类
// 知道其超类都没有了, 才停止处理
// 这里有很多递归过程, 有可能这个类可能会有超类, 有嵌套类和内部类等
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
// 将configClass加入缓存
this.configurationClasses.put(configClass, configClass);
}
然后调用 doProcessConfigurationClass,解析内部类和嵌套类,被Spring的各种注解注解的类,以及它的超类。
具体查看《ConfigurationClassPostProcessor使用案例》
postProcessBeanFactory
如果我们的种子类配置了Configuration注解,就会被认为是全量的配置类,Spring会对这个类进行一次增强。其增强动作就是在postProcessBeanFactory中完成的。
案例
/**
* 如果 “种子”注解了{@link Configuration} 则会调用
* {@link ConfigurationClassPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)}
* ==》{@link ConfigurationClassPostProcessor#enhanceConfigurationClasses(ConfigurableListableBeanFactory)}
* 对进行增强保证 单例
* 案例中的EnhanceRegisterBeanMethodTest 并没有实现{@link org.springframework.beans.factory.FactoryBean} 接口,不是简单工厂模式,而是工厂方法模式
* @author : 江鹏亮
* @date : 2020-06-17 21:57
**/
//@Configuration
public class EnhanceRegisterBeanMethodTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EnhanceRegisterBeanMethodTest.class);
Person person1 = context.getBean(Person.class);
// 获取factoryBean
EnhanceRegisterBeanMethodTest enhanceRegisterBeanMethodTest = context.getBean(EnhanceRegisterBeanMethodTest.class);
System.out.println("enhanceRegisterBeanMethodTest = " + enhanceRegisterBeanMethodTest.getClass().getSimpleName());
// 调用工厂方法再次调用person方法。
Person person2 = enhanceRegisterBeanMethodTest.person();
// 看看person1 和 person2 是否相等
if (person1 == person2) {
System.out.println("person1 == person2");
} else {
System.out.println("person1 != person2");
}
}
@Bean
public Person person() {
System.out.println("Person 的 构造函数被调用");
return new Person();
}
}
结果:
当不被@Configuration注解时,调用工厂再次获取bean时,会触发bean的构造,这符合我们的预期,但不符合我们对单例的要求。
如何解决?加上@Configuration注解
/**
* 如果 “种子”注解了{@link Configuration} 则会调用
* {@link ConfigurationClassPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)}
* ==》{@link ConfigurationClassPostProcessor#enhanceConfigurationClasses(ConfigurableListableBeanFactory)}
* 对进行增强保证 单例
* 案例中的EnhanceRegisterBeanMethodTest 并没有实现{@link org.springframework.beans.factory.FactoryBean} 接口,不是简单工厂模式,而是工厂方法模式
* @author : 江鹏亮
* @date : 2020-06-17 21:57
**/
@Configuration
public class EnhanceRegisterBeanMethodTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EnhanceRegisterBeanMethodTest.class);
Person person1 = context.getBean(Person.class);
// 获取factoryBean
EnhanceRegisterBeanMethodTest enhanceRegisterBeanMethodTest = context.getBean(EnhanceRegisterBeanMethodTest.class);
System.out.println("enhanceRegisterBeanMethodTest = " + enhanceRegisterBeanMethodTest.getClass().getSimpleName());
// 调用工厂方法再次调用person方法。
Person person2 = enhanceRegisterBeanMethodTest.person();
// 看看person1 和 person2 是否相等
if (person1 == person2) {
System.out.println("person1 == person2");
} else {
System.out.println("person1 != person2");
}
}
@Bean
public Person person() {
System.out.println("Person 的 构造函数被调用");
return new Person();
}
}
结果:
加上@Configuration后,Spring会对原来的工厂进行一次代理增强,再次调用工厂方法获取bean时,获取的是容器中cache中的bean。
Spring对全量配置类的增强
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);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
过滤全量配置类并使用ConfigurationClassEnhancer 对其进行增强。ConfigurationClassEnhancer代理用的是CGLib。在《ConfigurationClassEnhancer》中介绍CGLib并对ConfigurationClassEnhancer为案例进行解释。
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
// 过滤全量配置类加入到configBeanDefs中
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.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
logger.warn("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;
}
// new 一个ConfigurationClassEnhancer用于增强
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
// 遍历每个configBeanDefs,对其增强
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.isDebugEnabled()) {
logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
// 设置BeanClass为增强后的类
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}