spring5源码系列---内置的后置处理器PostProcess加载源码 (下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: spring5源码系列---内置的后置处理器PostProcess加载源码

下面我们就来分析上图所示的内容.


1. 对照源码和上图, 我们来看第一次调用

// 第一次, 调用实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors
            // 在所有创世纪的后置处理器中, 只有 internalConfigurationAnnotationProcessor 实现了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered
            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 判断beanFactory是否实现了PriorityOrdered接口. 如果实现了,是最优先调用.
                // 在整个加载过程中,会调用四次BeanDefinitionRegistryPostProcessor, 而实现了PriorityOrdered的接口最先调用
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    // 调用beanFactory.getBean实例化创世界的类ppName
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            /**
             * 第一次调用BeanDefinitionRegistryPostProcessors
             * 在这里典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用于进行bean定义的加载 比如我们的包扫描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 处理完了,清空currentRegistryProcessors
            currentRegistryProcessors.clear();

首先, 拿到了所有实现了BeanDefinitionRegistryPostProcessor的后置处理器, 上面我们做过铺垫,只有ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor后置处理器

所以,这里过滤出来的postProcessorNames只有一个,就是ConfigurationClassPostProcessor, 接下来, 判断这个类是否实现了PriorityOrdered 优先排序的接口, 如果实现了, 那么放入到currentRegistryProcessors中, 后面会进行调用.

接下来, 执行invokeBeanDefinitionRegistryPostProcessors

这是第一次调用BeanDefinitionRegistryPostProcessors

 

2. 第二次调用BeanDefinitionRegistryPostProcessors

// 第二步: 调用实现 Ordered 的 BeanDefinitionRegistryPostProcessors。
            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 这时实现了PriorityOrdered.class的postProcessor就不会再被加载进来了, 因为processedBeans.contains(ppName) == true
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    // 将其放入到currentRegistryProcessors, 马上就要被调用
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            // 对所有的处理器进行排序. 调用了Ordered的方法, 会返回排序(一个数字), 然后根据数字排序即可
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            /**
             * 第二次调用BeanDefinitionRegistryPostProcessors
             * 在这里典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用于进行bean定义的加载 比如我们的包扫描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();


第二次调用的时候 ,依然是获取所有的实现了BeanDefinitionRegistryPostProcessor接口的后置处理器, 且这个处理器没有实现过PriorityOrdered也就是没有被上面调用过. 且实现了Ordered接口


这一类添加到currentRegistryProcessors集合中, 然后调用invokeBeanDefinitionRegistryPostProcessors处理

这是第二次调用BeanDefinitionRegistryPostProcessor

 

3. 第三次调用BeanDefinitionRegistryPostProcessor

// 第三步. 调用没有实现任何优先级接口的 BeanDefinitionRegistryPostProcessor
            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                // 获取
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    // 已处理过的postProcessor不再处理
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                /**
                 * 第三次调用BeanDefinitionRegistryPostProcessors
                 * 在这里典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
                 * 用于进行bean定义的加载 比如我们的包扫描 @import 等
                 */
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }

第三次调用的是没有实现过任何排序接口的后置处理器. 并将其放入到currentRegistryProcessors, 然后执行invokeBeanDefinitionRegistryPostProcessors

 

4. 第四次调用

// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
/*
 * 调用bean工厂的后置处理器
 * registryProcessors: 带有注册功能的bean工厂的后置处理器
 * regularPostProcessors: 不带注册功能的bean工厂的后置处理器
 */
// 调用BeanDefinitionRegistryPostProcessor.postProcessBeanFactory方法----为什么是调用BeanDefinitionRegistryPostProcessor? 因为
// ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 调用BeanFactoryPostProcessor 自设的(ConfigurationClassPostProcessor没有)
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

ConfigurationClassPostProcessor同时实现了BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessors, 调用的是invokeBeanFactoryPostProcessors

 

一共进行了4次调用

总结: 优先处理的是实现了PriorityOrdered的后置处理器, 然后调用实现了Order接口的后置处理器, 最后调用了没有实现任何排序方法的后置处理器. 最后调用工厂类方法.

 

下面我们来具体分析invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

 

5. 提问: 检验一下是否理解了上面四个步骤

 

1. ConfigurationClassPostProcessor会调用1234哪几步?
因为ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor,PriorityOrdered, 因此会调用1,4
2. 如果自己定义了一个MyBeanFactoryPostProcessor会调用1234那几步?
package com.lxl.www.iocbeanlifecicle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
   }
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   }
}
因为MyBeanFactoryPostProcessor是自定义的, 没有实现任何PriorityOrdered 或者 Order, 因此, 会调用3,4

二. 详细研究第四步, invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);的逻辑.



我们在这一步打个断点, 然后跟着断点一步一步点击进去

1187916-20201010174954480-1989800602.png

1187916-20201026101429523-427138642.png

这是registryProcessors里面只有一个后置处理器, 就是ConfigurationClassPostProcessor.


然后进入到ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法

@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);
        if (!this.registriesPostProcessed.contains(factoryId)) {
            // BeanDefinitionRegistryPostProcessor hook apparently not supported...
            // Simply call processConfigurationClasses lazily at this point then.
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }
        // 使用 cglib 配置类进行代理, 因为@Bean方法到时候要进行创建Bean的实例.
        enhanceConfigurationClasses(beanFactory);
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }

这里先看enhanceConfigurationClasses(beanFactory);个方法

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
        Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
            MethodMetadata methodMetadata = null;
            if (beanDef instanceof AnnotatedBeanDefinition) {
                methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
            }
            if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
                // Configuration class (full or lite) or a configuration-derived @Bean method
                // -> resolve bean class at this point...
                AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
                if (!abd.hasBeanClass()) {
                    try {
                        abd.resolveBeanClass(this.beanClassLoader);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException(
                                "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                    }
                }
            }
            /**
             * 只有full版配置才会创建cglib代理
             * full是怎么来的呢? 我们使用@Configuration注解了, 在加载的时候, 就会设置为full
             * 当设置为full以后, 我们在调用的时候, 就会创建一个cglib动态代理.
             *
             * 为什么要创建动态代理呢?
             * 动态代理可以保证, 每次创建的bean对象只有一个
             *
             * 那么加@Configuration和不加本质上的区别是什么?
             * 当在配置类中一个@Bean使用方法的方式引入另一个Bean的时候, 如果不加@Configuration注解, 就会重复加载Bean
             * 如果加了@Configuration, 则会在这里创建一个cglib代理, 当调用了@Bean方法是会先检测容器中是否存在这个Bean, 如果不存在则创建, 存在则直接使用.
             */
            if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
                if (!(beanDef instanceof AbstractBeanDefinition)) {
                    throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                            beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                }
                else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                    logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                            "' since its singleton instance has been created too early. The typical cause " +
                            "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                            "return type: Consider declaring such methods as 'static'.");
                }
                configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
        }
        if (configBeanDefs.isEmpty()) {
            // nothing to enhance -> return immediately
            return;
        }
        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()));
                }
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }

粗体部分就是判断是否需要进行cglib代理. 进行cglib代理的条件是, beanDefinition中属性configurationClass的值是full. 只有full版配置才会创建cglib代理


那么有下面几个问题:


问题1: full版本配置是什么呢?


我们使用@Configuration注解了, 在加载的时候, 就会将configurationClass属性设置为full.当设置为full以后, 我们在调用的时候, 就会创建一个cglib动态代理.


问题2: 为什么要创建动态代理呢?


动态代理可以保证, 每次创建的bean对象只有一个


问题3:那么加@Configuration和不加本质上的区别是什么?


当在配置类中一个@Bean使用方法的方式引入另一个Bean的时候, 如果不加@Configuration注解, 就会重复加载Bean.如果加了@Configuration, 则会在这里创建一个cglib代理, 当调用了@Bean方法是会先检测容器中是否存在这个Bean, 如果不存在则创建, 存在则直接使用.


问题4:full是怎么来的呢?


这是在上面调用invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);接口的时候, 标记的是full还是Lite

下面来看一下源码

1187916-20201029095027764-35349167.png

在这里一步,执行的时候,进行了这个类是full的还是lite,继续忘下看

1187916-20201029095253239-156979304.png

此时满足条件的postProcessor只有一个, 那就是ConfigurationClassPostProcessor. 下面直接看ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法

1187916-20201029095403250-2041177501.png

前面都是一些条件判断, 重点看processConfigBeanDefinitions(registry);

1187916-20201029095449040-29537211.png

在这里,这个方法判断了, 这个类是full的还是lite的. 下面直接上代码

/**
     * Check whether the given bean definition is a candidate for a configuration class
     * (or a nested component class declared within a configuration/component class,
     * to be auto-registered as well), and mark it accordingly.
     * @param beanDef the bean definition to check
     * @param metadataReaderFactory the current factory in use by the caller
     * @return whether the candidate qualifies as (any kind of) configuration class
     */
    public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
        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();
            if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
                    BeanPostProcessor.class.isAssignableFrom(beanClass) ||
                    AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
                    EventListenerFactory.class.isAssignableFrom(beanClass)) {
                return false;
            }
            metadata = AnnotationMetadata.introspect(beanClass);
        }
        else {
            try {
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
                metadata = metadataReader.getAnnotationMetadata();
            }
            catch (IOException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not find class file for introspecting configuration annotations: " +
                            className, ex);
                }
                return false;
            }
        }
        // 判断元数据中是否包含Configuration注解
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        /**
         * 判断, proxyBeanMethods属性是否为true, 如果为true就是一个完全的类,
         * 也就是带有@Configuration注解, 设置Configuration_class属性为full
         *
         * proxyBeanMethods配置类是用来指定@Bean注解标注的方法是否使用代理,
         * 默认是true使用代理,直接从IOC容器之中取得对象;
         * 如果设置为false,也就是不使用注解,每次调用@Bean标注的方法获取到的对象和IOC容器中的都不一样,是一个新的对象,所以我们可以将此属性设置为false来提高性能。
         */
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        // 判断是不是带了@Component, @ComponentScan @Import @ImportResource @Bean注解,
        // 如果带有这几种注解, 就将其Configuration_class属性为lite类型的配置类
        else if (config != null || isConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        else {
            return false;
        }
        // It's a full or lite configuration candidate... Let's determine the order value, if any.
        Integer order = getOrder(metadata);
        if (order != null) {
            beanDef.setAttribute(ORDER_ATTRIBUTE, order);
        }
        return true;
    }

上面主要是获取元数据, 然后判断元数据中是否有Configuration注解. 如果有,返回其属性. 我们判断其属性中proxyBeanMethods是否true, 如果是true, 那么将其设置为full.

如果配置中带有@Component, @ComponentScan @Import @ImportResource @Bean这几种属性之一, 那么就将其设置为lite.

 

问题5: cglib动态代理做了什么事情呢?

不看源码的情况下, 简单可以理解为, 去ioc工厂里面通过getBean("car") 查询了看ioc中是否有这个对象, 如果有就取出来, 不再另创建.


这也是@Configuration 和其他注解类似@Component和@ComponentScan的本质区别:


当在配置类中一个@Bean使用方法的方式引入另一个Bean的时候, 如果不加@Configuration注解, 就会重复创建Bean

如果加了@Configuration, 则会在这里创建一个cglib代理, 当调用了@Bean方法是会先检测容器中是否存在这个Bean, 如果不存在则创建, 存在则直接使用.

 

下面来看个例子

基础类:
public class Car  {
    private String name;
    private Tank tank;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Tank getTank() {
        return tank;
    }
    public void setTank(Tank tank) {
        this.tank = tank;
    }
}
public class Tank {
    private String name;
    public Tank() {
        System.out.println("创建一个tank");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

这是定义的car和tank的基础类

@Configuration
@ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"})
public class MainConfig {
    @Bean("car")
    public Car car() {
        Car car = new Car();
        car.setName("zhangsan");
        // 这里调用了Tank类, tank是通过@Bean注解注入的. 
        car.setTank(tank());
        return car;
    }
    @Bean
    public Tank tank() {
        return new Tank();
    }
}


当配置类使用了@Configuration注解的时候, 运行main方法

public class MainStarter {
    public static void main(String[] args) {
        // 第一步: 通过AnnotationConfigApplicationContext读取一个配置类
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        context.scan("package");
        //context.addBeanFactoryPostProcessor();
        Car car = (Car) context.getBean("car");
        Car car2 = (Car) context.getBean("car");
        System.out.println(car.getName());
        context.close();
    }
}

1187916-20201010183258796-2011379413.png

当去掉@Configuration注解的时候, 再次运行, 我们看到创建了两次tank


//@Configuration
@ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"})
public class MainConfig {
    @Bean("car")
    public Car car() {
        Car car = new Car();
        car.setName("zhangsan");
        // 这里调用了Tank类, tank是通过@Bean注解注入的. 
        car.setTank(tank());
        return car;
    }
    @Bean
    public Tank tank() {
        return new Tank();
    }
}

1187916-20201010183212878-1672712085.png

在main方法中调用了两次(Car) context.getBean("car");


在new一个对象的时候, 如果不取ioc容器中取, 那么每一次都会创建一个新的.

在ioc容器中, car对象只有一个, 但是在构建car的时候, 调用了tank, tank在ioc容器中却不一定只有一份. 只有使用了@Configuration, 表示需要使用cglib动态代理查找tank类, 保证ioc容器中只有一份.

 

7. 详细研究四次调用中的第一次调用.  通过分析跟踪@ComponentScan注解是如何解析的,


通过跟踪@ComponentScan注解是如何解析的, 分来理解BeanDefinitionScan, BeanDefinitionRegistry, BeanDefinitionReader是如何工作的.


public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
        /**
         * 首先,调用BeanDefinitionRegistryPostProcessors 的后置处理器
         * 定义已处理的后置处理器
         */
        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        Set<String> processedBeans = new HashSet<>();
        /**
         * 这里一共分为两大步:
         * 第一步: 调用所有实现了 BeanDefinitionRegistryPostProcessor 接口的bean定义. (BeanDefinitionRegistryPostProcessor带注册功能的后置处理器)
         * 第二步: 调用BeanFactoryPostProcessor Bean工厂的后置处理器
         */
        /**********************第一步: 调用所有实现了BeanDefinitionRegistryPostProcessor接口的bean定义  begin****************************/
        // 判断beanFactory是否实现了BeanDefinitionRegistry, 实现了该结构就有注册和获取Bean定义的能力
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            /**
             * 这是一个集合, 存马上即将要被调用的BeanDefinitionRegistryPostProcessor
             */
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
            // 首先, 调用实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors
            // 在所有创世纪的后置处理器中, 只有 internalConfigurationAnnotationProcessor 实现了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered
            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 判断beanFactory是否实现了PriorityOrdered接口. 如果实现了,是最优先调用.
                // 在整个加载过程中,会调用四次BeanDefinitionRegistryPostProcessor, 而实现了PriorityOrdered的接口最先调用
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    // 调用beanFactory.getBean实例化配置类的后置处理器(创世界的类ppName), 也就是初始化, 实例化, 赋值属性.
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            /**
             * 第一次调用BeanDefinitionRegistryPostProcessors
             * 在这里典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用于进行bean定义的加载 比如我们的包扫描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 处理完了,清空currentRegistryProcessors
            currentRegistryProcessors.clear();

这里也有两大步


第一步: 初始化bean工厂的后置处理器

  通过调用beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class) 初始化了bean工厂的后置处理器,

第二步: 解析配置


   调用invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);调用beanDefinitionRegistry的后置处理器. 筛选出符合条件的配置类.

1187916-20201102064533414-1021070492.png


如上图所示, 最后筛选出的配置类只有MainConfig配置类. 也就是说configCandidates配置候选集合中只有一个MainConfig

// 创建一个ConfigurationClassParser对象, 解析@Configuration class
        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 {
            // 执行解析
            parser.parse(candidates);
            parser.validate();

然后, 接下来创建了一个对象ConfigurationClassParser, 这是一个配置类解析器. 下面将使用这个解析器解析配置类.


重点是如何解析的, 代码已重点标注出来了.


 // 执行解析
parser.parse(candidates);

我们这里是通过注解解析的, 所以直接看下面的代码


public void parse(Set<BeanDefinitionHolder> configCandidates) {
        // 循环配置类
        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 真正的解析bean定义:通过注解元数据解析
                if (bd instanceof AnnotatedBeanDefinition) {
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
......
}

解析主要做了几件事呢?如下图:

1187916-20201102094515412-1548109791.png

解析配置类, 看看配置类是否含有如上标记的注解, 如果有, 则调用响应的返回对其进行解析,处理.


下面来看看源码. 是如何处理这一块的.

/**
     * 在这里会解析@Component  @PropertySources @ComponentScan @ImportResource
     * @param configClass
     * @param sourceClass
     * @param filter
     * @return
     * @throws IOException
     */
    @Nullable
    protected final SourceClass doProcessConfigurationClass(
            ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
            throws IOException {
        // 1. 处理@Component注解,判断元数据是否带有Component注解
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            // Recursively process any member (nested) classes first
            processMemberClasses(configClass, sourceClass, filter);
        }
        // Process any @PropertySource annotations
        // 2. 处理@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
        // 3. 处理@ComponentScan注解, 判断元数据是否带有@ComponentScan注解
        /**
         * 这里mainConfig配置类中有两个注解,一个是@Configuration ,一个是@ComponentScan. 在这里, 我们看一下@ComponentScan
         */
        //componentScans 拿到的就是ComponentScan注解里的属性
        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对象, 并放入到scannedBeanDefinitions中
                // 这正的解析ComponentScans和ComponentScan中的配置
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // 循环处理包扫描出来的bean定义
                // 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());
                    }
                }
            }
        }
        // 4. 处理@Import注解
        // Process any @Import annotations
        processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
        // 5. 处理@ImportResource注解
        // Process any @ImportResource annotations
        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);
            }
        }
        // 6. 处理@Bean注解
        // Process individual @Bean methods
        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
        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;
    }

下面我们重点看对@ComponentScan和@ComponentScans注解的解析, 为什么看他呢? 因为很多注解都标记了@Component注解.


比如@Service注解,本身使用@Component

1187916-20201102100315968-748243465.png


再来看@Controller注解, 其实质也是一个@Component注解

1187916-20201102100409842-34079173.png

我们在自定义配置类的时候, 会使用@ComponentScan注解. 并传递一个包, 作为扫描包. 如MainConfig配置

1187916-20201102100557879-1240756976.png

这就会扫描包下所有的配置类.


它主要的逻辑如下:

1187916-20201102100741941-419788870.png

在拿到@ComponentScan注解以后, 会对其进行parse. 主要解析里面的注解. 并对每一个注解进行处理. 处理后将其添加到scanner属性中. 最后调用scanner.doScan(....)方法.


源码如下:

// 解析配置
    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
        // 定义了一个类路径扫描器ClassPathBeanDefinitionScanner
        // 这里的scanner用于读取配置类
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
        // 1. 判断是否有nameGenerator注解
        // 为扫描器设置beanName的生成器对象, 并赋值给scanner, BeanNameGenerator的作用是为bean definitions生成Bean名字的接口
        Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
        boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
        scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                BeanUtils.instantiateClass(generatorClass));
        // 2. 判断是否有scopedProxy注解
        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"));
        // 3. 判断属性中是否有includeFilters属性, 有的话就添加到scanner中
        // 设置componentScan中包含的过滤器 -- 在使用注解的时候配置了包含和排除的过滤器, 这里进行处理
        for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
            for (TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addIncludeFilter(typeFilter);
            }
        }
        // 4. 判断属性总是否有excludeFilters属性, 有的话放到scnanner中
        // 设置componentScan中排除的过滤器
        for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
            for (TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addExcludeFilter(typeFilter);
            }
        }
        // 5. 判断是否有lazyInit属性
        // 获取配置类中懒加载初始化的属性
        boolean lazyInit = componentScan.getBoolean("lazyInit");
        if (lazyInit) {
            scanner.getBeanDefinitionDefaults().setLazyInit(true);
        }
        Set<String> basePackages = new LinkedHashSet<>();
        // 6. 判断是否有basePackages属性
        // 获取basePackages属性, 也就是我们定义的包扫描路径
        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));
        }
        scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
            @Override
            protected boolean matchClassName(String className) {
                return declaringClass.equals(className);
            }
        });
        // 调用scanner.doScan()方法, 扫描basePackages包
        return scanner.doScan(StringUtils.toStringArray(basePackages));
    }

调用doScan方法扫描配置类. 我们来看看主要做了哪些事情

1187916-20201102121600681-1274078773.png


第一步: 找到所有候选的BeanDefinition.

  上面解析出了@ComponentScan注解传递过来的basePackages包. 扫描包中所有的类, 得到候选类.

  扫描的时候做了几件事呢? 看最上图最右侧部分. 这扫描出来就是我们的目标类.

第二步: 解析这些准目标类.

第三步: 设置默认的beanDefinition属性

/**
     * 设置默认的bean定义的信息
     * Apply the provided default values to this bean.
     * @param defaults the default settings to apply
     * @since 2.5
     */
    public void applyDefaults(BeanDefinitionDefaults defaults) {
        // 设置这个类是不是懒加载的
        Boolean lazyInit = defaults.getLazyInit();
        if (lazyInit != null) {
            setLazyInit(lazyInit);
        }
        // 设置默认的自动装配方式
        setAutowireMode(defaults.getAutowireMode());
        setDependencyCheck(defaults.getDependencyCheck());
        // 设置初始化方法的名称
        setInitMethodName(defaults.getInitMethodName());
        // 是否可以调用InitMethod方法
        setEnforceInitMethod(false);
        setDestroyMethodName(defaults.getDestroyMethodName());
        // 是否可以调用DestroyMethod方法
        setEnforceDestroyMethod(false);
    }

第四步: 将解析出来的bean定义注册到ioc容器中


这里就调用了BeanDefinitionReaderUtils.registerBeanDefinition注册bean定义. 之前注册过配置类, 这里和其是一样的. 所以不再赘述了

 

这里有两个细节:

1. excludeFilter中排除了自己

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
        // 定义了一个类路径扫描器ClassPathBeanDefinitionScanner
        // 这里的scanner用于读取配置类
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
        // 1. 判断是否有nameGenerator注解
        // 为扫描器设置beanName的生成器对象
        Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
        boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
        scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                BeanUtils.instantiateClass(generatorClass));
        // 2. 判断是否有scopedProxy注解
        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"));
        // 3. 判断属性中是否有includeFilters属性, 有的话就添加到scanner中
        // 设置componentScan中包含的过滤器 -- 在使用注解的时候配置了包含和排除的过滤器, 这里进行处理
        for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
            for (TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addIncludeFilter(typeFilter);
            }
        }
        // 4. 判断属性总是否有excludeFilters属性, 有的话放到scnanner中
        // 设置componentScan中排除的过滤器
        for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
            for (TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addExcludeFilter(typeFilter);
            }
        }
        // 5. 判断是否有lazyInit属性
        // 获取配置类中懒加载初始化的属性
        boolean lazyInit = componentScan.getBoolean("lazyInit");
        if (lazyInit) {
            scanner.getBeanDefinitionDefaults().setLazyInit(true);
        }
        Set<String> basePackages = new LinkedHashSet<>();
        // 6. 判断是否有basePackages属性
        // 获取basePackages属性, 也就是我们定义的包扫描路径
        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));
        }
        // 想ExcludeFilter中添加默认的排除类,
        scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
            @Override
            protected boolean matchClassName(String className) {
                /**
                 * declaringClass就是配置类MainConfig, 也就是说. 如果当前类是配置类, 那么就会排除掉
                 * 这是一个钩子方法, 现在不会调用. 后面才调用
                 * 在哪里调用呢?
                  */
                return declaringClass.equals(className);
            }
        });
        // 调用scanner.doScan()方法, 扫描basePackages包
        return scanner.doScan(StringUtils.toStringArray(basePackages));
    }

在解析配置类的时候, 除了@ComponentScan注解中定义的ExcludeFilter和IncludeFilter以外, 还有默认的排除类. 如上加粗字体的部分. 这里是排除了配置类本身, 我们这里的配置类是MainConfig, 也就说, 会排除掉自己.


@Override
            protected boolean matchClassName(String className) {
                /**
                 * declaringClass就是配置类MainConfig, 也就是说. 如果当前类是配置类, 那么就会排除掉
                 * 这是一个钩子方法, 现在不会调用. 后面才调用
                 * 在哪里调用呢? 先记住这个钩子方法matchClassName
                  */
                return declaringClass.equals(className);
            }


matchClassName是一个钩子方法. 在执行到这里的时候, 不会真的去执行. 什么时候执行呢? 后面调用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
            /**
             * 在候选的配置类中, 排除掉了自己, 同时包含了默认的配置类
             */
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

在寻找候选配置类的时候, 进行了排除了配置类本身.

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            // 扫描basePackages, 获取候选类
            return scanCandidateComponents(basePackage);
        }
    }

进入这个方法

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            //第一步:  将com.lxl.www.iocbeanlifecicle转换成了物理路径com/lxl/www/iocbeanlifecicle
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            //第二步:  .getResources(...)读取到了包下所有的类
            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 metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        //第四步:  判断这个类是否是我们要排除的 或者 包含的
                        if (isCandidateComponent(metadataReader)) {
                            // 通过scnner扫描出来的beanDefinition是ScannedGenericBeanDefinition类型
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            // 设置sbd的原类路径
                            sbd.setSource(resource);

在第四步的时候调用了isCandidateComponent(metadataReader, 这里就判断了是否是包含的类,或者是排除的类

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        // 判断这个类类是否是我们设置的要排除的?
        // 这里依然使用到了策略设计模式. TypeFilter是一个父类, 不同子类的TypeFilter会调用不同的match方法
        for (TypeFilter tf : this.excludeFilters) {
            // 在这里面排除类配置类本身
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return false;
            }
        }
        // 判断这个类是否是我们要包含的?
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

紫色加错的部分是就是判读是否符合排除的类. 红色加错的部分是判断是否是包含的类.

先来看紫色的部分, 排除的类

@Override
    public boolean  match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        // This method optimizes avoiding unnecessary creation of ClassReaders
        // as well as visiting over those readers.
        if (matchSelf(metadataReader)) {
            return true;
        }
        ClassMetadata metadata = metadataReader.getClassMetadata();
        // 排除配置类.
        if (matchClassName(metadata.getClassName())) {
            return true;
        }

看到了么, 这里调用了matchClassName. 这就是上面定义的钩子方法,

@Override
            protected boolean matchClassName(String className) {
                /**
                 * declaringClass就是配置类MainConfig, 也就是说. 如果当前类是配置类, 那么就会排除掉
                 * 这是一个钩子方法, 现在不会调用. 后面才调用
                 * 在哪里调用呢? 先记住这个钩子方法matchClassName
                  */
                return declaringClass.equals(className);
            }

此时declaringClass表示的是当前的配置类, className表示的是目标类, 如果当前目标类 == 配置类, 那么就放回true. 返回true, 则会排除掉

 

2. includeFilter中包含了默认的配置类

下面来看红色加错的部分

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        // 判断这个类类是否是我们设置的要排除的?
        // 这里依然使用到了策略设计模式. TypeFilter是一个父类, 不同子类的TypeFilter会调用不同的match方法
        for (TypeFilter tf : this.excludeFilters) {
            // 在这里面排除类配置类本身
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return false;
            }
        }
        // 判断这个类是否是我们要包含的?
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

我们看到这里有this.includeFilters.包含的过滤器. 这里面是有值的

1187916-20201103101834570-943577069.png

我们没有在配置类MainConfig上设置includeFilter啊, 这里面怎么会有值呢?

这是因为我们有默认包含的过滤器, 下面看看默认包含的过滤器是在哪里设置的.

首先从入口类点击AnnotationConfigApplicationContext


1187916-20201103102624962-367941916.png

然后在点击this();

1187916-20201103102735978-1719024113.png


再点击ClassPathBeanDefinitionScanner

1187916-20201103102923238-627311518.png


然后一路点击三个this(...)

1187916-20201103103014232-2033909129.png

最后看到上图 registerDefaultFilter();注册默认的过滤器


@SuppressWarnings("unchecked")
    protected void registerDefaultFilters() {
        // 注册默认的filter---第一个: 在includeFilter中增加了Component
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
        try {
            // 注册默认的filter---第二个:在includeFilter中增加了 javax.annotation.ManagedBean
            this.includeFilters.add(new AnnotationTypeFilter(
                    ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
            logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {
            // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
        }
        try {
            // 注册默认的filter---第三个:在includeFilter中增加了 javax.inject.Named
            this.includeFilters.add(new AnnotationTypeFilter(
                    ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
            logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }

如上图看到, 注册了3个默认的过滤器. 分别是Component, ManagedBean, Named. 他们都是注解类型的过滤器AnnotationTypeFilter

其中javax.annotation.ManagedBean和javax.inject.Named是jdk提供给我们的.

 

到此为止, 就将MainConfig配置类解析完并注册到ioc容器中了.

相关文章
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
124 2
|
3月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
139 5
|
1月前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
2月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
69 2
|
3月前
|
监控 IDE Java
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
172 8
|
3月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
90 9
|
9月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
117 1
|
4月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
231 5
|
4月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
4月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
170 9