spring源码解读 -- @Configuration配置类解析流程详解

本文深入探讨Spring框架如何解析带有@Configuration注解的配置类,详细分析ConfigurationClassPostProcessor的作用及其实现过程,包括解析配置类、注册Bean定义和处理各种注解如@PropertySource、@ComponentScan、@Import等。

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

本次来探讨下spring是如何解析配置类(即添加了@Configuration的类)

一、环境搭建

POM文件依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.szyrm</groupId>
    <artifactId>spring-source</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <spring-version>5.2.5.RELEASE</spring-version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>
    </dependencies>

</project>

二、测试

1、POJO类
package cn.szyrm.spring;

/**
 * 这个类在演示中,我们将会通过用配置
 * 在标注有@Bean方法进行配置
 */
public class Car {
   
   

    private String name;

    public String getName() {
   
   
        return name;
    }

    public void setName(String name) {
   
   
        this.name = name;
    }
}

2、配置类
@Configuration
public class AppConfig {
   
   
    @Bean
    public Car car(){
   
   
        return  new Car();
    }
}

3、启动测试类
public class ApplicationTest {
   
   
    public static void main(String[] args) {
   
   
        ApplicationContext context =  new   AnnotationConfigApplicationContext  (AppConfig.class);
        Car car = context.getBean(Car.class);
        Assert.notNull(car,"容器中未查询到对应bean");
    }
}

4、运行ApplicationTest 类,发现没有异常。说明已经正确配置

三、源码解读

1、一步一步查找源码入口

这里我们既然是查看怎么解析Configuration配置类

  • 1)我们使用全局搜索Configuration.class

    发现有如下地方使用:

在这里插入图片描述

  • 2)、通过上面的搜索,发现是通过org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry,java.lang.Object) 注入到spring中的。

  • 3)、搜索上面方法的调用位置
    在这里插入图片描述

  • 4)、查看具体调用的位置

在这里插入图片描述

  • 5)、追溯到最终调用的位置

在这里插入图片描述

通过上面的分析,我们发现往spring 容器中注册了ConfigurationClassPostProcessor 这个工厂后置处理器,那么我们可以借助IDEA工具来查找spring 具体是什么时候实例这个对象?以及实例化该对象后所做的事情?

  • 6)、ConfigurationClassPostProcessor 类声明上添加断点

  • 7)、以debug模式启动main方法

在这里插入图片描述

这里补充一个知识点,从ConfigurationClassPostProcessor定义可以看出其实现了BeanDefinitionRegistryPostProcessor,那么在初始化完成后,就会调用接口中的相应方法进行处理。下面我们来通过源码进行追踪下。

在这里插入图片描述

8)、postProcessBeanDefinitionRegistry 方法的调用

由于该后置处理器同时实现了PriorityOrdered接口,所有会被最先调用。

在这里插入图片描述

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors 方法就会调用我们要继续调用的方法:org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

在这里插入图片描述

	/**
	 * Derive further bean definitions from the configuration classes in the registry.
	 */
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   
   
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
   
   
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
   
   
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);

		processConfigBeanDefinitions(registry);
	}

9)、postProcessBeanFactory 方法调用

在这里插入图片描述
在这里插入图片描述

2、核心类方法解析

1)、processConfigBeanDefinitions(registry)方法解读
	/**
	 * Build and validate a configuration model based on the registry of
	 * {@link Configuration} classes.
	 */
	public void processConfigBeanDefinitions
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值