文章目录
-
- 一,ConfigurationClassPostProcessor简介
- 二,ConfigurationClassPostProcessor注入时机
-
- 1,注解方式的注入
- 2,XML方式的注入
- 三,postProcessBeanDefinitionRegistry()方法
-
- 1,第一步,筛选出被@Configuration注解标注的BeanDefinition
- 2,第二步,解析被@Configuration注解标注的BeanDefinition
- 3,第三步,将扫描到的所有beanDefinition注册到容器的BeanDefinitionMap中
- 4,第四步,判断第三步中注入到BeanDefinitionMap中BeanDefinition是否已经被解析过,如果没有被解析过,那么需要继续解析
- 四,postProcessBeanFactory()方法
- 五,总结
一,ConfigurationClassPostProcessor简介
ConfigurationClassPostProcessor
是一个后置处理器的类,主要功能是参与BeanFactory的建造,主要功能如下:
- 解析加了@Configuration的配置类
- 解析@ComponentScan扫描的包
- 解析@ComponentScans扫描的包
- 解析@Import注解
ConfigurationClassPostProcessor
类图:
ConfigurationClassPostProcessor
实现了 BeanDefinitionRegistryPostProcessor
接口,而 BeanDefinitionRegistryPostProcessor
接口继承了 BeanFactoryPostProcessor
接口,所以 ConfigurationClassPostProcessor
中需要重写 postProcessBeanDefinitionRegistry()
方法和 postProcessBeanFactory()
方法。
- postProcessBeanDefinitionRegistry()方法:定位、加载、解析、注册相关注解。
- postProcessBeanFactory()方法:添加CGLIB增强处理及ImportAwareBeanPostProcessor后置处理类。
二,ConfigurationClassPostProcessor注入时机
1,注解方式的注入
配置类SpringConfiguration.java
@Configuration
@ComponentScan(basePackages="com.bobo.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
启动类:
public class MyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
}
}
Spring源码会在创建AnnotationConfigApplicationContext
容器的时候,会去创建AnnotatedBeanDefinitionReader
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
在创建AnnotatedBeanDefinitionReader
的过程中会去注入注解相关的后置处理器:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// 注入注解相关的后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public abstract class AnnotationConfigUtils {
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 省略部分代码....
// 创建BeanDefinitionHolder集合
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 注册内部管理的用于处理@configuration注解的后置处理器的bean
// ConfigurationClassPostProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册内部管理的用于处理@Autowired,@Value,@Inject以及@Lookup注解的后置处理器bean
// AutowiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册内部管理的用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器bean
// CommonAnnotationBeanPostProcessor
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册内部管理的用于处理JPA注解的后置处理器bean
// PersistenceAnnotationBeanPostProcessor
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册内部管理的用于处理@EventListener注解的后置处理器的bean
// EventListenerMethodProcessor
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
// 注册内部管理用于生产ApplicationListener对象的EventListenerFactory对象
// DefaultEventListenerFactory
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
}
此处导入了五个后置处理器:
- ConfigurationClassPostProcessor:beanName为internalConfigurationAnnotationProcessor用于处理@configuration注解的后置处理器的bean
- AutowiredAnnotationBeanPostProcessor:beanName为internalAutowiredAnnotationProcessor用于处理@Autowired,@Value,@Inject以及@Lookup注解的后置处理器bean
- CommonAnnotationBeanPostProcessor:beanName为internalCommonAnnotationProcessor用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器bean
- EventListenerMethodProcessor:beanName为internalEventListenerProcessor用于处理@EventListener注解的后置处理器的bean
- DefaultEventListenerFactory:beanName为internalEventListenerFactory管理用于生产ApplicationListener对象的EventListenerFactory对象
2,XML方式的注入
boboTest.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.bobo.aop.annotation"/>
</beans>
测试类:
public class Test {
public static void main(String[] args) {
MyClassPathXmlApplicationContext ac = new MyClassPathXmlApplicationContext("boboTest.xml");
}
}
源码中document树在解析xml文件的时候,解析到context标签属于自定义标签,所以会走自定义标签的解析
public class BeanDefinitionParserDelegate {
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取对应的命名空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间找到对应的NamespaceHandlerspring
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 调用自定义的NamespaceHandler进行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
这里会获取到ComponentScanBeanDefinitionParser
解析器,然后会走到regsiterComponents()方法里面:
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
protected void registerComponents(
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
// 省略部分代码....
// Register annotation config processors, if necessary.
boolean annotationConfig = true;
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
// 获取component-scan标签的annotation-config属性值,默认为true
annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
}
if (annotationConfig) {
// 如果annotation-config属性值为true,在给定的注册表中注册所有用于注解的bean后置处理器
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
}
// 省略部分代码...
}
}
可以看到获取到component-scan
标签,默认会调用AnnotationConfigUtils.registerAnnotationConfigProcessors()
方法,进行对注解相关的后置处理器的注册,此方法上面已经分析过了!
三,postProcessBeanDefinitionRegistry()方法
很显然ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法的执行是在invokeBeanFactoryPostProcessors()方法中执行的,如果不了解invokeBeanFactoryPostProcessors()方法的执行流程的话,请移步去看上一篇文章:吃透Spring源码(十五):invokeBeanFactoryPostProcessors 执行流程
此方法主要完成对@Configuration
注解标注的BeanDefinition
解析,同时解析出 @ComponentScan 和 @ComponentScans 扫描出的Bean,也会解析出加了 @Bean 注解的方法所注册的Bean,以及通过 @Import 注解注册的Bean和 @ImportResource 注解导入的配置文件中配置的Bean。
下面我们直接到ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法中:
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
/**
* 定位、加载、解析、注册相关注解
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 根据对应的registry对象生成hashcode值,此对象只会操作一次,如果之前处理过则抛出异常
int registryId = System.identityHashCode(registry);
// 将马上要进行处理的registry对象的id值放到已经处理的集合对象中
this.registriesPostProcessed.add(registryId);
// 处理配置类的bean定义信息
processConfigBeanDefinitions(registry);
}
}
处理配置类的bean定义信息方法:
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
/**
* 构建和验证一个类是否被@Configuration修饰,并做相关的解析工作
* 如果你对此方法了解清楚了,那么springboot的自动装配原理就清楚了
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 创建存放BeanDefinitionHolder的对象集合
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 当前registry就是DefaultListableBeanFactory,获取所有已经注册的BeanDefinition的beanName
String[] candidateNames = registry.getBeanDefinitionNames();
//----------------第一步-----------------
// 遍历所有要处理的beanDefinition的名称,筛选对应的被注解修饰的beanDefinition
for (String beanName : candidateNames) {
// 获取指定名称的BeanDefinition对象
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断当前BeanDefinition是否是一个配置类,并为BeanDefinition设置属性为lite或者full,此处设置属性值是为了后续进行调用
// 如果Configuration配置proxyBeanMethods代理为true则为full
// 如果加了@Bean、@Component、@ComponentScan、@Import、@ImportResource注解,则设置为lite
// 如果配置类上被@Order注解标注,则设置BeanDefinition的order属性值
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 添加到对应的集合对象中
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//----------------第二步-----------------
// 存放相关的BeanDefinitionHolder对象
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 存放扫描包下的所有bean
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 解析带有@Controller、@Import、@ImportResource、@ComponentScan、@ComponentScans、@Bean的BeanDefinition
parser.parse(candidates);
// 将解析完的Configuration配置类进行校验,1、配置类不能是final,2、@Bean修饰的方法必须可以重写以支持CGLIB
parser.validate();
// 获取所有的bean,包括扫描的bean对象,@Import导入的bean对象
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 清除掉已经解析处理过的配置类
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
// 判断读取器是否为空,如果为空的话,就创建完全填充好的ConfigurationClass实例的读取器
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//----------------第三步-----------------
// 核心方法,将完全填充好的ConfigurationClass实例转化为BeanDefinition注册入IOC容器
this.reader.loadBeanDefinitions(configClasses);
// 添加到已经处理的集合中
alreadyParsed.addAll(configClasses);
candidates.clear();
//----------------第四步-----------------
// 这里判断registry.getBeanDefinitionCount() > candidateNames.length的目的是为了知道reader.loadBeanDefinitions(configClasses)这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
// 实际上就是看配置类(例如AppConfig类会向BeanDefinitionMap中添加bean)
// 如果有,registry.getBeanDefinitionCount()就会大于candidateNames.length
// 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了,如果未解析,需要重新进行解析
// 这里的AppConfig类向容器中添加的bean,实际上在parser.parse()这一步已经全部被解析了
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());
}
// 如果有未解析的类,则将其添加到candidates中,这样candidates不为空,就会进入到下一次的while的循环中
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());
}
}
1,第一步,筛选出被@Configuration注解标注的BeanDefinition
遍历容器中的BeanDefinitionNames
集合,找出来被@Configuration
标注的BeanDefinition
并加入到代处理集合configCandidates
中。
主要由ConfigurationClassUtils.checkConfigurationClassCandidate()
方法来完成:
abstract class ConfigurationClassUtils {
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// 获取bean定义信息中的class类名
String className = beanDef.getBeanClassName();
AnnotationMetadata metadata;
// 通过注解注入的db都是AnnotatedGenericBeanDefinition,实现了AnnotatedBeanDefinition
// spring内部的bd是RootBeanDefinition,实现了AbstractBeanDefinition
// 此处主要用于判断是否归属于AnnotatedBeanDefinition
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
// 从当前bean的定义信息中获取元数据信息
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
// 判断是否是spring中默认的BeanDefinition
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
// 如果class实例是下面四种类或接口的子类、父接口等任何一种情况,直接返回
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
// 为给定类创建新的AnnotationMetadata实例
metadata = AnnotationMetadata.introspect(beanClass);
}
// 如果上述两种情况都不符合
else {
try {
// 获取className的MetadataReader实例
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
// 读取底层类的完整注释元数据,包括带注解方法的元数据
metadata = metadataReader.getAnnotationMetadata();
}
}
// 获取bean定义的元数据被@Configuration注解标注的属性字典值
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 如果bean被@Configuration注解标注,且属性proxyBeanMethods为false(使用代理模式),则将bean定义记为full
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 如果bean被@configuration注解标注,且被注解@Component,@ComponentScan、@Import、@ImportResource或者@Bean标记的方法,则将bean定义标记为lite
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// bean定义是一个标记为full或lite的候选项,如果设置order则设置order属性值
Integer order = getOrder(metadata);
// 如果值不为空的话,那么直接设置值到具体的beanDefinition
if (order != null) {
// 设置bean定义的order值
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
}
以上主要完成:
判断当前BeanDefinition是否被@Configuration注解标注,如果是,并为BeanDefinition设置属性为lite或者full,此处设置属性值是为了后续进行调用。如果不是被@Configuration注解标注,直接返回false。
如果被@Configuration注解标注:
1、 配置proxyBeanMethods代理为true则为full;
2、 如果又被标注了@Bean、@Component、@ComponentScan、@Import、@ImportResource注解,则设置为lite;
3、 如果配置类上被@Order注解标注,则设置BeanDefinition的order属性值;
4、 返回true,则该beanDefinition会被加入到configCandidates集合中;
执行完第一步,我们的例子中只有SpringConfiguration是被@Configuration注解标注的,所以符合。
2,第二步,解析被@Configuration注解标注的BeanDefinition
解析被@Configuration注解标注的BeanDefinition且带有@Controller、@Import、@ImportResource、@ComponentScan、@ComponentScans、@Bean的BeanDefinition,获取所有的bean,包括扫描的bean对象,@Import导入的bean对象等放入configClasses集合里面。
主要是由ConfigurationClassParser#paser()方法来完成的
class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 循环遍历configCandidates
for (BeanDefinitionHolder holder : configCandidates) {
// 获取BeanDefinition
BeanDefinition bd = holder.getBeanDefinition();
// 根据BeanDefinition类型的不同,调用parse不同的重载方法,实际上最终都是调用processConfigurationClass()方法
try {
// 注解类型
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 {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
}
}
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 判断是否跳过解析,基于@Conditional标签判断该对象是否要跳过
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// SourceClass的意义:简单的包装类,目的是为了以统一的方式去处理带有注解的类,不管这些类是如何加载的
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
// 解析各种注解
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
// 将解析的配置类存储起来,这样回到parse方法时,能取到值
this.configurationClasses.put(configClass, configClass);
}
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// @Configuration继承了@Component
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 递归处理内部类,因为内部类也是一个配置类,配置类上有@configuration注解,该注解继承@Component,if判断为true,调用processMemberClasses方法,递归解析配置类中的内部类
processMemberClasses(configClass, sourceClass, filter);
}
// 如果配置类上加了@PropertySource注解,那么就解析加载properties文件,并将属性添加到spring上下文中
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
}
// 处理@ComponentScan或者@ComponentScans注解,并将扫描包下的所有bean转换成填充后的ConfigurationClass
// 此处就是将自定义的bean加载到IOC容器,因为扫描到的类可能也添加了@ComponentScan和@ComponentScans注解,因此需要进行递归解析
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
// 解析@ComponentScan和@ComponentScans配置的扫描的包所包含的类
// 比如 basePackages = com.bobo, 那么在这一步会扫描出这个包及子包下的class,然后将其解析成BeanDefinition
// (BeanDefinition可以理解为等价于BeanDefinitionHolder)
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 通过上一步扫描包com.bobo,有可能扫描出来的bean中可能也添加了ComponentScan或者ComponentScans注解.
//所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有ComponentScan和ComponentScans
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 判断是否是一个配置类,并设置full或lite属性
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 通过递归方法进行解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// 处理@ImportResource注解,导入spring的配置文件
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 处理加了@Bean注解的方法,将@Bean方法转化为BeanMethod对象,保存再集合中
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 处理接口的默认方法实现,从jdk8开始,接口中的方法可以有自己的默认实现,因此如果这个接口的方法加了@Bean注解,也需要被解析
processInterfaces(configClass, sourceClass);
// 解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
return null;
}
}
3,第三步,将扫描到的所有beanDefinition注册到容器的BeanDefinitionMap中
将第二步中扫描到的所有bean(在configClasses
中存放着),注入到容器的BeanDefinitionMap
中,完成导入bean的注入工作。
class ConfigurationClassBeanDefinitionReader {
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
// 循环调用loadBeanDefinitionsForConfigurationClass方法
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
/**
* 读取一个单独的ConfigurationClass类,注册bean本身(@Import引入的普通类)或者@Configuration配置类的Bean方法
*/
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 如果一个bean是通过@Import(ImportSelector)的方式添加到容器中的,那么此时configClass.isImported()返回的是true
// 而且configClass的importedBy属性里面存储的是ConfigurationClass就是将bean导入的类
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 判断当前的bean中是否含有@Bean注解的方法,如果有,需要把这些方法产生的bean放入到BeanDefinitionMap当中
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 将@ImportResource引入的资源注入IOC容器
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 如果bean上存在@Import注解,且import的是一个实现了ImportBeanDefinitionRegistrar接口,
//则执行ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
}
最终会注册到BeanDefinitionMap
中。
4,第四步,判断第三步中注入到BeanDefinitionMap中BeanDefinition是否已经被解析过,如果没有被解析过,那么需要继续解析
// 这里判断registry.getBeanDefinitionCount() > candidateNames.length的目的是为了知道reader.loadBeanDefinitions(configClasses)这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
// 如果有,registry.getBeanDefinitionCount()就会大于candidateNames.length
// 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了,如果未解析,需要重新进行解析
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());
}
// 如果有未解析的类,则将其添加到candidates中,这样candidates不为空,就会进入到下一次的while的循环中
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;
}
这里判断registry.getBeanDefinitionCount() > candidateNames.length的目的是为了知道reader.loadBeanDefinitions(configClasses)这一步有没有向BeanDefinitionMap中添加新的BeanDefinition,如果有,registry.getBeanDefinitionCount()就会大于candidateNames.length,这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了,如果未解析,需要重新进行解析。
四,postProcessBeanFactory()方法
当然ConfigurationClassPostProcessor#postProcessBeanFactory()方法的执行也是在invokeBeanFactoryPostProcessors()方法中执行的,如果不了解invokeBeanFactoryPostProcessors()方法的执行流程的话,请移步去看上一篇文章:吃透Spring源码(十五):invokeBeanFactoryPostProcessors 执行流程
此方法主要是对被@Configuration
注解标注的类添加CGLIB增强处理以及添加ImportAwareBeanPostProcessor
后置处理。
下面我们直接到ConfigurationClassPostProcessor#postProcessBeanFactory()方法中:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
// 如果还没执行解析工作,则先去执行processConfigBeanDefinitions进行解析
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 对当前容器中被@Configuration注解标注的BeanDefinition进行CGLIb增强
enhanceConfigurationClasses(beanFactory);
// 添加ImportAwareBeanPostProcessor后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
为什么要对被@Configuration
注解标注的类添加CGLIB增强?
解释这个问题我们先来看一段代码:
@Configuration
public class SpringConfiguration {
@Bean
public A a() {
return new A();
}
@Bean
public B b() {
a();
return new B();
}
}
配置类中有两个方法,a()方法返回对象A,b()方法调用一下a()方法,在返回对象B,并且都被@Bean注解修饰。
SpringConfiguration配置类,在被Spring容器去创建B对象的时候,此时A对象已经创建,那么调用a()方法会再去创建A对象,所以无法保证Bean对象的单例性。
凡是加了@Configuration注解修饰的类都会被spring代理,目的是为了解决@Bean单例问题
五,总结
- ConfigurationClassPostProcessor类是用来对@Configuration注解标注的BeanDefinition来处理的。
- postProcessBeanDefinitionRegistry()方法是解析@Configuration注解标注的BeanDefinition,同时解析出 @ComponentScan 和 @ComponentScans 扫描出的Bean,也会解析出加了 @Bean 注解的方法所注册的Bean,以及通过 @Import 注解注册的Bean和 @ImportResource 注解导入的配置文件中配置的Bean
- postProcessBeanFactory()方法,对加了@Configuration注解修饰的类都会被spring代理,目的是为了解决@Bean单例问题。