一提起配置类,大家第一个想到的一定是
@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) {// 获取 BDBeanDefinition 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 foundif (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicableconfigCandidates.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 contextSingletonBeanRegistry 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 classConfigurationClassParser 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 contentif (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 classesif (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;}
