1. 前言
在上一篇《Spring源码系列一:Spring容器启动流程》中,我们了解到在ApplicationContext的refresh()(初始化)阶段的PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())步骤中,完成的BeanDefinition的扫描、解析、注册工作,是通过如下四件件事情完成的:
1.实例化实现了BeanDefinitionRegistryPostProcessor接口的Bean;
2.调用实现了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法;
3.实例化实现了BeanFactoryPostProcessor接口的Bean;
4.调用实现了BeanFactoryPostProcessor的postProcessBeanFactory()方法。
这个步骤中,涉及到Spring的一个核心类「ConfigurationClassPostProcessor」,该类在AnnotationConfigApplicationContext实例化阶段的设置AnnotatedBeanDefinitionReader步骤中已经完成了添加,其UML类图如下所示:
其中,
接口Aware的相关实现主要用于Spring容器给当前Processor设置一些诸如Environment等相关的信息;
接口Ordered的相关实现用于配置及获取当前Processor的执行优先级;
接口BeanFactoryPostProcessor给当前Processor提供了对BeanFactory修改的入口;
接口BeanDefinitionRegistryPostProcessor给当前Processor提供了注册BeanDefinition的入口。
因此,「ConfigurationClassPostProcessor的核心为对接口BeanFactoryPostProcessor及接口BeanDefinitionRegistryPostProcessor的方法的实现」,对应实现方法的核心执行流程如下所示:
接下来将按步骤分析涉及到的内容。
2. 分析
以下内容均基于Spring5.3.37版本进行分析。
2.1 ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
当前方法主要通过调用内部方法processConfigBeanDefinitions(BeanDefinitionRegistry registry)完成了BeanDefinition的扫描、创建、注册,因此重点分析processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法的执行流程及关联的类和方法。
2.1.1 processConfigBeanDefinitions(BeanDefinitionRegistry registry)
此方法的核心执行步骤如下:
1.从DefaultListableBeanFactory的属性beanDefinitionNames中取得BeanDefinitionName集合,此时能用于后续解析的集合的值来源于创建容器后调用AnnotationConfigApplicationContext.register(Class<?>... componentClasses)传入解析的配置类;
2.循环BeanDefinitionName集合,通过BeanName的到BeanDefinition,调用ConfigurationClassUtils.checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory)判断是否为配置类候选者,得配置类候选者的BeanDefinition集合;
6.判断BeanDefinitionRegistry中BeanDefintion的数量是不是大于传入解析的配置类候选者BeanDefintion个数,是则将新解析得到配置类候选者BeanDefinition集合,循环步骤4、5、6,直至全部解析、扫描、创建、注册完毕。
步骤中涉及的核心类及方法如下。
2.1.1.1 ConfigurationClassUtils.checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory)
此方法用于判断当前传入的BeanDefintion是否为配置类候选者,主要干了两件事情:
1.判断是否为配置类候选者,判断条件:
①BeanDefintion的属性beanClass不为空或属性factoryMethodName不为空,且非BeanFactoryPostProcessor、BeanPostProcessor、AopInfrastructureBean、EventListenerFactory的实现类;
②BeanDefinition对应类上有@Configuration注解,或类上有@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解。
以上两条件为且的关系,缺一不可。
2.给配置类候选者设置configurationClass属性值。
如果配置类候选者上有@Configuration注解,且注解的属性proxyBeanMethods为true(默认为true),则给当前BeanDefintion设置属性configurationClass,值为full,如果配置类候选者上有@Configuration注解但proxyBeanMethods为false,或者配置类候选者上有@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解,,则给当前BeanDefintion设置属性configurationClass,值为lite。
3.给配置类候选者设置order属性
通过获取配置类候选者上的@Order注解配置的值,为配置类候选者设置属性order,值为@Order注解上配置的值;若无@Order注解则设置为空。
核心源码如下:
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// 没有className或没有factoryMethodName,非配置类候选者,则直接返回false,
String className = beanDef.getBeanClassName();
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();
// 如果是以下PostProcessor的实现类,非配置类候选者,则直接返回false,
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
// 省略部分源码...
}
// 类上有@Configuration注解,且该注解的proxyBeanMethods属性为true
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
// 则给BeanDefintion设置属性configurationClass,值为full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 类上有@Configuration注解,且该注解的proxyBeanMethods属性为false
// 或类上有@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解
else if (config != null || isConfigurationCandidate(metadata)) {
// 则给BeanDefintion设置属性configurationClass,值为lite
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属性
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
2.1.1.2 ConfigurationClassParser.parse(SetconfigCandidates)
此方法用于解析配置类候选者BeanDefintion,类上有@Configuration、@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解是ConfigurationClass,得到ConfigurationClass集合,存放在属性configurationClasses中,供后续扫描创建新的BeanDefintion。内部调用processConfigurationClass(ConfigurationClass configClass, Predicate filter)方法进行解析。
2.1.1.2.1 processConfigurationClass(ConfigurationClass configClass, Predicate filter)
该方法的执行步骤如下:
1.判断是否需要跳过解析,通过调用ConditionEvaluator.shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase)方法,取得类上@Conditional注解进行判断,不符合预定的条件则跳过不解析;
2.判断当前ConfigurationClass是否已解析过,如果已经解析过,且是通过@Import注解或者通过嵌套在其他配置类中自动注册而来,则跳过;否则再次进行解析,用新的解析结果覆盖旧的解析结果;
3.创建SourceClass,入参为Class,如果类的类名是以java.lang.annotation.或org.springframework.stereotype.开头,则为Object.class;若类名以java开头,则使用ClassUtils.forName(String name, ClassLoader classLoader)方法获得类的Class;否则利用ASM技术得到Class;
4.通过do-while循环调用doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)方法,递归解析ConfigurationClass;
5.将已解析的ConfigurationClass添加到ConfigurationClassParser的属性configurationClasses中。
核心源码如下:
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 通过解析@Conditional注解判断是否需要跳过
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 如果当前配置类已经解析过,且是通过@Import注解或者通过嵌套在其他配置类中自动注册而来,进行importedBy属性合并,然后跳过;否则再次进行解析,用新的解析结果覆盖旧的解析结果;
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
// 如果当前配置类和已存在的配置类都是通过@Import注解或者通过嵌套在其他配置类来的,则合并importedBy属性
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.
// 移除原ConfigurationClass
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
// 循环解析SourceClass,直到所有配置类均被处理完成
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
// 将处理完成的配置类放到configurationClasses属性中
this.configurationClasses.put(configClass, configClass);
}
2.1.1.2.2 doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
执行流程如下:
1.处理带@Component注解;
通过调用processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,Predicate filter)方法,解析当前配置类内部声明的内部类、内部接口,将所有符合ConfigurationClassUtils.isConfigurationCandidate(AnnotationMetadata metadata)检查条件的内部类/接口作为配置类候选者集合,并将集合排序后,再次调用processConfigurationClass(ConfigurationClass configClass, Predicate filter)方法进行解析;
2.处理带@PropertySources注解;
解析@PropertySources注解,将解析的结果存放到AbstractEnvironment属性propertySources中,属性propertySources的类型为MutablePropertySources,内部维护了一个List<PropertySource<?>>集合。 「如果重复解析到了名称一样的PropertySource,将会用新的覆盖旧的」。
3.处理@ComponentScans、@ComponentScan注解;
①循环解析配置类上的@ComponentScans、@ComponentScan注解;
②通过调用ComponentScanAnnotationParser的parse(AnnotationAttributes componentScan, String declaringClass)方法,解析注解的属性,得到包扫描路径,parse()内部再调用ClassPathBeanDefinitionScanner的doScan(String... basePackages)得到路径下所有的BeanDefiniton;
③循环将新得到的BeanDefinition集合,通过ConfigurationClassUtils.checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory)判断是否为配置类候选者,若是则接着调用ConfigurationClassParser的parse(String className, String beanName)方法,递归解析。
4.处理@Import注解;
processImports(configClass, sourceClass, getImports(sourceClass), filter, true)
调用getImports(SourceClass sourceClass)方法递归获得配置类上涉及的@Import注解得到SourceClass集合,作为processImports()方法的入参
该方法内部执行步骤:
①循环解析@Import注解得到的SourceClass集合;
②如果SourceClass的源类实现了ImportSelector接口,则调用实现自该接口的selectImports(AnnotationMetadata importingClassMetadata)方法取得类名称集合,将类名称集合转换成SourceClass集合,递归调用processImports()方法继续解析;
③如果SourceClass的源类实现了ImportBeanDefinitionRegistrar接口,则获得ImportBeanDefinitionRegistrar实例,添加到当前的ConfigurationClass的属性importBeanDefinitionRegistrars中;
④若不满足以上两个情况,则继续调用processConfigurationClass(ConfigurationClass configClass, Predicate filter)方法进行解析。
5.处理@ImportResource注解;
解析@ImportResource注解上属性locations对应的配置文件信息。
6.处理@Bean注解标记的方法;
通过ASM技术,得到SourceClass源类上@Bean标记的方法集合,将其构建成BeanMethod添加到ConfigurationClass的属性beanMethods中。
7.处理配置类实现的接口中的默认方法;
取得SourceClass源类实现的接口,通过ASM技术,得到接口中有@Bean标记的方法集合,剔除掉abstract修饰的方法后,将剩余的构建成BeanMethod添加到ConfigurationClass的属性beanMethods中,然后递归调用processInterfaces()方法,解析当前接口实现的父接口。
8.处理配置类继承的父类。
取得SourceClass源类继承的父类作为SourceClass,递归doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)方法进行解析。
整体核心源码如下:
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// 对有@Component注解标记的类进行其内部类、内部接口的解析
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
// 解析@PropertySources注解,将解析的结果存放到AbstractEnvironment属性propertySources中,
// 属性propertySources的类型为MutablePropertySources,内部维护了一个List<PropertySource<?>>集合。
// 如果重复解析到了名称一样的PropertySource,将会用新的覆盖旧的。
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
// 处理@Component注解
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
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
// 处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
// 处理@ImportResource注解
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);
}
}
// Process individual @Bean methods
// 处理@Bean标记的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
// 处理配置类上实现的接口中的默认方法
processInterfaces(configClass, sourceClass);
// Process superclass, if any
// 取得配置类上的父类,再次执行整个doProcessConfigurationClass解析方法
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();
}
}
// No superclass -> processing is complete
return null;
}
2.1.1.3 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set configurationModel)
该方法解析通过2.1.1.2节中得到的ConfigurationClass,得到BeanDefinition,并添加到DefaultListableBeanFactory的属性beanDefinitionMap中完成注册。核心步骤如下:
1.将ConfigurationClass属性importedBy中的ConfigurationClass进行BeanDefinition创建、注册;
2.将ConfigurationClass属性beanMethods中的BeanMethod进行BeanDefinition创建、注册;
3.将ConfigurationClass属性importedResources中BeanDefinitionReader取出构建成对应对象,执行loadBeanDefinitions(String location)方法得到BeanDefinition,然后完成注册;
4.将ConfigurationClass属性将importBeanDefinitionRegistrars中ImportBeanDefinitionRegistrar取出,执行ImportBeanDefinitionRegistrar的registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,BeanNameGenerator importBeanNameGenerator)方法进行用户自定义扩展BeanDefinition创建及注册逻辑。
核心源码如下:
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 通过解析@Conditional注解判断是否需要跳过
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 将ConfigurationClass属性importedBy中的ConfigurationClass进行BeanDefinition创建、注册
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 将ConfigurationClass属性beanMethods中的BeanMethod进行BeanDefinition创建、注册,BeanMethod来源于被@Bean方法标记的方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 将ConfigurationClass属性importedResources中BeanDefinitionReader取出构建成对应对象,执行loadBeanDefinitions(String location)方法得到BeanDefinition,然后完成注册
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 将ConfigurationClass属性将importBeanDefinitionRegistrars中ImportBeanDefinitionRegistrar取出,
// 执行ImportBeanDefinitionRegistrar的registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,BeanNameGenerator importBeanNameGenerator)方法
// 进行用户自定义扩展BeanDefinition创建及注册逻辑
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
2.2 ConfigurationClassPostProcessor.postProcessBeanFactory() 该方法用于对BeanFactory创建过程的进行处理,核心内容为:
1.对有@Configuration注解,且注解属性proxyBeanMethods为true(默认为true)的类通过CGLIB的生成其代理类;
2.向ApplicationContext中添加ImportAwareBeanPostProcessor后置处理器。
2.2.1 ConfigurationClassEnhancer.enhance(Class<?> configClass, @Nullable ClassLoader classLoader)
该方法为BeanDefinition属性configurationClass的值full的源类,通过ConfigurationClassEnhancer的enhance(Class<?> configClass, ClassLoader classLoader)方法创建代理类(CGLIB方式创建),并设置给当前BeanDefinition。
核心源码如下:
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
// 省略部分代码...
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);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
// 进行代理类的创建
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
// 省略日志信息输出代码...
// 将创建好的代理类设置给当前BeanDefinition
beanDef.setBeanClass(enhancedClass);
}
}
// 省略部分代码...
}
ConfigurationClassEnhancer的enhance(Class<?> configClass, ClassLoader classLoader)方法
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
// 如果当前类已经是代理类,则直接返回
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
// 省略日志信息输出代码...
return configClass;
}
// 创建代理类
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
// 省略日志信息输出代码...
return enhancedClass;
}
ConfigurationClassEnhancer的newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader)方法
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
// 设置父类,CGLIB代理类是通过继承父类生成的
enhancer.setSuperclass(configSuperClass);
// 给所有基于@Configuration标记的类生成代理类设置EnhancedConfiguration接口,主要用于后续Bean实例化、初始化等过程中BeanPostProcessor的执行
// 接口EnhancedConfiguration继承了接口BeanFactoryAware,因为需要代理类通过访问BeanFactory去创建被代理类对象
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
// 给类的方法设置拦截器(BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor)
// 两个拦截器均实现了MethodInterceptor接口
// BeanMethodInterceptor用于对@Bean标记的方法进行拦截,即每次调用@Bean标记的方法时会进到此拦截器中
// BeanFactoryAwareMethodInterceptor用于对@Configuration标记的类实例的BeanFactoryAware.setBeanFactory(BeanFactory)进行拦截
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
2.2.2 ImportAwareBeanPostProcessor
ImportAwareBeanPostProcessor主要用于创建@Configuration标记的类的代理类设置BeanFactory属性。
3. 总结
「ConfigurationClassPostProcessor」作为Spring容器启动流程中一个非常重要的类, 通过「实现自BeanDefinitionRegistryPostProcessor的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法完成了BeanDefinition的扫描、创建、注册」,核心步骤为
1)ConfigurationClassParser.parse(Set configCandidates):通过解析@Configuration、@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解得到了ConfigurationClass;
2)ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set configurationModel):通过解析ConfigurationClass完成了BeanDefinition的创建及注册。
通过「实现自BeanFactoryPostProcessor的postProcessBeanFactory()方法使用CGLIB完成了@Configuration注解、且注解属性proxyBeanMethods为true(默认为true)的类生成了其代理类,并进行方法增强」。
4. 其他
- ConfigurationClassPostProcessor对@Configuration注解、且注解属性proxyBeanMethods为true(默认为true)的类生成了其代理类的目的是什么?
@Configuration
public class AppConfig {
@PostConstruct
private void init() {
System.out.println(orderService());
System.out.println(orderService());
System.out.println(orderService1());
System.out.println(orderService1());
}
@Bean
public OrderService orderService () {
return new OrderService();
}
public OrderService orderService1 () {
return new OrderService();
}
}
上述代码的输出结果为:
spring.test.service.OrderService@6c3f5566
spring.test.service.OrderService@6c3f5566
spring.test.service.OrderService@12405818
spring.test.service.OrderService@314c508a
通过结果可以得知,「有@Bean标记的方法,由于有代理类的增强,在重复调用时会进行拦截,判断对应实例是否已存在,若存在则不会继续调用创建方法,而没有@Bean标记的方法,每次都会进行调用重新创建」。所以我们需要通过单例Bean进行Bean之间的关联时,一定要用@Bean标记方法,并且配置类需要@Configuration进行标记,且@Configuration的proxyBeanMethods为true,特别是在配置Spring数据库事务管理器关联的DataSource过程中。
本文暂时没有评论,来添加一个吧(●'◡'●)