Spring注解版执行流程 ConfigurationClassPostProcessor
上一篇文章我们对容器中存在的配置类进行了解析,解析完毕之后是对配置类进行校验工作。
parser.validate();
// 循环遍历所有的配置类,调用配置了的校验方法,problemReporter是
// ConfigurationClassPostProcessor后置处理器初始化中赋值的默认参数 new FailFastProblemReporter()
// 再创建ConfigurationClassParser对象时传入构造方法中的。
// 主要作用是抛出错误。
public void validate() {
for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
configClass.validate(this.problemReporter);
}
}
public void validate(ProblemReporter problemReporter) {
// 获取 @Configuration 注解的属性值,除非配置类声明为 proxyBeanMethods=false 不适用 CGLIB 代理模式,否则的话不可能为 final 类
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
// 如果配置类是final类型,则抛出异常
if (this.metadata.isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
// 校验配置类中@Bean定义的方法
// 要求bean方法不能是static方法/final方法和重载方法
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
}
}
proxyBeanMethods 是为了让使用 @Bean 注解的方法被代理而实现 bean 的生命周期的行为。
设置为 true,那么直接调用方法获取 bean,不会创建新的 bean,而是会走 bean 的生命周期的行为。
设置为 false, 那么直接调用方法获取 bean,会创建新的 bean,且不会走 bean 的生命周期的行为。
验证完之后继续往后看。在此之前,注入的 BeanDefinition 都是 Configuration 配置类中定义的内部 bean,因为配置类依赖于这些内部的实例,所以后面这部分工作就是处理配置类 BD 加载工作.
// 获取所有的 bean,包括扫描的 bean 对象,@Import 导入的 bean 对象
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 清除掉已经解析处理过的配置类
configClasses.removeAll(alreadyParsed);
// 判断读取器是否为空,如果为空的话,就创建完全填充好的 ConfigurationClass 实例的读取器
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 核心方法,将完全填充好的ConfigurationClass实例通过BeanDefinition注册入IOC容器
this.reader.loadBeanDefinitions(configClasses);
// 添加到已经处理的集合中
alreadyParsed.addAll(configClasses);
candidates.clear();
this.reader.loadBeanDefinitions(configClasses)中的处理逻辑。
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;
}
// 若 bean 通过 @Import(ImportSelector) 方式添加到容器中的,那么此时 configClass#isImported 返回的是 true
// 1.configClass.importedBy 属性里面存储的是 ConfigurationClass 就是将 bean 导入的类
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 2.判断当前 bean 是否含有 @Bean 注解方法,如果有,需要把这些方法产生 bean 放入到 BeanDefinitionMap 当中
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 3.将 @ImportResource 引入的资源注入 IOC 容器
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 4.如果 bean 上存在 @Import 注解,且 import 是一个实现了 ImportBeanDefinitionRegistrar 接口,则执行 ImportBeanDefinitionRegistrar#registerBeanDefinitions 方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
1.registerBeanDefinitionForImportedConfigurationClass 方法
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
// 定义 bd 实例
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
// 设置 scope 属性以及通过生成器生成 beanName、公共的属性值信息
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
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);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
处理被 @Import 导入的类,并且是没有加配置注解的【@Component、@Confuguration】否则会被先识别的配置类所替代,因为同样的配置类是只允许出现一个的
@Import 注解导入的类中如果不是 DeferredImportSelector 或 ImportBeanDefinitionRegistrar 这个类型的话,就会当作是一个普通的配置类进行 BeanDefinition 注入,importBy 属性值就是导入的类
2.loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
// 获取方法元数据
MethodMetadata metadata = beanMethod.getMetadata();
// 获取方法名称
String methodName = metadata.getMethodName();
// 是否标记为当前 @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");
// 获取别名
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
for (String alias : names) {
// 注册剩下的别名
this.registry.registerAlias(beanName, alias);
}
// 是否存在同名 bean 定义,这实际上已经覆盖之前(例如通过XML)
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
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;
}
// 封装为ConfigurationClassBeanDefinition,表示是来自配置类里的bean定义
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
// 设置来源的类
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
// 判断是否是静态的,设置 BeanClass
if (metadata.isStatic()) {
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);
}
// 如果方法元数据是标准方法元数据的话,就设置解析的工厂方法
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);
// 获取自动装配枚举信息
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
//如果是自动装配,也就是BY_NAME 或者 BY_TYPE,再设置了一次自动装配模式
beanDef.setAutowireMode(autowire.value());
}
// 自动装配候选,默认是true
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
// 初始化方法 @PostConstruct、@PreDestroy 或 XML 或 InitializingBean、DisposableBean 接口
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
// 销毁方法
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// 处理作用域
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
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;
}
}
// 如果必要的话就替换原来 bean 定义与目标信息
BeanDefinition beanDefToRegister = beanDef;
// 如果作用域不是no的话就要使用代理
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
}
if (logger.isTraceEnabled()) {
logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
将 @Bean注解方法元数据取出来分析,分析有没有别名、有没有跟 xml 配置冲突,封装成一个configurationClassBeanDefinition,然后设置工厂方法名,获取 bean 注解的属性,设置初始化方法,销毁方法,是否自动装配,是否需要代理等,最后将 BD 信息加入到 BeanDefinitionMap、BeanDefinitionNames 集合中
3.loadBeanDefinitionsFromImportedResources 方法
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")) {
// When clearly asking for Groovy, that's what they'll get...
readerClass = GroovyBeanDefinitionReader.class;
}
else {
// Primarily ".xml" files but for any other extension as well
readerClass = XmlBeanDefinitionReader.class;
}
}
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
if (reader == null) {
try {
// 初始化 reader 读取器实例
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() + "]");
}
}
// 该方法是 XML 方式注入 Bean 核心的解析工作步骤
reader.loadBeanDefinitions(resource);
});
}
加载 ImportResources 中引入的 xml 文件,有两种加载类 GroovyBeanDefinitionReader、XmlBeanDefinitionReader,不指定默认采用的就是 XmlBeanDefinitionReader 读取器,然后用这个 reader 去加载 xml 资源。
最后,还有一步保证措施需要执行,主要是为了检测 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions 是否还有其他的配置类进行了引入
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
// 如果有未解析的类,则将其添加到 candidates 中,这样 candidates 不为空,就会进入到下一次的 while 的循环中
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
1.判断 registry.getBeanDefinitionCount() > candidateNames.length 目的:为了知道 reader.loadBeanDefinitions(configClasses) 这一步有没有向 BeanDefinitionMap 中添加新的 BeanDefinition
2.实际上就是看配置类,例如:AppConfig 类「Spring ImportTests 测试内部静态类」会向 BeanDefinitionMap 中添加 bean,这里的 AppConfig 类向容器中添加的 bean,实际上在 parser#parse 方法 这一步已经全部被解析好了,只是待塞入到 bdNames/bdMaps 集合中
3.如果有,registry.getBeanDefinitionCount 就会大于 candidateNames.length,这样就需要再次遍历新加入的 BeanDefinition,并判断这些 bean 是否已经被解析过了,如果未解析,需要重新进行解析
循环结束以后。
//往工厂对象里面添加ImportRegistry对象。以支持ImportAware @Configuration类
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
// 清空缓存。
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
至此,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法已经全部分析完成。
这两篇文章虽然里面的细节远不是这两篇文章可以将明白的,我只能说:“佩服!!!”。
还记得我们为什么要将这个方法嘛。是因为我们在refresh#invokeBeanFactoryPostProcessors方法中找实现了BeanDefinitionRegistryPostProcessor#PriorityOrdered的后置处理器,执行postProcessBeanDefinitionRegistry方法。
代码往后执行呢。你会发现后面就没有执行任何其他后置处理器方法了。后面执行ConfigurationClassPostProcessor#postProcessBeanFactory。