Spring源码之BeanDefinition扫描创建注册流程

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. 分析

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集合;

3.将配置类候选者的BeanDefinition集合进行排序

4.将配置类候选者的BeanDefinition集合传入ConfigurationClassParser.parse(Set<BeanDefinitionHolder> configCandidates)方法进行解析,得到配置类集合;

5.将配置类集合传入ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set<ConfigurationClass> configurationModel)方法,得到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(Set<BeanDefinitionHolder> configCandidates)

        此方法用于解析配置类候选者BeanDefintion,类上有@Configuration、@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解是ConfigurationClass,得到ConfigurationClass集合,存放在属性configurationClasses中,供后续扫描创建新的BeanDefintion。内部调用processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter)方法进行解析。

2.1.1.2.1 processConfigurationClass(ConfigurationClass configClass, Predicate<String> 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<String> 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<String> filter)

执行流程如下:

1.处理带@Component注解;

通过调用processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,Predicate<String> filter)方法,解析当前配置类内部声明的内部类、内部接口,将所有符合ConfigurationClassUtils.isConfigurationCandidate(AnnotationMetadata metadata)检查条件的内部类/接口作为配置类候选者集合,并将集合排序后,再次调用processConfigurationClass(ConfigurationClass configClass, Predicate<String> 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<String> 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<String> 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<ConfigurationClass> 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<BeanDefinitionHolder> configCandidates):通过解析@Configuration、@Component、@ComponentScan、@Import、@ImportResource注解,或者类的方法上有@Bean注解d得到了ConfigurationClass;

        2)ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set<ConfigurationClass> configurationModel):通过解析ConfigurationClass完成了BeanDefinition的创建及注册。

  • 通过实现自BeanFactoryPostProcessor的postProcessBeanFactory()方法使用CGLIB完成了@Configuration注解、且注解属性proxyBeanMethods为true(默认为true)的类生成了其代理类,并进行方法增强。

4. 其他

1. 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过程中。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值