在Spring中的ConfigurationClassParser一文中,提到了会把一些解析结果,如bean方法、需要导入的配置文件资源和bean定义注册器保存在ConfigurationClass对象的属性中。后续ConfigurationClassPostProcessor会调用ConfigurationClassBeanDefinitionReader来处理。本文就来分析一下是怎么处理的。
该类ConfigurationClassBeanDefinitionReader和ConfigurationClassParser类共同组成了ConfigurationClassPostProcessor的registry的后置操作中的核心实现。
loadBeanDefinitions方法
在ConfigurationClassPostProcessor中会直接调用该方法。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
// 创建条件判断器
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
// 遍历所要处理的配置类
for (ConfigurationClass configClass : configurationModel) {
// 加载配置类中的bean定义
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
该方法遍历每个配置类,并调用loadBeanDefinitionsForConfigurationClass方法。
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 判断类是不是可以跳过
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
// 判断bean是不是存在
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
// 移除bean定义
this.registry.removeBeanDefinition(beanName);
}
// 移除配置类中的bean
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 如果当前配置类是否是被其他类导入的
if (configClass.isImported()) {
// 注册配置bean
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 加载@Bean方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 加载@ImportResources导入的bean信息
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
/*
* 注意这里处理ImportBeanDefinitionRegistrar的实现类是由该类上的@Import引入的,
* 而不是直接处理该类的实现了ImportBeanDefinitionRegistrar的内部类。
*/
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
在该方法中,主要做了下面几件操作:
- 判断该类是否满足条件注解中的要求;
- 注册配置bean;
- 处理bean方法;
- 处理导入的配置文件资源;
- 从注册器中加载bean定义;
条件判断
private class TrackedConditionEvaluator {
private final Map<ConfigurationClass, Boolean> skipped = new HashMap<>();
public boolean shouldSkip(ConfigurationClass configClass) {
// 查询缓存
Boolean skip = this.skipped.get(configClass);
if (skip == null) {
// 判断当前类是否被其他配置类导入
if (configClass.isImported()) {
boolean allSkipped = true;
// 遍历导入当前配置类的其他配置类
for (ConfigurationClass importedBy : configClass.getImportedBy()) {
// 递归判断是否应该跳过导入当前类的其他配置类
if (!shouldSkip(importedBy)) {
allSkipped = false;
break;
}
}
// 只有所有导入该配置类的其他配置类都需要跳过时,才跳过当前类
if (allSkipped) {
// The config classes that imported this one were all skipped, therefore we are skipped...
skip = true;
}
}
if (skip == null) {
// 通过条件判断器来判断是不是应该跳过
skip = conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN);
}
// 将处理结果加入缓存中
this.skipped.put(configClass, skip);
}
return skip;
}
}
TrackedConditionEvaluator类是ConfigurationClassBeanDefinitionReader的一个内部类,主要目的是为了封装ConditionEvaluator类。前者在后者的基础上,提供了缓存的功能,以及递归判断了引入当前配置类的类是不是满足条件。实际的判断操作还是通过ConditionEvaluator来实现的。
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 如果没被@Conditional注解修饰,则不跳过
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
// 如果是配置类
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
// 递归处理
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
// 递归处理
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
// 获取Condition类型信息
for (String[] conditionClasses : getConditionClasses(metadata)) {
// 遍历类
for (String conditionClass : conditionClasses) {
// 创建Condition对象
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
// 添加到集合中
conditions.add(condition);
}
}
// 对Condition对象进行排序
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
// 获取Condition对象生效的阶段
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
/*
* 如果存在生效阶段,则先比较和目标阶段是否一致,如果不一致,则不做处理。
* 如果match返回false,说明应该skip
* 在Spring Boot中大量使用了@Conditional注解,而且定义了很多Condition类,可以转移到Spring Boot的源码中进行分析。
*/
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
这个方法主要在获取@Conditional注解中配置的Condition对象,然后调用这些对象的matches方法,如果返回了false,则会认为该配置类应该被跳过。
这个功能在Spring Boot中大量被使用,而且@Conditional有很多衍生注解,比如@ConditionalOnMissingBean、@ConditionalOnClass,主要是避免了用户设置@Conditional注解的Condition类型,从而满足开箱即用的特性。
注册配置bean
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
// 获取配置类的元数据
AnnotationMetadata metadata = configClass.getMetadata();
// 创建bean定义
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
// 解析作用域元数据
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
// 生成bean的名称
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
// 处理一些常见的注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
// 应用作用域代理模式
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册bean定义
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
仔细一看,就会发现处理过程和ClassPathBeanDefinitionScanner中doScan方法的for循环中的逻辑差不多,请参考Spring中的ClassPathBeanDefinitionScanner一文,这里不再赘述。
处理bean方法
Spring会将配置类中被@Bean注解修饰的方法抽象为bean注册到bean工厂中。
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
// 判断bean方法是否能跳过
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.state(bean != null, "No @Bean annotation attributes");
// Consider name and any aliases
// 获取其name属性
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
// 默认以方法名作为bean的名称,如果指定了name,那么以第一个元素作为bean的名称
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
// 将所有名称设置为别名
for (String alias : names) {
// 设置别名
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
// 判断bean方法的名称是否和所在配置类的bean名称相同,
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
// 如果相同则抛出异常
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
// 创建bean定义对象
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
// 设置bean定义来源
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) { // 如果是静态方法
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
// 设置bean的类型
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
}
else {
// 设置bean的类型
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
// 设置创建bean的工厂方法的名称
beanDef.setUniqueFactoryMethodName(methodName);
}
else { // 非静态方法
// instance @Bean method
// 将配置类的bean名称作为工厂bean的名称
beanDef.setFactoryBeanName(configClass.getBeanName());
// 设置创建bean的工厂方法的名称
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
// 设置装配模式
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
// 获取@Bean注解的autowire属性
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
// 设置自动装配模式
beanDef.setAutowireMode(autowire.value());
}
// 是否作为自动装配的候选bean
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
// 出去初始化方法名称
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
// 获取销毁方法名称
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
// 获取@Scope注解
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
// 创建作用域代理bean的定义
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
// 创建配置类bean定义
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
}
// 注册bean定义
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
// 先判断bean工厂中是否存在目标名称的bean
if (!this.registry.containsBeanDefinition(beanName)) {
return false;
}
// 根据bean名称获取已有的bean
BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
// Is the existing bean definition one that was created from a configuration class?
// -> allow the current bean method to override, since both are at second-pass level.
// However, if the bean method is an overloaded case on the same configuration class,
// preserve the existing bean definition.
if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
// 如果已存在的bean的类名称和bean方法所在配置类的名称相同
if (ccbd.getMetadata().getClassName().equals(
beanMethod.getConfigurationClass().getMetadata().getClassName())) {
if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
}
return true;
}
else {
return false;
}
}
// A bean definition resulting from a component scan can be silently overridden
// by an @Bean method, as of 4.2...
if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
return false;
}
// Has the existing bean definition bean marked as a framework-generated bean?
// -> allow the current bean method to override it, since it is application-level
if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
return false;
}
// At this point, it's a top-level override (probably XML), just having been parsed
// before configuration class processing kicks in...
if (this.registry instanceof DefaultListableBeanFactory &&
// 默认是true
!((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);
}
return true;
}
尽管该方法很长,但是内部主要是在处理@Bean和@Scope注解,最后一行代码才是真正的注册操作。
处理导入的配置文件资源
// 加载XML文件的配置
private void loadBeanDefinitionsFromImportedResources(
Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
// 遍历resource
importedResources.forEach((resource, readerClass) -> {
// Default reader selection necessary?
// 确定使用哪种读取器,readerClass是@ImportResource注解中的reader属性。
if (BeanDefinitionReader.class == readerClass) {
// 忽略.groovy
if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
// When clearly asking for Groovy, that's what they'll get...
readerClass = GroovyBeanDefinitionReader.class;
}
else if (shouldIgnoreXml) {
throw new UnsupportedOperationException("XML support disabled");
}
else {
// Primarily ".xml" files but for any other extension as well
// 默认的读取器类型
readerClass = XmlBeanDefinitionReader.class;
}
}
// 获取缓存中的bean定义读取器
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
if (reader == null) {
try {
// Instantiate the specified BeanDefinitionReader
// 创建bean定义读取器对象
reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
// Delegate the current ResourceLoader to it if possible
if (reader instanceof AbstractBeanDefinitionReader) {
AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
abdr.setResourceLoader(this.resourceLoader);
abdr.setEnvironment(this.environment);
}
// 将读取器对象加入缓存
readerInstanceCache.put(readerClass, reader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
}
}
// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
// 加载资源中的bean定义
reader.loadBeanDefinitions(resource);
});
}
由于这种方式使用的很少,所以不进一步分析具体reader的bean定义加载逻辑了。
处理注册器
// 从注册器中加载bean
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
// 遍历注册器
registrars.forEach((registrar, metadata) ->
// 执行注册器
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
这里遍历所有的注册器,并调用它的registerBeanDefinitions方法来注册bean。
总结
本文分析了ConfigurationClassBeanDefinitionReader的主要实现原理。 通过本文知道了尤其常用的bean方法是怎么被注册的,以及不太常用的外部配置文件和注册器又是怎么注册的bean。