Spring版本: 5.3.27
JDK版本: 1.8
1、MyConfig.properties何时被加载解析?
2、MyService中的两个@Value何时解析?
3、MyService中的两个@Value何时注入属性文件中的值?
一、样例
服务类
kotlin
package com.lazy.snail.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @ClassName MyService
* @Description TODO
* @Author lazysnail
* @Date 2024/10/17 11:42
* @Version 1.0
*/
@Service
public class MyService {
@Value("${blog.host}")
private String host;
@Value("${blog.email}")
private String email;
public void printEmail() {
System.out.println(this.email);
}
}
属性配置文件
ini
#MyConfig.properties
blog.host=https://lazysnailstudio.com/
blog.email=lazy_snail@aliyun.com
主配置类
less
@Configuration
@PropertySource(value = "classpath:MyConfig.properties")
@ComponentScan(basePackages = "com.lazy.snail")
public class AppConfig {
}
测试类
java
package com.lazy.snail;
import com.lazy.snail.service.MyService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Slf4j
public class SpringTest {
@Test
void test() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean(MyService.class).printEmail();
}
}
二、样例分析
1、new AnnotationConfigApplicationContext(AppConfig.class)
创建容器、注册内部bean定义信息、注册配置类bean定义信息
refresh之前容器中的bean定义信息:
2、refresh中invokeBeanFactoryPostProcessors
实例化内部bean(ConfigurationClassPostProcessor)
通过postProcessBeanDefinitionRegistry方法解析配置类
处理配置类AppConifg的注解
@PropertySource的处理会加载MyConfig.properties文件,然后解析其中的键值。
@ComponentScan的处理会构建扫描器,对指定包下所有类进行扫描,符合条件的注册到容器。
此案例此处会把MyService注册到容器。
MyService上有@Service注解,@Service注解中有@Component,所以MyService也会被当做配置类进行处理 。走一遍doProcessConfigurationClass方法的逻辑。
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor又继承了BeanFactoryPostProcessor,所以也具有BeanFactoryPostProcessor功能。
postProcessBeanFactory中对符合条件的配置类进行了增强处理。
invokeBeanFactoryPostProcessors结束,容器中有了MyService的bean定义信息、配置文件信息。
bean定义信息:
配置信息:
3、refresh中registerBeanPostProcessors
1、从bean定义信息集合中找到实现了BeanPostProcessor接口的beanDefinition。
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
这两个beanDefinition是最初构造AnnotationConfigApplicationContext时注册到容器的。
2、实例化上述两个后置处理器,然后注册到容器
实例化:
注册:
registerBeanPostProcessors结束,容器中多了两个单例对象,两个后置处理器。
单例:
后置处理器:
4、refresh中finishBeanFactoryInitialization
接下来主要看MyService的实例化过程。
preInstantiateSingletons方法会实例化容器中的单例。
得到MyService的引用后,后置处理器处理。
AutowireAnnotationBeanPostProcessor处理,找到MyService上@Value注解的属性。解析出来后添加到beanDefinition中。
开始给属性赋值
至此关于@Value的解析注入就结束了。
三、小结
1、读取解析配置文件信息,加载到容器待用。
2、实例化过程中,通过后置处理器解析@Value。
3、同样通过后置处理器,找到对应的值,赋值给对应属性。