Spring源码解析之|Spring源码解析之 ——ConfigurationClassPostProcessor
Spring源码解析之 ——ConfigurationClassPostProcessor
思考:(1) @Configuration,@Component,@Bean,@Import 注解的作用是什么? 什么时候被解析的。
这里就ConfigurationClassPostProcessor就上场了先看张图,这个就是ConfigurationClassPostProcessor处理的构建节点。ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,
而BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,所以 ConfigurationClassPostProcessor 中需要重写postProcessBeanDefinitionRegistry()
方法和postProcessBeanFactory()方法。而ConfigurationClassPostProcessor类的作用就是通过这两个方法去实现的。
文章图片
ConfigurationClassPostProcessor做些什么?1:postProcessBeanDefinitionRegistry()将@Configuration,@Component,@Bean,@Import等注解的对象,解析为BeanDefinition,放在容器中,等待被解析为Spring bean;
这里会将@Configuration注解的类的BeanDefinition添加个属性,标记是FULL,还是LITE
2:postProcessBeanFactory()被标记FULL的BeanDefinition的beanClass替换为Cglib代理的class名
processConfigBeanDefinitions()代码解析
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//.....省略// 将候选者进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}if (this.environment == null) {
this.environment = new StandardEnvironment();
}//创建@Configuration解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set candidates = new LinkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
// 注意:这一步只会将加了@Configuration注解以及通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap中
// 通过其他注解(例如@Import、@Bean)的方式,在parse()方法这一步并不会将其解析为BeanDefinition放入到BeanDefinitionMap中,
// 而是先解析成ConfigurationClass类
// 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的
parser.parse(candidates);
parser.validate();
Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 将上一步parser解析出的ConfigurationClass类加载成BeanDefinition
// 实际上经过上一步的parse()后,解析出来的bean已经放入到BeanDefinition中了,但是由于这些bean可能会引入新的bean,例如实现了ImportBeanDefinitionRegistrar或者ImportSelector接口的bean,或者bean中存在被@Bean注解的方法
// 因此需要执行一次loadBeanDefinition(),这样就会执行ImportBeanDefinitionRegistrar或者ImportSelector接口的方法或者@Bean注释的方法
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
candidates.clear();
//....省略代码
}
while (!candidates.isEmpty());
//.....省略代码
}
1.parser.parse() 根据BeanDefinition类型的不同,调用parse()不同的重载方法。实际是调用ConfigurationClassParser中的processConfigurationClass()方法
parse()具体代码
public void parse(Set 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 (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}this.deferredImportSelectorHandler.process();
}
processConfigurationClass()方法中实际解析的方法为doProcessConfigurationClass()方法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate filter) throws IOException {
//.....省略代码SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass()方法中就开始了Spring一些注解的解析
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
throws IOException {//解析@Component注解的类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
//遍历被注解类的内部类,这个也是为什么一些内部类一样会被spring获取到的原因
processMemberClasses(configClass, sourceClass, filter);
}// 解析@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");
}
}// 解析@ComponentScans , @ComponentScan注解
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
//解析@ComponentScans , @ComponentScan扫描包下的@Component,@Service,@Controller,@Repository注解。
//将扫描出来的类转为bd添加到beanDefinitionMap中
Set scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//对@Configuration注解进行特殊处理
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
//checkConfigurationClassCandidate给@Configuration注解的类打上FULL标记
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}//解析Import注解注册的bean,这一步只会将import注册的bean变为ConfigurationClass,不会变成BeanDefinition
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//引入配置文件
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);
}
}// 解析@Bean注解
Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//......省略代码
// No superclass -> processing is complete
return null;
}
componentScanParser.parse()在扫描时会通过includeFilters和excludeFilters条件去决定具体扫描的bean,但是实际includeFilters中只有
@Component注解,但是实际中扫描的到的bean,也会将@Service,@Controller,@Repository,@Controller都会被扫描出来。
文章图片
这里大概是@Component元注解,Spring在读取@Service,@Controller,@Repository,@Controller,也读取了它的元注解,并将作为@Component处理。这里就不做具体分析了。
2.this.reader.loadBeanDefinitions() 在执行parse()方法后@Component,@Service等注解的bean会被注解添加到beanDefinitionMap,而@Import,@Bean这些会被转为ConfigurationClass进行下一步解析。
这里是loadBeanDefinitions()里面核心方法
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修饰的bean
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//注册@Bean修饰的bean
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//注册@ImportResources配置的信息
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//@Import注解的bean,且bean实现了ImportBeanDefinitionRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
3.postProcessBeanFactory()方法 【Spring源码解析之|Spring源码解析之 ——ConfigurationClassPostProcessor】postProcessBeanFactory()对加了@Configuration注解的类进行CGLIB代理和向Spring中添加一个后置处理器ImportAwareBeanPostProcessor。
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//.....省略代码//@Configuration注解的类进行CGLIB代理
enhanceConfigurationClasses(beanFactory);
//添加一个后置处理器ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- Android事件传递源码分析
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- Java内存泄漏分析系列之二(jstack生成的Thread|Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析)
- [源码解析]|[源码解析] NVIDIA HugeCTR,GPU版本参数服务器---(3)
- ffmpeg源码分析01(结构体)
- spring|spring boot项目启动websocket