Spring-IOC-Bean的声明周期(BeanDefinition阶段)

bean 完整生命周期的 BeanDefinition 阶段,这一阶段主要发生了以下几件事情
1.加载配置文件、配置类
2.解析配置文件、配置类并封装为 BeanDefinition
3.编程式注入额外的 BeanDefinition
4.BeanDefinition 的后置处理

加载xml配置文件

在这里插入图片描述
保存xml配置文件的加载会使用ClassPathXmlApplicationContextsetConfigLocation 方法。
点进入发现调用的是AbstractRefreshabelConfigApplicationContext类中的setConfigLocation方法。将路径存储到数组变量configLocations中。
在这里插入图片描述
在这里插入图片描述
debug发现已经放到xml配置文件路径configLocations中。
在这里插入图片描述

加载配置文件并解析

当执行 ApplicationContext 的 refresh 方法后,会开始刷新(初始化)IOC 容器。加载xml配置文件就发生在下面的2步骤:obtainFreshBeanFactory。

//AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        // 2. 初始化BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        
        // ......
    }
}

1.进入obtainFreshBeanFactory:

//AbstractApplicationContext#obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

方法内两个动作:
1.刷新BeanFactory
2.返回BeanFactory

那么加载和解析就包含在刷新BeanFactory里面。refreshBeanFactory方法是一个抽象方法,目前研究xml配置文件的解析。

2.进入AbstractRefreshableApplicationContext中

//AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
    // 存在BeanFactory则先销毁
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建BeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        customizeBeanFactory(beanFactory);
        // 【1.3】加载配置文件
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    } // catch ......
}

protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
    }

基于 xml 配置文件的 ApplicationContext 可以反复刷新加载 IOC 容器,所以此处有已经存在的判断:如果当前 ApplicationContext 中组合的 BeanFactory 已经存在,则销毁原来的 BeanFactory ,并重新创建。

加载配置文件的动作是loadBeanDefinitions

3.进入loadBeanDefinition方法

loadBeanDefinitions 方法也是一个抽象方法。在AbstractXmlApplicationContext中可以找到对应的实现:

//AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // xml配置文件由XmlBeanDefinitionReader解析
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // 配置上下文环境、资源加载器等
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    initBeanDefinitionReader(beanDefinitionReader);
    // 使用xml解析器 解析xml配置文件
    loadBeanDefinitions(beanDefinitionReader);
}

它内部创建了一个XmlBeanDefinitionReader(Spring框架解析xml文件的核心API)。最后把这个XmlBeanDefinitionReader作为参数传入重载的loadBeanDefinitions方法:

//AbstractXmlApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        // 【1.4】加载配置文件资源路径的xml配置文件
        reader.loadBeanDefinitions(configLocations);
    }
}

这里面的逻辑分两部分:
1.处理已经加载好的现成的Resource(Spring的资源模型,代表文件或者类的资源)
2…处理制定好的配置文件资源路径

Debug 至此处,同样也能发现 reader 与 configLocations 都准备好了:
在这里插入图片描述
在这里插入图片描述

4.XmlBeanDefinitionReader加载配置文件

测试代码没有指定Resource,进入loadBeanDefinitions(configLocations)

//AbstractBeanDefinitionReader
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    // assert ......
    int count = 0;
    for (String location : locations) {
        count += loadBeanDefinitions(location);
    }
    return count;
}

可以看到,这个方法是循环遍历资源文件路径,进行解析。

5.进入AbstractBeanDefinitionReader类的loadBeanDefinitions

//AbstractBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(location, null);
}

//AbstractBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
        // throw ex ......
    }

    if (resourceLoader instanceof ResourcePatternResolver) {
        try {
            // 根据传入的路径规则,匹配所有符合的xml配置文件
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            int count = loadBeanDefinitions(resources);
            if (actualResources != null) {
                Collections.addAll(actualResources, resources);
            }
            // logger ......
            return count;
        } // catch ......
    }
    else {
        // 每次只能解析一个xml配置文件
        Resource resource = resourceLoader.getResource(location);
        // 【解析】
        int count = loadBeanDefinitions(resource);
        if (actualResources != null) {
            actualResources.add(resource);
        }
        // logger ......
        return count;
    }
}

这个方法中的2个核心步骤:
1.根据传入的资源路径,获取xml配置文件资源对象
2.解析xml配置文件

//XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
}

//XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    // assert logger ......
    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (!currentResources.add(encodedResource)) {
        // throw ex ......
    }

    try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
        InputSource inputSource = new InputSource(inputStream);
        if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
        }
        // 【真正干活的】
        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    } // catch ......
    finally {
        currentResources.remove(encodedResource);
        if (currentResources.isEmpty()) {
            this.resourcesCurrentlyBeingLoaded.remove();
        }
    }
}

InputSource:XML实体的单个输入源。
InputSource对象属于应用程序:SAX解析器。

6.进入doLoadBeanDefinitions

//XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
    try {
        Document doc = doLoadDocument(inputSource, resource);
        int count = registerBeanDefinitions(doc, resource);
        // logger ......
        return count;
    } // catch ......
}

这个方法的两个核心步骤:
1.将xml输入流转换为Document(文档对象)
2.解析文档对象并注册BeaDefinitions对象。

7.进入registerBeanDefinitions 方法。

//XmlBeanDefinitionReader#doLoadBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 【解析】
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

此处构建了一个DefaultBeanDefinitionDocumentReader ,调用它的registerBeanDefinitions 方法。

//DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    doRegisterBeanDefinitions(doc.getDocumentElement());
}

//DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        // 取<beans>上的profile属性
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                // logger ......
                return;
            }
        }
    }

    preProcessXml(root);
    // 【解析xml】
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}

这块代码先把 xml 配置文件中声明的 profile 取出来,并根据 Environment 中配置好的 profile 决定是否继续解析( profile 的过滤)

接下来,后面就是 xml 配置文件的解析动作了,在这前后有一个预处理和后处理动作,不过默认情况下这里是没有实现的(模板方法罢了),所以我们只需要看 parseBeanDefinitions 就可以。

8.进入parseBeanDefinitions 解析

//DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                // 解析<beans>中的元素
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 解析其它命名空间中的元素
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}

Spring 如何解析 xml ,我们不关心,但是如何从解析完的 xml 中获取关键信息,以及封装 BeanDefinition ,这才是我们要关注的。

在这里插入图片描述
OK ,继续回到源码,源码中可以看到,每次循环出来的 Node 都会尝试着转成 Element 去解析,而解析的动作主要是 parseDefaultElement ,它会解析 标签下的 xml 元素。

//DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

这里它会解析 <import> 标签、<alias> 标签、<bean> 标签,以及递归解析嵌套的 <beans> 标签!

9.processBeanDefinition-解析<bean>标签

//DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 解析xml元素为BeanDefinition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 解析<bean>中嵌套的自定义标签
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // BeanDefinition注册到BeanDefinitionRegistry
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        } // catch ......
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

第一个步骤会把 xml 元素封装为 BeanDefinitionHolder(内部组合了一个BeanDefiniton)

//BeanDefinitionParserDelegate#parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}

//BeanDefinitionParserDelegate#parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    // 取出bean的id
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 取出bean的name
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    // 取出bean的alias
    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
    // 如果没有给bean赋name,则第一个alias视为name
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        // logger ......
    }

    // 检查bean的name是否有重复
    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }

    // 解析其余的bean标签元素属性
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        // 如果没有给bean赋name,且没有alias,则生成默认的name
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                } else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null &&
                            beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                            !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
                // logger ......
            } // catch ......
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

只有 id 和 name ,class 呢?scope 呢?lazy-init 呢?莫慌,看到中间还有一个封装好的 parseBeanDefinitionElement 方法了.

10.parseBeanDefinitionElement

//BeanDefinitionParserDelegate#parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement(
        Element ele, String beanName, @Nullable BeanDefinition containingBean) {
    this.parseState.push(new BeanEntry(beanName));

    // 解析class的全限定名
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    // 解析parent的definition名称
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }

    try {
        // 构造BeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);

        // 解析其余的<bean>标签属性
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

        // 解析property属性
        parseMetaElements(ele, bd);
        // 解析其它的属性 ......

        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));

        return bd;
    } // catch finally ......

    return null;
}

调用 createBeanDefinition 方法创建了一个 BeanDefinition。之后把 <bean> 标签中的其它属性、<bean> 的子标签的内容都封装起来,而封装 <bean> 其它属性的 parseBeanDefinitionAttributes 方法中,已经把这些内容都解析到位了

//BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
  public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
        if (ele.hasAttribute("singleton")) {
            this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
        } else if (ele.hasAttribute("scope")) {
            bd.setScope(ele.getAttribute("scope"));
        } else if (containingBean != null) {
            bd.setScope(containingBean.getScope());
        }

        if (ele.hasAttribute("abstract")) {
            bd.setAbstract("true".equals(ele.getAttribute("abstract")));
        }

        String lazyInit = ele.getAttribute("lazy-init");
        if (this.isDefaultValue(lazyInit)) {
            lazyInit = this.defaults.getLazyInit();
        }

        bd.setLazyInit("true".equals(lazyInit));
        String autowire = ele.getAttribute("autowire");
        bd.setAutowireMode(this.getAutowireMode(autowire));
        String autowireCandidate;
        if (ele.hasAttribute("depends-on")) {
            autowireCandidate = ele.getAttribute("depends-on");
            bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
        }

        autowireCandidate = ele.getAttribute("autowire-candidate");
        String destroyMethodName;
        if (this.isDefaultValue(autowireCandidate)) {
            destroyMethodName = this.defaults.getAutowireCandidates();
            if (destroyMethodName != null) {
                String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
            }
        } else {
            bd.setAutowireCandidate("true".equals(autowireCandidate));
        }

        if (ele.hasAttribute("primary")) {
            bd.setPrimary("true".equals(ele.getAttribute("primary")));
        }

        if (ele.hasAttribute("init-method")) {
            destroyMethodName = ele.getAttribute("init-method");
            bd.setInitMethodName(destroyMethodName);
        } else if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }

        if (ele.hasAttribute("destroy-method")) {
            destroyMethodName = ele.getAttribute("destroy-method");
            bd.setDestroyMethodName(destroyMethodName);
        } else if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }

        if (ele.hasAttribute("factory-method")) {
            bd.setFactoryMethodName(ele.getAttribute("factory-method"));
        }

        if (ele.hasAttribute("factory-bean")) {
            bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
        }

        return bd;
    }

xml 配置文件中的 标签就可以转换为 BeanDefinition 了。

BeanDefinitionHolder的意义

它是持有 BeanDefinition 的一个包装而已,不过它除了持有之外,还包含了另外的重要信息:bean 的名称

public class BeanDefinitionHolder implements BeanMetadataElement {

	private final BeanDefinition beanDefinition;

	private final String beanName;

	@Nullable
	private final String[] aliases;

总结:

首先 ClassPathXmlApplicationContextrefresh 之前,会指定传入的 xml 配置文件的路径,执行 refresh 方法时,会初始化 BeanFactory ,触发 xml 配置文件的读取、加载和解析。其中 xml 的读取需要借助 XmlBeanDefinitionReader ,解析 xml 配置文件则使用 DefaultBeanDefinitionDocumentReader ,最终解析 xml 中的元素,封装出 BeanDefinition ,最后注册到 BeanDefinitionRegistry

加载注解配置类

注解配置类的加载时机会晚一些,它用到了一个至关重要的 BeanDefinitionRegistryPostProcessor 。而且无论如何,这个后置处理器都是最最优先执行的,它就是 ConfigurationClassPostProcessor

BeanDefinitionRegistryPostProcessor的调用时机

这次我们要看的是 BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor 的执行时机,而它们的执行都在下面所示的第 5 步 invokeBeanFactoryPostProcessors 中执行:

//AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // ......
        try {
           //web环境下重写这个方法
            postProcessBeanFactory(beanFactory);
            // 5. 执行BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);
            registerBeanPostProcessors(beanFactory);
            // ......
        }
        // catch finally .....
    }
}

进来这个方法,发现核心的方法就一句话:

//AbstractApplicationContext
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors;

//AbstractApplicationContext#invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 交给代理执行
   //getBeanFactoryPostProcessors()返回一个List<BeanFactoryPostProcessor>集合
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // 下面是支持AOP的部分(暂时不读)
}

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
        Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
        this.beanFactoryPostProcessors.add(postProcessor);
    }

    public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
        return this.beanFactoryPostProcessors;
    }

它又是交给一个 Delegate 执行。

PostProcessorRegistrationDelegate的实现

invokeBeanFactoryPostProcessors 方法的篇幅实在太长了,只截取关键的部分。

//PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    Set<String> processedBeans = new HashSet<>();

    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        // 该部分会将BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor分离开
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                regularPostProcessors.add(postProcessor);
            }
        }
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // 首先,执行实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 接下来,执行实现了Ordered接口的BeanDefinitionRegistryPostProcessors
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 最后,执行所有其他BeanDefinitionRegistryPostProcessor
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
        }

        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    else {
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // 执行BeanFactoryPostProcessor ......
}

逻辑梳理
1.先处理BeanDefinitionRegistryPostProcessor

2.定义两个集合分别收集BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor

3…将编程注入(ApplicationContext调用addBeanFactoryPostProcessor方法增加的后置处理器)BeanFactoryPostProcessor集合遍历,执行BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry方法。将后置处理器分别放到不同的集合中。

4.遍历beanDefinitionNames集合中(DefaultListableBeanFactory中定义的集合属性),找到类型是BeanDefinitionRegistryPostProcessorbeanDefinitionNames。处理实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors。
(1)getBean方法根据beandefinition创建后置处理器对象。
(2)排序这些BeanDefinitionRegistryPostProcessors后置处理器。
(3)调用BeanDefinitionRegistryPostProcessorspostProcessBeanDefinitionRegistry方法。

5.逻辑和4类似。处理实现Order接口的BeanDefinitionRegistryPostProcessors后置处理器。

6.处理普通的BeanDefinitionRegistryPostProcessor后置处理器。普通的beanDefinitonRegistryPostProcessor(postProcessBeanDefinitionRegistry方法调用)处理完后。
(1)调用收集beanDefinitonRegistryPostProcessor集合中所有后置处理器的postProcessBeanFactory方法。
(2)调用收集beanFactoryPostProcessor集合中所有后置处理器的postProcessBeanFactory方法。

7.处理BeanFactoryPostProcessor。逻辑同上。

ConfigurationClassPostProcessor的处理

ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口。
在这里插入图片描述

直接定位到 postProcessBeanDefinitionRegistry 方法吧:

//ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    int registryId = System.identityHashCode(registry);
    // check throw ex ......
    this.registriesPostProcessed.add(registryId);

    // 【解析配置类】
    processConfigBeanDefinitions(registry);
}

可以发现,在这个方法的最后一行,就是解析配置类中定义的 bean ,并封装为 BeanDefinition 。

进入processConfigBeanDefinitions 方法

//ConfigurationClassPostProcessor#processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    // 筛选出所有的配置类
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
     
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            // logger ......
        } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // Return immediately if no @Configuration classes were found
    if (configCandidates.isEmpty()) {
        return;
    }

    // 配置类排序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // 构造默认的BeanNameGenerator bean的名称生成器
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // 真正解析配置类的组件:ConfigurationClassParser
    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();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);

        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // 【加载配置类的内容】
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
        
        // 一些额外的处理动作
    }
    while (!candidates.isEmpty());

    // 一些额外的处理 ......
}

它初始化了一个 ConfigurationClassParser ,这个家伙是用来解析注解配置类的核心 API 。

ConfigurationClassParser#parse – 解析注解配置类

//ConfigurationClassParser#parse
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            // 注解配置类
            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 ......
    }
    
    // 回调特殊的ImportSelector
    this.deferredImportSelectorHandler.process();
}

整体看一下这个方法,它会把配置类的全限定名拿出来,扔进重载的 parse 方法中(注意无论是执行 if-else-if 的哪个分支,最终都是执行重载的 parse 方法);or 循环调用完成后,最底下会让 deferredImportSelectorHandler 执行 process 方法。

deferredImportSelectorHandlerImportSelector接口的扩展。它的执行时机比 ImportSelector 更晚,它会在注解配置类的所有解析工作完成后才执行。
进入deferredImportSelectorHandler的处理逻辑:

public void process() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    try {
        if (deferredImports != null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
            deferredImports.forEach(handler::register);
            handler.processGroupImports();
        }
    }
    finally {
        this.deferredImportSelectors = new ArrayList<>();
    }
}

它会取出所有解析中存储好的 DeferredImportSelector ,并依次执行。由于 DeferredImportSelector 的执行时机比较晚,对于 @Conditional 条件装配的处理也会更有利,所以这个设计还是不错的。

parse解析配置类

上面的 ConfigurationClassParser 中最终都会把配置类传入重载的 parse 方法中,参数类型注意是 ConfigurationClass

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        // 如果配置类已经被@Import过了,则跳过
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
                existingClass.mergeImportedBy(configClass);
            }
            return;
        }
        else {
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }

    SourceClass sourceClass = asSourceClass(configClass);
    do {
        // 【真正干活的】
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    this.configurationClasses.put(configClass, configClass);
}

doProcessConfigurationClass - 解析配置类

处理@Component注解

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {

    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        processMemberClasses(configClass, sourceClass);
    }
    // ........

它就会判断这个类是否有标注 @Component 注解。因为所有的 @Configuration 类必定是 @Component ,所以该逻辑必进。而内部执行的 processMemberClasses 方法如下:

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
        Predicate<String> filter) throws IOException {
    // 获取配置类中的所有内部类
    Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
    if (!memberClasses.isEmpty()) {
        List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
        // 循环解析内部类
        for (SourceClass memberClass : memberClasses) {
            // 如果内部类也是配置类,则它们也会被解析
            if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
                    !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
                candidates.add(memberClass);
            }
        }
        OrderComparator.sort(candidates);
        for (SourceClass candidate : candidates) {
            // 防止循环@Import的处理:如果两个配置类互相@Import,则视为错误
            if (this.importStack.contains(configClass)) {
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
            } else {
                this.importStack.push(configClass);
                try {
                    // 递归解析内部的配置类
                    processConfigurationClass(candidate.asConfigClass(configClass), filter);
                }
                finally {
                    this.importStack.pop();
                }
            }
        }
    }
}

这个方法是处理内部类的啊,而且还是递归处理。

处理@PropertySource注解

   // ............
    // Process any @PropertySource annotations
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        }
        // else logger ......
    }
    // ............

接下来是处理 @PropertySource 注解了,可以发现借助 AnnotationConfigUtils 可以很容易的取出配置类上标注的所有注解信息,然后筛选出指定的注解属性即可。而内部的 processPropertySource 方法就在真正的封装 PropertySource 导入的资源文件:

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
    // 解析@PropertySource注解的属性
    String name = propertySource.getString("name");
    if (!StringUtils.hasLength(name)) {
        name = null;
    }
    String encoding = propertySource.getString("encoding");
    if (!StringUtils.hasLength(encoding)) {
        encoding = null;
    }
    String[] locations = propertySource.getStringArray("value");
    // ......

    for (String location : locations) {
        try {
            // 处理路径,加载资源文件,并添加进Environment中
            String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
            Resource resource = this.resourceLoader.getResource(resolvedLocation);
            addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
        } // catch ......
    }
}

前面的一大堆操作都是拿 @PropertySource 的一些属性等等,最后的 for 循环中才是封装资源文件,存放进 Environment 的部分。

处理@ComponentScan注解

  // ............
    // Process any @ComponentScan annotations
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        // 如果有@ComponentScans,则要取出里面所有的@ComponentScan依次扫描
        for (AnnotationAttributes componentScan : componentScans) {
            // 【复杂】借助ComponentScanAnnotationParser扫描
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 是否扫描到了其它的注解配置类
            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());
                }
            }
        }
    }
    // ............

中间的部分,它使用 ComponentScanAnnotationParser 来委托处理包扫描的工作,
ComponentScanAnnotationParser 的 parse 方法中,看一看内部的实现:最开始就创建了ClassPathBeanDefinitionScanner对象。

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    // 构造ClassPathBeanDefinitionScanner
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    // 解析@ComponentScan中的属性 ......
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");

    // 整理要扫描的basePackages
    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));
    }
    // 没有声明basePackages,则当前配置类所在的包即为根包
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    // ......
    // 【扫描】执行包扫描动作
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

1.构造 ClassPathBeanDefinitionScanner ,并封装 @ComponentScan 注解中的属性
2.整理要进行包扫描的 basePackages ,以及 include 和 exclude 的过滤器
3.执行包扫描的动作

真正的包扫描那还得看 ClassPathBeanDefinitionScanner :

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    // assert ......
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 【真正的包扫描动作在这里】
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            // 处理scope(默认情况下是singleton)
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 生成bean的名称
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            // 处理bean中的@Lazy、@Primary等注解
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 设置AOP相关的属性(如果支持的话)
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 注册进BeanDefinitionRegistry
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

从上往下的逻辑条理还是很清晰的,只要扫描到了符合的类(默认被 @Component 注解标注的类),就会包装为 BeanDefinition ,然后对这些 BeanDefinition 进行一些额外的处理,最终注册进 BeanDefinitionRegistry 。

findCandidateComponents 方法:

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    } else {
        return scanCandidateComponents(basePackage);
    }
}

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        // 此处可处理 [/**/service/*Service.class] 这样的表达式
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        for (Resource resource : resources) {
            if (resource.isReadable()) {
                try {
                    // 加载.class字节码
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    // 如果符合匹配规则,则封装为ScannedGenericBeanDefinition
                    if (isCandidateComponent(metadataReader)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            candidates.add(sbd);
                        }
                    }
                } // catch .......
            }
        }
    } // catch ......
    return candidates;
}

它会将带有通配符的 Ant 风格(诸如 /xxx/**/*.class )的路径解析出来,并加载到对应的类,封装为 ScannedGenericBeanDefinition ,完事。

处理@Import注解

 // ............
    // Process any @Import annotations
    processImports(configClass, sourceClass, getImports(sourceClass), true);
    // ............

就一句话啊,那咱直接点进去:

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
        Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
        boolean checkForCircularImports) {

    if (importCandidates.isEmpty()) {
        return;
    }
    // 防止循环@Import导入
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        this.importStack.push(configClass);
        try {
            for (SourceClass candidate : importCandidates) {
                // 处理ImportSelector
                if (candidate.isAssignable(ImportSelector.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                            this.environment, this.resourceLoader, this.registry);
                    Predicate<String> selectorFilter = selector.getExclusionFilter();
                    if (selectorFilter != null) {
                        exclusionFilter = exclusionFilter.or(selectorFilter);
                    }
                    // DeferredImportSelector的执行时机后延
                    if (selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    } else {
                        // 执行ImportSelector的selectImports方法,并注册导入的类
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                }
                // 处理ImportBeanDefinitionRegistrar
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                            ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                    this.environment, this.resourceLoader, this.registry);
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                    // 导入普通类 / 配置类
                    this.importStack.registerImport(
                            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                }
            }
        } // catch ......
        finally {
            this.importStack.pop();
        }
    }
}

整体逻辑非常有序,它分别对 ImportSelector 、ImportBeanDefinitionRegistrar 、普通类 / 配置类都做了处理,并递归解析其中存在的配置类。

处理@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);
        }
    }
    // ............

@ImportResource 可以导入 xml 配置文件,而解析这些 @ImportResource 的逻辑就在这里。

处理@Bean注解

   // ............
    // Process individual @Bean methods
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }
    // ............

合着 @Bean 的处理也只是存起来。它是如何把这些 @Bean 方法都拿出来的,我们还得去看看 retrieveBeanMethodMetadata 方法:

private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
    AnnotationMetadata original = sourceClass.getMetadata();
    // 获取被@Bean注解标注的方法
    Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
    if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
        try {
            AnnotationMetadata asm =
                    this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
            Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
            if (asmMethods.size() >= beanMethods.size()) {
                Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
                // 筛选每个方法
                for (MethodMetadata asmMethod : asmMethods) {
                    for (MethodMetadata beanMethod : beanMethods) {
                        if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
                            selectedMethods.add(beanMethod);
                            break;
                        }
                    }
                }
                if (selectedMethods.size() == beanMethods.size()) {
                    beanMethods = selectedMethods;
                }
            }
        } // catch ......
    }
    return beanMethods;
}

这里 Spring 使用 ASM 读取字节码的目的,是为了保证加载配置类中 @Bean 方法的从上到下的顺序与源文件 .java 中一致

处理父接口

 // ............
    // Process default methods on interfaces
    processInterfaces(configClass, sourceClass);
    // .......
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    for (SourceClass ifc : sourceClass.getInterfaces()) {
        // 寻找接口中标注了@Bean的方法
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
        for (MethodMetadata methodMetadata : beanMethods) {
            if (!methodMetadata.isAbstract()) {
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }
        }
        processInterfaces(configClass, ifc);
    }
}

它会把配置类实现的所有接口都拿出来,并且遍历所有标注了 @Bean 的方法,并添加到 bean 的注册信息中。跟上面一样,它只是存起来,并没有封装为 BeanDefinition ,所以这里只是解析动作而已。

loadBeanDefinitions - 加载BeanDefinition

到这里,配置类的解析就完成了,回到 ConfigurationClassPostProcessor 中,解析完那些 @Bean 后还要注册为 BeanDefinition 呢,而这个方法的核心在 loadBeanDefinitions 中。
this.reader.loadBeanDefinitions(configClasses); 的执行会来到 ConfigurationClassBeanDefinitionReader 中:

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    for (ConfigurationClass configClass : configurationModel) {
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}
private void loadBeanDefinitionsForConfigurationClass(
        ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    // 与条件装配有关
    if (trackedConditionEvaluator.shouldSkip(configClass)) {
        String beanName = configClass.getBeanName();
        if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
            this.registry.removeBeanDefinition(beanName);
        }
        this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        return;
    }

    // 如果当前配置类是被@Import的,要把自己注册进BeanFactory
    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    // 注册@Bean注解方法
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    // 注册来自xml配置文件的bean
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    // 注册来自ImportBeanDefinitionRegistrar的bean
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();
    String methodName = metadata.getMethodName();

    // 如果条件装配将其跳过,则该@Bean标注的方法,对应的BeanDefinition不会注册进BeanDefinitionRegistry
    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 ......

    // 如果bean指定了多个name,则第1个为唯一标识,其余的都是alias别名
    List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
    String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
    // Register aliases even when overridden
    for (String alias : names) {
        this.registry.registerAlias(beanName, alias);
    }

    // 注解中配置了@Bean,与xml中的bean撞车了,会抛出异常
    if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
        if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
            // throw ex ......
        }
        return;
    }

    // 构造BeanDefinition
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    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
        beanDef.setFactoryBeanName(configClass.getBeanName());
        beanDef.setUniqueFactoryMethodName(methodName);
    }

    // 处理@Bean的属性(name、initMethod等)、额外的注解(@Lazy、@DependsOn等) ......

    // 注册进BeanDefinitionRegistry
    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

一样标准的套路:检查 → 构造 BeanDefinition → 封装信息 → 注册进 BeanDefinitionRegistry 。

metadata.isStatic() ,它的判断逻辑下面,会给 BeanDefinition 封装两个属性:setBeanClassName / setFactoryBeanName 、setUniqueFactoryMethodName ,它们俩分别指定了当前 @Bean 方法所在的配置类,以及方法名。

前面 @Component 注解标注的类形成的 BeanDefinition ,以及 xml 配置文件转换出来的 BeanDefinition 有个什么特点?它们都指定了 bean 的全限定名、属性注入等,而且最终创建的对象一定是通过反射创建。而在注解配置类中的 @Bean 方法是有实际的代码执行,属于编程式创建,无法使用(也不适合用)反射创建 bean 对象,所以为了在后面能正常创建出 bean 对象,此处就需要记录该 bean 的定义源(包含注解配置类和方法名),以保证在创建 bean 对象时,能够使用反射调用该注解配置类的方法,生成 bean 对象并返回

loadBeanDefinitionsFromImportedResources

这部分是解析从注解配置类上取到的 xml 配置文件的路径,有了前面的分析,我们马上就能猜到,它又要用 XmlBeanDefinitionReader 那一套来搞了,点开源码,发现果然如此:

private void loadBeanDefinitionsFromImportedResources(
        Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

    Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();

    importedResources.forEach((resource, readerClass) -> {
        if (BeanDefinitionReader.class == readerClass) {
            if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
                readerClass = GroovyBeanDefinitionReader.class;
            }
            else {
                // 创建XmlBeanDefinitionReader,以备下面的解析
                readerClass = XmlBeanDefinitionReader.class;
            }
        }

        BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
        // reader的缓存等等

        // 调用XmlBeanDefinitionReader解析资源文件
        reader.loadBeanDefinitions(resource);
    });
}

loadBeanDefinitionsFromRegistrars

最后一部分是执行 ImportBeanDefinitionRegistrar ,这个就更简单了,既然是接口,那执行它们的话,只需要调用 registerBeanDefinitions 方法就可以吧,进到方法内部,发现真就是这么简单:

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    registrars.forEach((registrar, metadata) ->
            registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

总结

  注解配置类的解析发生在 BeanDefinitionRegistryPostProcessor 的执行阶段,它对应的核心后置处理器是 ConfigurationClassPostProcessor

  它主要负责两个步骤三件事情:
   1.解析配置类
   2.注册 BeanDefinition 。

  三件事情包括:
   1) 解析 @ComponentScan 并进行包扫描,实际进行包扫描的组件是 ClassPathBeanDefinitionScanner ;
   2) 解析配置类中的注解(如 @Import 、@ImportResource 、@PropertySource 等)并处理,工作的核心组件是 ConfigurationClassParser ;
   3) 解析配置类中的 @Bean 并封装 BeanDefinition ,实际解析的组件是 ConfigurationClassBeanDefinitionReader 。

BeanDefinition的后置处理

BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 的执行,而它们的执行时机还是上面的。

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法中。

执行完这些后置处理器之后,BeanDefinition 的后置处理也就算结束了。

BeanDefinition部分的生命周期

首先,bean 的生命周期分为 BeanDefinition 阶段和 bean 实例阶段。
BeanDefinition 阶段分为加载 xml 配置文件、解析注解配置类、编程式构造 BeanDefinition 、BeanDefinition 的后置处理,一共四个部分
1.加载 xml 配置文件 发生在基于 xml 配置文件的 ApplicationContext 中 refresh 方法的 BeanFactory 初始化阶段,此时 BeanFactory 刚刚构建完成,它会借助 XmlBeanDefinitionReader 来加载 xml 配置文件,并使用 DefaultBeanDefinitionDocumentReader 解析 xml 配置文件,封装声明的 <bean> 标签内容并转换为 BeanDefinition

2.解析注解配置类 发生在 ApplicationContext 中 refresh 方法的 BeanDefinitionRegistryPostProcessor 执行阶段,该阶段首先会执行 ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry 方法。ConfigurationClassPostProcessor 中会找出所有的配置类,排序后依次解析,并借助 ClassPathBeanDefinitionScanner 实现包扫描的 BeanDefinition 封装,借助 ConfigurationClassBeanDefinitionReader 实现 @Bean 注解方法的 BeanDefinition 解析和封装。

3.编程式构造 BeanDefinition 也是发生在 ApplicationContext 中 refresh 方法的 BeanDefinitionRegistryPostProcessor 执行阶段,由于 BeanDefinitionRegistryPostProcessor 中包含 ConfigurationClassPostProcessor ,而 ConfigurationClassPostProcessor 会执行 ImportBeanDefinitionRegistrar 的逻辑,从而达到编程式构造 BeanDefinition 并注入到 BeanDefinitionRegistry 的目的;另外,实现了 BeanDefinitionRegistryPostProcessor 的类也可以编程式构造 BeanDefinition ,注入 BeanDefinitionRegistry

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值