Spring源码(十六)-ConfigurationClassPostProcessor

 2023-01-10
原文作者:程序员小杰 原文地址:https://juejin.cn/post/7122064723037650980

日积月累,水滴石穿 ?

前言

上篇讲到 refresh()invokeBeanFactoryPostProcessors方法,该方法会执行所有

BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry()方法以及BeanFactoryPostProcessorpostProcessBeanFactory()方法。其重中之中就是 postProcessBeanDefinitionRegistry方法。

在无自定义的情况下,Spring容器中就一个实现了 BeanDefinitionRegistryPostProcessorBeanDefinition,它的名字是 ConfigurationClassPostProcessor

作用

各位可能还不了解 ConfigurationClassPostProcessor这个类的作用,小杰就先说说。

SpringBean 的都是基于 BeanDefinition 去创建的,所以需要先有 BeanDefinition,才会有 Bean

一个 BeanDefinition就代表着一个类,那一个类是怎么被解析为BeanDefinition呢?这个就是由 ConfigurationClassPostProcessor来完成的。

ConfigurationClassPostProcessor是一个BeanFactory后置处理器,会对写有 @Configuration@ComponentScan@ComponentScans@ImportResource@Import@Component@Bean注解的类解析为 BeanDefinition,并添加到容器。再由后续的流程将之注册为 Bean

ConfigurationClassPostProcessor

    public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
    PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
        
    }

可以看到实现了BeanDefinitionRegistryPostProcessor ,而 BeanDefinitionRegistryPostProcessor接口继承了 BeanFactoryPostProcessor 接口,那就会重写其postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法。

一、postProcessBeanDefinitionRegistry

我们先来看 postProcessBeanDefinitionRegistry方法。看看是如何进行扫描的!

    @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);
        }
        // registriesPostProcessed在本类的 postProcessBeanFactory 方法中会用到
        // 记录 registryId
        this.registriesPostProcessed.add(registryId);
    
        // 寻找配置类对应的BeanDefinition然后进行处理
        // 比如开始扫描
        processConfigBeanDefinitions(registry);
    }

processConfigBeanDefinitions

核心逻辑在processConfigBeanDefinition()方法中。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        String[] candidateNames = registry.getBeanDefinitionNames();
    
        // 遍历BeanDefinitionRegistry中当前存在的beanDefinition,从中找出那些 beanDefinition 是配置 bean
        for (String beanName : candidateNames) {
            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);
                }
            }
            // 检查BeanDefinition是不是配置类候选者,那什么样的BeanDefinition符合呢?
            // 1. 存在@Configuration的就是配置类
            // 2. 存在@Component,@ComponentScan,@Import,@ImportResource
            // 3. 存在@Bean标注的方法
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                //构建一个 BeanDefinitionHolder,添加到 configCandidates 集合中
                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;
        // 当前 BeanFactory 是不是支持单例bean的注册,如果支持则设置一个 BeanNameGenerator
        // 用来在扫描 @Component 和 @Import 某个Bean时取名字
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            // localBeanNameGeneratorSet 默认为 false
            if (!this.localBeanNameGeneratorSet) {
                // 程序员可以指定一个beanName生成器 applicationContext.setBeanNameGenerator()
                // 不指定则使用默认的 ConfigurationBeanNameGenerator
                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
        // 配置 bean 解析器,解析器里存在 registry,所以在解析的过程中可以往 registry 中添加 BeanDefinition
        ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            // 对配置BeanDefinition进行解析,解析完后会生成ConfigurationClass
            parser.parse(candidates);
            //验证
            parser.validate();
    
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            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());
            }
    
            // 利用 reader 解析 ConfigurationClass,同时注册 BeanDefinition
            this.reader.loadBeanDefinitions(configClasses);
            // 省略部分代码 ... 
        }
        while (!candidates.isEmpty());
    
    // 省略部分代码 ... 
    }

方法一:checkConfigurationClassCandidate

检查BeanDefinition是不是配置类。配置类分两种 full、lite,如果加了@Configuration,那么配置类类型为full,如果加了@Bean@Component@ComponentScan@Import@ImportResource这些注解,配置类类型为lite

    public static boolean checkConfigurationClassCandidate(
        BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    
        // 省略部分不重要的代码
        
        // 获取 Configuration 注解的属性信息,配置类分两种
        // 1、被 @Configuration 标记的配置类为 full,full 的配置类会生成代理对象
        // 2、其他的配置类为 lite
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        // proxyBeanMethods 默认值为 true
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            // CONFIGURATION_CLASS_FULL = full
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        // 注意,并不是说没有 @Configuration 注解,当前 BeanDefinition 就不是一个配置类
        // 还要注意 isConfigurationCandidate 方法,会检查是否存在
        // @Component, @ComponentScan,@Import,@ImportResource,@Bean注解
        // 只是配置类类型为 lite
        else if (config != null || isConfigurationCandidate(metadata)) {
            // CONFIGURATION_CLASS_LITE = lite
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        else {
            // 返回false,表示不是一个配置类
            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;
    }
isConfigurationCandidate

检查是否存在@Component@ComponentScan@Import@ImportResource@Bean注解,如果有,当前BeanDefinition是一个配置类,类型为 lite

    public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
        // Do not consider an interface or an annotation...
        // 不考虑接口上的注解
        if (metadata.isInterface()) {
            return false;
        }
    
        // Any of the typical annotations found?
        // candidateIndicators 是一个静态的 Set 集合
        // 集合中有四个值,分别为@Component,@ComponentScan,@Import,@ImportResource这四个注解
        for (String indicator : candidateIndicators) {
            if (metadata.isAnnotated(indicator)) {
                return true;
            }
        }
    
        // Finally, let's look for @Bean methods...
        // 查找有没有加了@Bean注解的方法
        try {
            return metadata.hasAnnotatedMethods(Bean.class.getName());
        }
        catch (Throwable ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
            }
            return false;
        }
    }
    
    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());
    }

方法二:parse

该方法会对上面找到的配置类进行解析,也就是解析类上的注解。会将@ComponentScan扫描到的类,@Import导入的类,@Bean方法所在的类解析成ConfigurationClass类。

@Component@ComponentScan@Import@ImportResource@Bean

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        // 遍历多个配置类的 BeanDefinition
        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 根据BeanDefinition类型的不同,调用parse()不同的重载方法
                // 但是内部都是调用 processConfigurationClass 方法
                // 小杰这就分析 AnnotatedBeanDefinition 入口
                // 处理有注解的 BeanDefinition
                if (bd instanceof AnnotatedBeanDefinition) {
                    // 处理注解的信息
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
                }
                else {
                    parse(bd.getBeanClassName(), holder.getBeanName());
                }
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                    "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
            }
        }
    	
        // 如果@Import 导入的类的类型为 DeferredImportSelector
        // 这句话才会生效,内部其实也是调用 processImports 方法。
        this.deferredImportSelectorHandler.process();
    }
    
    // 处理注解的信息
    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
        // 构建一个 ConfigurationClass 对象,表示配置类信息,包括注解信息
        // 和 beanName,以及resource属性,表示配置类的类路径地址
        processConfigurationClass(new ConfigurationClass(metadata, beanName));
    }

processConfigurationClass

processConfigurationClass 方法中调用 doProcessConfigurationClass方法,这才是核心处理逻辑方法。

    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    
        // 省略部分代码
        // sourceClass 将类简单的包装了一下,可以忽略
        SourceClass sourceClass = asSourceClass(configClass);
        do {
            //循环解析,核心逻辑
            sourceClass = doProcessConfigurationClass(configClass, sourceClass);
        }
        // 配置类可能存在父类,所以需要递归处理
        while (sourceClass != null);
    
        // 把当前配置类存在configurationClasses Map里面
        this.configurationClasses.put(configClass, configClass);
    }

doProcessConfigurationClass

    @Nullable
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {
    
        // 1. 如果配置类上有@Component注解,则要获得类中的内部类,判断内部类上是否有 @Component、@ComponentScan、@Import、@ImportResource注解
        // 如果有调用 processConfigurationClass
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            // Recursively process any member (nested) classes first
            processMemberClasses(configClass, sourceClass);
        }
    
        // Process any @PropertySource annotations
        // 2. 解析@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
        // 3. 解析@ComponentScan、ComponentScans 注解,获得类上注解的信息,比如:basePackages 的值
        // 并进行扫描
        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
                // 扫描指定包路径及子包下的类,得到 BeanDefinitionHolder,BeanDefinitionHolder 中包含 BeanDefinition
                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();
                    }
    
                    // 检查扫描所得到 BeanDefinition 是不是配置 Bean
                    // 基本上都有 @Component 注解,所以都是配置类,继续需要进行解析
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }
    
        // Process any @Import annotations
        // 4. 解析@Import。
        // getImports方法返回 sourceClass 上定义的 Import注解中所导入的类的信息的集合
        processImports(configClass, sourceClass, getImports(sourceClass), true);
    
        // Process any @ImportResource annotations
        // 5. 解析@ImportResource,得到导入进来的spring的xml配置文件,然后解析
        AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        if (importResource != null) {
            //xml文件地址
            String[] resources = importResource.getStringArray("locations");
            //得到解析xml文件的解析器
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
            for (String resource : resources) {
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
    // 添加到ConfigurationClass 类 importedResources Map 属性中,后续进行解析
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }
    
        // Process individual @Bean methods
        // 6. 解析配置类中的加了@Bean注解的方法
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            // 将找到的方法添加到 ConfigurationClass 类 beanMethods Set 属性中,后续进行解析
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }
    
        // Process default methods on interfaces
        // 7. 如果配置类实现了某个接口,那么则解析该接口中的加了@Bean注解的默认方法
        // 添加到 ConfigurationClass 类 beanMethods Set 属性中,后续进行解析
        processInterfaces(configClass, sourceClass);
    
        // Process superclass, if any
        // 8. 如果有父类,则返回父类给上层遍历进行处理
        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;
    }

方法逻辑挺长的,大体流程如下:

  • 1、配置类上有@Component注解,则要获得配置类中的内部类,判断内部类上是否有 @Component、@ComponentScan、@Import、@ImportResource注解,如果有则代表内部类也是配置类,则需要调用 processConfigurationClass方法。相当于递归。
  • 2、处理解析@PropertySource注解。
  • 3、解析@ComponentScan、ComponentScans注解,扫描指定包路径及子包下的类。由于扫描所得到 BeanDefinition有可能也是配置类,所以也需要递归处理解析。
  • 4、处理@Import注解。
  • 5、处理@ImportResource注解,解析 xml 文件。
  • 6、处理@Bean注解的方法
  • 如果配置类实现了某个接口,那么则解析该接口中的加了@Bean注解的默认方法
  • 8、如果有父类,则返回父类给上层遍历进行处理

简单的流程步骤这里就不再分析了。

流程一

核心逻辑在 this.componentScanParser.parse方法中。

    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    
    // useDefaultFilters 值默认为 true,所以 includeFilters 中默认就注册了一个 @Component 注解对应的 Filter
    // ClassPathBeanDefinitionScanner 这个对象在讲 Spring 启动流程中已经分析了
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
    componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    
    // 设置BeanName生成器
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
    BeanUtils.instantiateClass(generatorClass));
    
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
    	scanner.setScopedProxyMode(scopedProxyMode);
    }
    else {
    	Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
    	scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }
    
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));
    
    // 得到 @ComponentScan 中 includeFilters 的值 ,并设置 IncludeFilter,
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
    for (TypeFilter typeFilter : typeFiltersFor(filter)) {
    	scanner.addIncludeFilter(typeFilter);
    }
    }
    
    // 得到 @ComponentScan 中 excludeFilters 的值 ,并设置 ExcludeFilter
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
    for (TypeFilter typeFilter : typeFiltersFor(filter)) {
    	scanner.addExcludeFilter(typeFilter);
    }
    }
    
    // 设置懒加载
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
    	scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }
    
    Set<String> basePackages = new LinkedHashSet<>();
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
    String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    Collections.addAll(basePackages, tokenized);
    }
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
    	basePackages.add(ClassUtils.getPackageName(clazz));
    }
    if (basePackages.isEmpty()) {
    	basePackages.add(ClassUtils.getPackageName(declaringClass));
    }
    // declaringClass 为传入的配置类全路径,例如:com.cxyxj.xx.AppApplication
    // 默认的排除过滤
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
        	return declaringClass.equals(className);
        }
    });
    
    // 开始扫描包路径,得到 BeanDefinitionHolder
    return scanner.doScan(StringUtils.toStringArray(basePackages));
    }

不出意外,还是包含一个 doScan方法。

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        for (String basePackage : basePackages) {
            // 扫描包路径得到BeanDefinition,得到的BeanDefinition是空的,还没有解析类上所定义的注解信息
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                // 得到Scope的信息,并设置
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                // 得到beanName
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                if (checkCandidate(beanName, candidate)) {
                    // 生成BeanDefinitionHolder并注册到registry中
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    				// 根据 @@Scope 属性 proxyMode 的值,确定是否需要产生代理对象
                    definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }
    
    // Scope注解中的ProxyMode属性有四个取值
    // 1.DEFAULT:默认值,默认情况下取no
    // 2.NO:不开启代理
    // 3.INTERFACES:使用jdk动态代理
    // 4.TARGET_CLASS:使用cglib代理
    // 假如有一个单例beanA,其中有一个属性B,B的Scope是session,此时,容器在启动时创建A的过程中需要注入B属性,
    // 但是B的scope是session,这种情况下是注入不了的,是会报错的
    // 但是如果将B的Scope的ProxyMode属性配置为INTERFACES/TARGET_CLASS时,那么B就会生成一个ScopedProxyFactoryBean类型的BeanDefinitionHolder
    // 在A注入B时,就会注入一个ScopedProxyFactoryBean类型的Bean
    static BeanDefinitionHolder applyScopedProxyMode(
        ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
    
        ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
        if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
            return definition;
        }
    
        // 是否使用cglib
        boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
        // 创建ScopedProxyFactoryBean类型的BeanDefinitionHolder
        return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
    }
findCandidateComponents

findCandidateComponents的方法值为 Set<BeanDefinition>,可以得知,扫描就是在这个方法干的。

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    
        // Spring提供了一种支持更快速扫描的机制,就是编译时直接创建一个静态的,ASM技术
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            // 扫描@Component,扫描 basePackage 下的所有类,看是否有@Component注解
            return scanCandidateComponents(basePackage);
        }
    }

对于 ASM 技术,有兴趣的伙伴可以去网上了解下。小杰不会。我们来看最笨的方法 scanCandidateComponents

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        // 扫描类,得到BeanDefinition
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            //路径下所有的类
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
                        // MetadataReader 包含了对应 class 的元信息以及注解元信息。
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 判断一个类是不是Component
                        if (isCandidateComponent(metadataReader)) {
                            // 通过扫描@Component得到的BeanDefinition类型为ScannedGenericBeanDefinition
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            // 再进一步验证
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                //将 sbd 添加到 Set 集合中
                                candidates.add(sbd);
                            }
           // 省略诸多 catch、else
        return candidates;
    }
                        
    
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    	//如果读取的类的注解在排除注解过滤规则中,返回false
    	for (TypeFilter tf : this.excludeFilters) {
    		if (tf.match(metadataReader, getMetadataReaderFactory())) {
    			return false;
    		}
    	}
    	//如果读取的类的注解在包含的注解的过滤规则中,则返回ture
    	for (TypeFilter tf : this.includeFilters) {
    		if (tf.match(metadataReader, getMetadataReaderFactory())) {
    			return isConditionMatch(metadataReader);
    		}
    	}
    	//如果读取的类的注解既不在排除规则,也不在包含规则中,则返回false
    	return false;
    }
    
     // 判断一个类是不是Component
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    		// 不匹配,扫描到的类在 excludeFilters 中,返回false,代表不是一个备选的Component
    		for (TypeFilter tf : this.excludeFilters) {
    			if (tf.match(metadataReader, getMetadataReaderFactory())) {
    				return false;
    			}
    		}
    
    		// 匹配,只有通过了 includeFilters 的验证才算是一个备选的Component
    		for (TypeFilter tf : this.includeFilters) {
    			if (tf.match(metadataReader, getMetadataReaderFactory())) {
    				return isConditionMatch(metadataReader);
    			}
    		}
    		return false;
    	}

excludeFiltersincludeFilters都是 @ComponentScan注解的属性,如果不熟悉,可以前往:@ComponentScan 注解详解

流程四

    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
    			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
    
    		if (importCandidates.isEmpty()) {
    			return;
    		}
    
    		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
    			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    		}
    		else {
    			this.importStack.push(configClass);
    			try {
    				// 以下会判断 @Import(UserService.class) 导入的类型
    				for (SourceClass candidate : importCandidates) {
    					// 如果导入的类实现了 ImportSelector 接口
    					if (candidate.isAssignable(ImportSelector.class)) {
    						// Candidate class is an ImportSelector -> delegate to it to determine imports
    						Class<?> candidateClass = candidate.loadClass();
    						// 得到 ImportSelector 对象
    						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
    								this.environment, this.resourceLoader, this.registry);
    						// DeferredImportSelector 是 ImportSelector 的子接口
    						if (selector instanceof DeferredImportSelector) {
    							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
    						}
    						else {
    							// 执行 selectImports 方法,得到 selectImports 方法的返回值(需要导入的类名)。
    							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
    							//包装为 SourceClass
    							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
    							// 将导入的类作为配置类,进行递归解析。可能可能还带有 @Import 或者其他注解,
    							processImports(configClass, currentSourceClass, importSourceClasses, false);
    						}
    					}
    					// 实现了 ImportBeanDefinitionRegistrar 接口
    					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
    						// Candidate class is an ImportBeanDefinitionRegistrar ->
    						// delegate to it to register additional bean definitions
    						// 如果@Import注解中的类实现了ImportBeanDefinitionRegistrar接口
    						// 就把该类的实例放入 ConfigurationClass类中属性 importBeanDefinitionRegistrars Map中,
    						// 后面再执行该实例的 registerBeanDefinitions 方法
    						Class<?> candidateClass = candidate.loadClass();
    						ImportBeanDefinitionRegistrar registrar =
    								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
    										this.environment, this.resourceLoader, this.registry);
    						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
    					}
    					else {
    						// 如果导入的类就是一个普通的类,将其作为配置类进行解析
    						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
    						// process it as an @Configuration class
    						this.importStack.registerImport(
    								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
    						// 调用 processConfigurationClass 方法
    						processConfigurationClass(candidate.asConfigClass(configClass));
    					}
    				}
    			}
    			catch (BeanDefinitionStoreException ex) {
    				throw ex;
    			}
    			catch (Throwable ex) {
    				throw new BeanDefinitionStoreException(
    						"Failed to process import candidates for configuration class [" +
    						configClass.getMetadata().getClassName() + "]", ex);
    			}
    			finally {
    				this.importStack.pop();
    			}
    		}
    	}

如果配置类上存在@Import注解,那么需要判断导入类的类型:

  • 如果是 ImportSelector,那么调用执行 selectImports方法得到类名,然后在把这个类当做配置类进行解析**(递归)**
  • 如果是ImportBeanDefinitionRegistrar,那么则生成一个ImportBeanDefinitionRegistrar 实例对象,并添加到配置类对象中(ConfigurationClass)的 importBeanDefinitionRegistrars属性中。
  • 如果是普通类,做作为配置类进行处理。

流程 4(ImportBeanDefinitionRegistrar类型)、流程 5、流程6都没有真正的将之解析为 BeanDefinition,都是先存到 ConfigurationClass类的属性中。

流程七

流程 7,只是Spring 多了一种注册 Bean 的写法。写法如下:

    public interface UService {
    
    	@Bean
    	default UserService u(){
    		return new UserService();
    	}
    
    }
    
    @Service
    public class UServiceImpl implements UService{
    }

UServiceImpl是一个配置类,且实现了 UService接口,接口中有一个默认的实现方法 u,该方法上添加了@Bean注解。经过第(7)步的解析,会添加到 ConfigurationClassbeanMethods 属性中,后续进行解析。

会向Spring容器中注册一个UserService类型的 Bean。

经过 processConfigurationClass方法的解析后,我们会得到许多个配置类,这些配置类存放在 ConfigurationClassParser类的configurationClasses属性中。存储结构如下:

202301012015427791.png

接下来就利用reader来进一步解析ConfigurationClass,因为还有一部分没有被生成 BeanDefinition

我们回到 processConfigBeanDefinitions方法中,找到 this.reader.loadBeanDefinitions(configClasses);代码。

方法三 loadBeanDefinitions

该方法就是将另外一部分生成BeanDefinition,被@Import@Bean@ImportedResource注解方式注册的类解析成BeanDefinition,然后注册到BeanDefinitionMap中。

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
            //循环调用
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }
    
    private void loadBeanDefinitionsForConfigurationClass(
        ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    
      // 省略....
    
        // 当前配置类是不是通过 @Import 注解导入进来的,如果是则解析该类上面的注解
        // 比如 @Scope,@Lazy 这些注解信息,然后构建成 BeanDefinition
        // 并注册到 BeanDefinitionMap 中
        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        //getBeanMethods:@Bean注解标注的方法,解析并注册到 BeanDefinitionMap 中
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
    
        // 从 @ImportedResource 导入进来的资源文件中加载BeanDefinition,并注册到 BeanDefinitionMap 中
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        // 如果@Import注解中的类实现了ImportBeanDefinitionRegistrar接口
        // 调用 ImportBeanDefinitionRegistrar 对象的 registerBeanDefinitions 方法加载 BeanDefinition
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

除了loadBeanDefinitionsForBeanMethod之外,其余方法就不再分析了,整体逻辑一目了然的。

    @SuppressWarnings("deprecation")  // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE
    	private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    		// @Bean标注方法的来源
    		ConfigurationClass configClass = beanMethod.getConfigurationClass();
    		MethodMetadata metadata = beanMethod.getMetadata();
    		// 方法名称
    		String methodName = metadata.getMethodName();
    
    		// Do we need to mark the bean as skipped by its condition?
    		if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
    			configClass.skippedBeanMethods.add(methodName);
    			return;
    		}
    		if (configClass.skippedBeanMethods.contains(methodName)) {
    			return;
    		}
    
    		// 获得 @Bean 的信息
    		AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    		Assert.state(bean != null, "No @Bean annotation attributes");
    
    		// Consider name and any aliases
    		//获得所有别名
    		List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
    		//如果指定了别名,则第一个别名作为 beanName,负责使用 方法名称作为 beanName
    		String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
    
    		// Register aliases even when overridden
    		for (String alias : names) {
    			// 注册别名
    			this.registry.registerAlias(beanName, alias);
    		}
    
    		// Has this effectively been overridden before (e.g. via XML)?
    		// 判断 beanName 是否已经被加载过了
    		if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
    			if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
    				throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
    						beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
    						"' clashes with bean name for containing configuration class; please make those names unique!");
    			}
    			return;
    		}
    		// 构建 BeanDefinition
    		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    		beanDef.setResource(configClass.getResource());
    		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
    		// 被@Bean标注的方法是静态,则使用静态工厂注入
    		if (metadata.isStatic()) {
    			// static @Bean method
    			if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
    				beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
    			}
    			else {
    				// 指定工厂类路径
    				beanDef.setBeanClassName(configClass.getMetadata().getClassName());
    			}
    			// 指定工厂方法
    			beanDef.setUniqueFactoryMethodName(methodName);
    		}
    		else {
    			// 实例工厂注入
    			// instance @Bean method
    			// factory-bean 配置实例化工厂类的名称
    			beanDef.setFactoryBeanName(configClass.getBeanName());
    			// 指定工厂方法
    			beanDef.setUniqueFactoryMethodName(methodName);
    		}
    
    		if (metadata instanceof StandardMethodMetadata) {
    			beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
    		}
    
    		beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    		beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
    				SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
    
    		AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
    
    		Autowire autowire = bean.getEnum("autowire");
    		if (autowire.isAutowire()) {
    			beanDef.setAutowireMode(autowire.value());
    		}
    
    		boolean autowireCandidate = bean.getBoolean("autowireCandidate");
    		if (!autowireCandidate) {
    			beanDef.setAutowireCandidate(false);
    		}
    
    		String initMethodName = bean.getString("initMethod");
    		if (StringUtils.hasText(initMethodName)) {
    			beanDef.setInitMethodName(initMethodName);
    		}
    
    		String destroyMethodName = bean.getString("destroyMethod");
    		beanDef.setDestroyMethodName(destroyMethodName);
    
    		// Consider scoping
    		ScopedProxyMode proxyMode = ScopedProxyMode.NO;
    		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
    		if (attributes != null) {
    			beanDef.setScope(attributes.getString("value"));
    			proxyMode = attributes.getEnum("proxyMode");
    			if (proxyMode == ScopedProxyMode.DEFAULT) {
    				proxyMode = ScopedProxyMode.NO;
    			}
    		}
    
    		// Replace the original bean definition with the target one, if necessary
    		// 使用需要创建代理对象
    		BeanDefinition beanDefToRegister = beanDef;
    		if (proxyMode != ScopedProxyMode.NO) {
    			BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
    					new BeanDefinitionHolder(beanDef, beanName), this.registry,
    					proxyMode == ScopedProxyMode.TARGET_CLASS);
    			beanDefToRegister = new ConfigurationClassBeanDefinition(
    					(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
    		}
    
    		if (logger.isTraceEnabled()) {
    			logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
    					configClass.getMetadata().getClassName(), beanName));
    		}
    		// 注册BeanDefinition
    		this.registry.registerBeanDefinition(beanName, beanDefToRegister);
    	}

看完上述逻辑,你会得到以下知识:

  • @Bean可以指定别名,第一个别名会作为beanName,如果没指定别名,会将方法名称作为别名。
  • @Bean 是通过factory-method实例化对象的。

具体使用请移步前往:XML文件的读取-factory-method的使用

上面几千字将 postProcessBeanDefinitionRegistry方法分析完啦!接下来看 postProcessBeanFactory

方法。

二、postProcessBeanFactory

通过前面的学习我们应该知道 postProcessBeanFactory是对BeanFactory进行处理的。那这个方法是怎么处理的呢,方法干了两件事:

  • 对被 @Configuration 标注的类,使用CGLIB代理生成代理对象。
  • beanPostProcessors 集合中添加一个 ImportAwareBeanPostProcessorBean的后置处理器。
    @Override
    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);
        // 是否需要进行解析
        // factoryId 在执行 postProcessBeanDefinitionRegistry 方法时,已经添加到了 registriesPostProcessed 集合中
        // 所以该判断永远不会成立
        if (!this.registriesPostProcessed.contains(factoryId)) {
            // BeanDefinitionRegistryPostProcessor hook apparently not supported...
            // Simply call processConfigurationClasses lazily at this point then.
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }
    
        // 对被 @Configuration 标注的类,使用CGLIB代理生成代理对象
        enhanceConfigurationClasses(beanFactory);
        // 向 beanPostProcessors 中添加一个 Bean的后置处理器
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }

enhanceConfigurationClasses

    public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
        
        Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            // configClassAttr 的值有两种:full、lite
            Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
            // 省略代码 。。。
    
            // 被@Configuration标注的配置类就是 full
            if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
               // 省略代码 。。。
                configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
        }
    
        // 加了@Configuration注解的配置类的BeanDefinition
        if (configBeanDefs.isEmpty()) {
            // nothing to enhance -> return immediately
            // 没有什么可增强的 -> 立即返回
            return;
        }
    
        // 生成被 @Configuration 标注类的代理对象
        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) {
                if (logger.isTraceEnabled()) {
                    logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                                               "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                }
                // 将增强类设置给 beanDefinition,后续基于 BeanDefinition 产生的bean就是增强类的对象了
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }
  • enhancer.enhance
    public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
         // 省略一大串日志 。。。
        Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
        
        return enhancedClass;
    }

上面的核心方法为newEnhancer,我们来看 newEnhancer方法。

  • newEnhancer
    private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
        Enhancer enhancer = new Enhancer();
        // 对代理对象设置父类
        enhancer.setSuperclass(configSuperClass);
        // 对代理对象设置父接口
        // EnhancedConfiguration 继承了 BeanFactoryAware
        enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
        enhancer.setUseFactory(false);
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
        // 添加了两个 MethodInterceptor ,BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor
        // CGLIB 的增强就是执行 MethodInterceptor类 的 intercept 方法
        // BeanMethodInterceptor :对加了@Bean注解的方法进行增强
        // BeanFactoryAwareMethodInterceptor:对实现了 BeanFactoryAware 接口,调用 setBeanFactory() 方法
        enhancer.setCallbackFilter(CALLBACK_FILTER);
        enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
        return enhancer;
    }

这方法创建了一个 Enhancer 实例。并设置了代理对象的父类、代理对象的父接口 EnhancedConfiguration,代理对象的增强逻辑 BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor

addBeanPostProcessor

beanPostProcessors 中添加一个 Bean的后置处理器,类型为 ImportAwareBeanPostProcessor,在后续 Bean 的生命周期中会触发。我们一起看看 ImportAwareBeanPostProcessor的代码逻辑。

    private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    
        private final BeanFactory beanFactory;
    
        public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }
    
        @Override
        public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
            // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
            // postProcessProperties method attempts to autowire other configuration beans.
            if (bean instanceof EnhancedConfiguration) {
                ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
            }
            return pvs;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            if (bean instanceof ImportAware) {
                ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
                AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
                if (importingClass != null) {
                    ((ImportAware) bean).setImportMetadata(importingClass);
                }
            }
            return bean;
        }
    }

ImportAwareBeanPostProcessor中就重写了两个方法,postProcessProperties方法与 postProcessBeforeInitialization方法。

  • postProcessProperties:如果当前 bean 实现了EnhanceConfiguration类,则为它设置 beanFactory属性赋值。如果忘记了 EnhanceConfiguration,看看 enhanceConfigurationClasses方法。
  • postProcessBeforeInitialization:处理 ImportAware回调。

为什么加了 @Configuration注解的类需要被代理呢?

不加 @Configuration注解

我们来看一个现象,准备如下代码,两个@Bean标注的方法 u()u2,在 u2中调用 u。会打印几次====== u?1次还是2次呢?

    @ComponentScan(basePackages = {"com.cxyxj.conf"})
    public class AppApplication {
    
       	@Bean
    	UserService u(){
    
    		UserService userService = new UserService();
    		System.out.println("====== u == " + userService);
    		return userService;
    	}
    
        @Bean
        BeanTest u2(){
            u();
            System.out.println("====== u2");
            return new BeanTest();
    }
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppApplication.class);
            UserService bean = context.getBean(UserService.class);
    		System.out.println("bean = " + bean);
        }
    }

启动结果如下:

202301012015436142.png

结果是打印了两次。返回的对象并不一致,这个两个对象的作用域都是singleton, 这不就违背了Spring的单例原则吗?即一个bean在一个IoC容器中只有一个实例。

各位是否还记得 @Bean是如何创建 Bean 实例的吗?采用的是 factory-method方式进行实例化,而这种方式底层是通过 反射

202301012015442463.png

源码位于 SimpleInstantiationStrategyinstantiate方法。

前往博文:Supplier、工厂方法实例化Bean

  • 通过反射执行 u()方法,将返回的的对象放入单例池中。
  • 通过反射执行 u2()方法,再调用 u(),这没办法从单例池获得UserService对象,只能重新创建UserService对象,并且这次创建的对象没办法放入单例池中。调用完 u(),将创建的 BeanTest对象放入单例池。

加 @Configuration注解

在类上加上 @Configuration注解,进行启动。结果如下:

202301012015450124.png

可以看出加上@Configuration注解之后,u()只被调用了一次。Spring 是怎么保证的呢?

各位还记得小杰在enhanceConfigurationClasses方法中提到,在由 CGLIB 产生代理对象的过程中,会构建一个 Enhancer实例,会给Enhancer实例的 filter属性添加了两个 MethodInterceptor ,分别是 BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor。其中 BeanMethodInterceptor就是处理被 @Bean 注解的方法。

BeanMethodInterceptor实现了MethodInterceptor接口,会重写其 intercept,这也是 CGLIB 代理的核心方法,代码如下:

  • enhancedConfigInstance:CGLIB 创建的代理对象
  • beanMethod:代理类执行的方法,本例中的 u()u2()
  • beanMethodArgs:需要传给方法的参数
  • cglibMethodProxy:方法代理,不需要过于关心
    @Override
    @Nullable
    public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
                            MethodProxy cglibMethodProxy) throws Throwable {
    
        // 得到bean工厂
        ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
        // beanMethod对应的beanName
        String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
    
        // Determine whether this bean is a scoped-proxy
        // 确定此 bean 是否是作用域代理
        if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
            String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
            if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
                beanName = scopedBeanName;
            }
        }
    
        // To handle the case of an inter-bean method reference, we must explicitly check the
        // container for already cached instances.
    
        // First, check to see if the requested bean is a FactoryBean. If so, create a subclass
        // proxy that intercepts calls to getObject() and returns any cached bean instance.
        // This ensures that the semantics of calling a FactoryBean from within @Bean methods
        // is the same as that of referring to a FactoryBean within XML. See SPR-6602.
        // 如果beanFactory中存在beanName并且也存在&+beanName所对应的bean,那么这个bean是一个FactoryBean
        if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
            factoryContainsBean(beanFactory, beanName)) {
            // FactoryBean对象
            Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
            if (factoryBean instanceof ScopedProxyFactoryBean) {
                // Scoped proxy factory beans are a special case and should not be further proxied
            }
            else {
                // It is a candidate FactoryBean - go ahead with enhancement
                // 对FactoryBean对象进行增强,当userService()中调用userFactoryBean()时,返回的是UserFactoryBean的代理对象
                // 因为不能返回getObject方法的bean,也不能直接方法上面的factoryBean对象,因为如果返回的是factoryBean对象
                // 如果后面调用getObject方法就会产生问题,而产生一个代理对象就可以对getObject方法进行代理,保证getObject方法返回的是同一个bean
                return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
            }
        }
    
        // 比如当前正在进行实例化的是u2()方法所对应的bean,而在u2()方法中会调用u()方法
       // 这个时候下面这个判断等于false,而等于false,就不会真正去执行u()方法了,就会直接去beanFactory中去获取bean
        if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
            // The factory is calling the bean method in order to instantiate and register the bean
            // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
            // create the bean instance.
            if (logger.isInfoEnabled() &&
                BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
                logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
                                          "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                                          "result in a failure to process annotations such as @Autowired, " +
                                          "@Resource and @PostConstruct within the method's declaring " +
                                          "@Configuration class. Add the 'static' modifier to this method to avoid " +
                                          "these container lifecycle issues; see @Bean javadoc for complete details.",
                                          beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
            }
            // 真正执行 @Bean 注解标注的方法
            return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
        }
        // 直接去beanFactory中去获取bean
        return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
    }

在执行 factoryMethod.invoke(factoryBean, args)时,就会进入到上述逻辑中。 好了,这就是本文的全部内容。


  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。