一提起配置类,大家第一个想到的一定是
@Configuration
@ComponentScan("org.wesoft.spring.scan")
public class AppConfig {
}
没错,这的确是一个配置类,这是类全类名为 AnnotatedGenericBeanDefinition,那么 Spring 是如何进行解析的呢?
代码跟踪链如下:
public void refresh() throws BeansException, IllegalStateException {
// 省略代码无数...
invokeBeanFactoryPostProcessors(beanFactory);
// 省略代码无数...
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 关键代码:getBeanFactoryPostProcessors() 正常情况下是空
// 除非手工通过 ac.addBeanFactoryPostProcessor() 添加
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 省略代码无数...
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 省略代码无数...
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 是否实现了 PriorityOrdered 接口(PriorityOrdered 接口,同时又继承了 PriorityOrdered 接口)
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 加入当前需要执行的集合中,执行完会清空该集合
// 为什么要放到集合中?是防止程序员也会提供一个实现
// beanFactory.getBean(),1、从容器中直接拿 bean,2、如果拿不到会实例化该 bean
// 关键代码:beanFactory.getBean() 会返回一个 ConfigurationClassPostProcessor 类
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 找到的 bean 将名字放入 processedBeans 集合中,后面会用这个集合进行判断,是否执行过,就不再进行执行
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 将所有的 bean 放入 registryProcessors 集合
registryProcessors.addAll(currentRegistryProcessors);
// ★★★ 执行 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 方法
// 因为只有 ConfigurationClassPostProcessor 继承了 BeanDefinitionRegistryPostProcessor
// 该方法完成以后,所有的 bean 都会被扫描出来放入 beanDefinitionMap 中
// 老版的 mybatis 就是通过这里入手,完成的扫描
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 清空当前需要执行的集合清空
currentRegistryProcessors.clear();
// 省略代码无数...
}
首先拿到所有的 BD,此时的 BD,只有开天辟地的 5 个内置 BD 和一个手工注册的 AppConfig,然后进行循环判断,先看这个类是否被解析过,如果没有被解析过,检查并解析这个类,也就是 ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)
这个方法,当解析完成后,就开始 parser.parse(candidates)
解析了
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取所有 内置的 5 个 BD 和 手动 register 进去的(AppConfig.class)
String[] candidateNames = registry.getBeanDefinitionNames();
// 寻找 @Configuration 的类
for (String beanName : candidateNames) {
// 获取 BD
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断有没有被解析
// ★ 如果这个类已经被解析了,且配置类上加了 @Configuration,就是 full
// ★ 如果这个类已经被解析了,且配置类上没加 @Configuration,就是 lite
// 第一次进来的时候,这个类并没有被解析,所以不会进来
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// ★★★ 检查 这个类是不是 AnnotatedGenericBeanDefinition
// ★★★ 同时会给这个类的 attribute 添加一个属性 key = configurationClass,value = full 或者 lite,即标记这个类已经解析过了
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// ★ 解析成功,加入到已经解析的配置类集合中
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
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(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// ★★★ 关键代码:解析这个类中所有的注解
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> 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());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
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());
}
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;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
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();
}
}
这里的判断首先看这个 BD 是不是 AnnotatedBeanDefinition 类型,这里就解释了很多问题,前面我们说过,AppConfig 是 AnnotatedGenericBeanDefinition,@Component 标记的 bean 是 ScannedGenericBeanDefinition 类型,@Bean 标记的是 ConfigurationClassBeanDefinition 类型,而这些都是 AnnotatedBeanDefinition 的子类
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
AnnotationMetadata metadata;
/*
一个配置类的 db 类型,就是 AnnotatedGenericBeanDefinition extends GenericBeanDefinition implement AnnotatedBeanDefinition
通常 AnnotatedBeanDefinition 类型的类,就是一个配置类,因为 Spring 会将配置类写死为 AnnotatedGenericBeanDefinition
★★★ AnnotatedBeanDefinition 的实现类有三个,AnnotatedGenericBeanDefinition,ConfigurationClassBeanDefinition,ScannedGenericBeanDefinition
就是判断 beanDef 是不是一个配置类,所以也解释了 @Component 里为什么也可以写 @Bean
因为 @Component 是一个 ScannedGenericBeanDefinition,他是 AnnotatedBeanDefinition 的子类
而开天辟地的 5 BD 都是 RootBeanDefinition,所以是不会进行解析的
*/
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
// 获取这个类上所有的 注解信息
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
metadata = new StandardAnnotationMetadata(beanClass, true);
}
else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
// 判断是不是一个 加了 @Configuration 的注解类,此时就是一个 full 配置类
if (isFullConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 判断是不是一个 没加 @Configuration 的注解类,此时就是一个 lite 配置类
else if (isLiteConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}