你知道Spring是怎么解析配置类的吗?

完全读懂Spring(二)你知道Spring是怎么解析配置类的吗?html


推荐阅读:

Spring官网阅读系列java

完全读懂Spring(一)读源码,咱们能够从第一行读起web

Spring执行流程图以下:spring

Spring执行流程图

若是图片显示不清楚能够访问以下连接查看高清大图:app

Spring执行流程图编辑器

这个流程图会随着咱们的学习不断的变得愈来愈详细,也会愈来愈复杂,但愿在这个过程当中咱们都能朝着精通Spring的目标不断前进!ide

上篇文章咱们学习了Spring中的第一行代码,咱们已经知道了Spring中的第一行代码其实就是建立了一个AnnotatedBeanDefinitionReader对象,这个对象的主要做用就是注册bd(BeanDefinition)到容器中。而且在建立这个对象的过程当中,Spring还为容器注册了开天辟地的几个bd,包括ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessor等等。svg

那么在本文中,咱们就一块儿来看看Spring中的第二行代码又作了些什么?源码分析

Spring中的第二行代码

第二行代码在上面的流程图中已经标注的很是明白了,就是post

this.scanner = new ClassPathBeanDefinitionScanner(this);

只是简单的建立了一个ClassPathBeanDefinitionScanner对象。**那么这个ClassPathBeanDefinitionScanner有什么做用呢?从名字上来看好像就是这个对象来完成Spring中的扫描的,真的是这样吗?**但愿同窗们能带着这两个问题往下看

ClassPathBeanDefinitionScanner源码分析

这个类名直译过来就是:类路径下的BeanDefinition的扫描器,因此咱们就直接关注其扫描相关的方法,就是其中的doScan方法。其代码以下:

// 这个方法会完成对指定包名下的class文件的扫描
// basePackages:指定包名,是一个可变参数
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {    
        // 1.findCandidateComponents这个方法是实际完成扫描的方法,也是接下来咱们要分析的方法
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {// 上篇文章中咱们已经分析过了,完成了@Scope注解的解析
            // 参考《完全读懂Spring(一)读源码,咱们能够从第一行读起》
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                                            
            if (candidate instanceof AbstractBeanDefinition) {
        // 2.若是你对BeanDefinition有必定了解的话,你确定会知道这个判断必定会成立的,这意味着 // 全部扫描出来的bd都会执行postProcessBeanDefinition方法进行一些后置处理 
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }                           
            if (candidate instanceof AnnotatedBeanDefinition) {  
		// 3. 是否是一个AnnotatedBeanDefinition,若是是的话,还须要进行额外的处理 
	AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
           // 4.检查容器中是否已经有这个bd了,若是有就不进行注册了 
            if (checkCandidate(beanName, candidate)) {
                // 下面这段逻辑在上篇文章中都已经分析过了,这里就直接跳过了
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

上面这段代码主要作了四件事

  1. 经过findCandidateComponents方法完成扫描
  2. 判断扫描出来的bd是不是一个AbstractBeanDefinition,若是是的话执行postProcessBeanDefinition方法
  3. 判断扫描出来的bd是不是一个AnnotatedBeanDefinition,若是是的话执行processCommonDefinitionAnnotations方法
  4. 检查容器中是否已经有这个bd了,若是有就不进行注册了

接下来咱们就一步步分析这个方法,搞明白ClassPathBeanDefinitionScanner到底能起到什么做用

一、经过findCandidateComponents方法完成扫描

findCandidateComponents方法源码以下:

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        // 正常状况下都是进入这个判断,对classpath下的class文件进行扫描
        return scanCandidateComponents(basePackage);
    }
}
  • addCandidateComponentsFromIndex

不用过多关注这个方法。正常状况下Spring都是采用扫描classpath下的class文件来完成扫描,可是虽然基于classpath扫描速度很是快,但经过在编译时建立候选静态列表,能够提升大型应用程序的启动性能。在这种模式下,应用程序的全部模块都必须使用这种机制,由于当 ApplicationContext检测到这样的索引时,它将自动使用它而不是扫描类路径。
要生成索引,只需向包含组件扫描指令目标组件的每一个模块添加附加依赖项便可:
Maven:

org.springframework spring-context-indexer 5.0.6.RELEASE true

你们有兴趣的话能够参考官网:https://docs.spring.io/spring/docs/5.1.14.BUILD-SNAPSHOT/spring-framework-reference/core.html#beans-scanning-index

这个依赖实在太大了,半天了拉不下来,我这里就不演示了

  • scanCandidateComponents(basePackage)

正常状况下咱们的应用都是经过这个方法完成扫描的,其代码以下:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        
        // 用来存储返回的bd的集合
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
           
            // 拼接成这种形式:classpath*:com.dmz.spring
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            
            // 获取到全部的class文件封装而成的Resource对象
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

            // 遍历获得的全部class文件封装而成的Resource对象
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
                
                
				if (resource.isReadable()) {
					try {
                        // 经过Resource构建一个MetadataReader对象,这个MetadataReader对象包含了对应class文件的解析出来的class的元信息以及注解元信息
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 并非全部的class文件文件都要被解析成为bd,只有被添加了注解(@Component,@Controller等)才是Spring中的组件
						if (isCandidateComponent(metadataReader)) {
                            // 解析元信息(class元信息以及注解元信息)获得一个ScannedGenericBeanDefinition
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
		// 省略多余的代码
		return candidates;
	}

Spring官网阅读(一)容器及实例化 一文中,我画过这样一张图

从上图中能够看出,java class + configuration metadata 最终会转换为一个BenaDefinition,结合咱们上面的代码分析能够知道,java class + configuration metadata实际上就是一个MetadataReader对象,而转换成一个BenaDefinition则是指经过这个MetadataReader对象建立一个ScannedGenericBeanDefinition

二、执行postProcessBeanDefinition方法

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
    // 为bd中的属性设置默认值
    beanDefinition.applyDefaults(this.beanDefinitionDefaults);
    
    // 注解模式下这个值一定为null,使用XML配置时,
    if (this.autowireCandidatePatterns != null) {
        beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
    }
}
	// 设置默认值
public void applyDefaults(BeanDefinitionDefaults defaults) {
    setLazyInit(defaults.isLazyInit());
    setAutowireMode(defaults.getAutowireMode());
    setDependencyCheck(defaults.getDependencyCheck());
    setInitMethodName(defaults.getInitMethodName());
    setEnforceInitMethod(false);
    setDestroyMethodName(defaults.getDestroyMethodName());
    setEnforceDestroyMethod(false);
}

能够看出,postProcessBeanDefinition方法最主要的功能就是给扫描出来的bd设置默认值,进一步填充bd中的属性

三、执行processCommonDefinitionAnnotations方法

这句代码将进一步解析class上的注解信息,Spring在建立这个abd的信息时候就已经将当前的class放入其中了,全部这行代码主要作的就是经过class对象获取到上面的注解(包括@Lazy,@Primary,@DependsOn注解等等),而后将获得注解中对应的配置信息并放入到bd中的属性中

四、注册BeanDefinition

跟**完全读懂Spring(一)读源码,咱们能够从第一行读起**的注册逻辑是同样的


经过上面的分析,咱们已经知道了ClassPathBeanDefinitionScanner的做用,毋庸置疑,Spring确定是经过这个类来完成扫描的,可是问题是,Spring是经过第二步建立的这个对象来完成扫描的吗?咱们再来看看这个ClassPathBeanDefinitionScanner的建立过程:

// 第一步
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
    this(registry, true);
}
// 第二步 
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
    this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
// 第三步 
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
                                      Environment environment) {

    this(registry, useDefaultFilters, environment,
         (registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
// 第四步
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
                                      Environment environment, @Nullable ResourceLoader resourceLoader) {

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    if (useDefaultFilters) {
        // 注册默认的扫描过滤规则(要被@Component注解修饰)
        registerDefaultFilters();
    }
    setEnvironment(environment);
    setResourceLoader(resourceLoader);
}

在这个ClassPathBeanDefinitionScanner的建立过程当中咱们全程没法干涉,不能对这个ClassPathBeanDefinitionScanner进行任何配置。而咱们在配置类上明明是能够对扫描的规则进行配置的,例如:

@ComponentScan(value = "com.spring.study.springfx.aop.service", useDefaultFilters = true,
               excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {IndexService.class}))

因此Spring中确定不是使用在这里建立的这个ClassPathBeanDefinitionScanner对象。

实际上真正完成扫描的时机是在咱们流程图中的3-5-1步。完成扫描这个功能的类就是咱们在上篇文章中所提到的ConfigurationClassPostProcessor。接下来咱们就经过这个类,看看Spring究竟是如何完成的扫描,这也是本文重点想要说明的问题

Spring是怎么解析配置类的?

一、解析时机分析

解析前Spring作了什么?

注册配置类

在分析扫描时机以前咱们先回顾下以前的代码,整个程序的入口以下:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    register(annotatedClasses);
    refresh();
}

其中在this()空参构造中Spring实例化了两个对象,一个是AnnotatedBeanDefinitionReader,在上篇文章中已经介绍过了,另一个是ClassPathBeanDefinitionScanner,在前文中也进行了详细的分析。

在完成这两个对象的建立后,Spring紧接着就利用第一步中建立的AnnotatedBeanDefinitionReader去将配置类注册到了容器中。看到这里不知道你们有没有一个疑问,既然Spring是直接经过这种方式来注册配置类,为何咱们还非要在配置类上添加@Configuration注解呢?按照这个代码的话,我不在配置类上添加任何注解,也能将配置类注册到容器中,例以下面这样:

public class Config {
}

public class Main {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
        System.out.println(ac.getBean("config"));
        // 程序输出:com.spring.study.springfx.aop.Config@7b69c6ba
        // 意味着Config被注册到了容器中
    }
}

你们仔细想一想我这个问题,不妨带着这些疑问继续往下看。

调用refresh方法

在将配置类注册到容器中后,Spring紧接着又调用了refresh方法,其源码以下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 这个方法主要作了如下几件事
        // 1.记录容器的启动时间,并将容器状态更改成激活
        // 2.调用initPropertySources()方法,主要用于web环境下初始化封装相关的web资源,好比将servletContext封装成为ServletContextPropertySource
        // 3.校验环境中必要的属性是否存在
        // 4.提供了一个扩展点能够提早放入一些事件,当applicationEventMulticaster这个bean被注册到容器中后就直接发布事件
        prepareRefresh();

        // 实际上获取的就是一个DefaultListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 为bean工厂设置一些属性
        prepareBeanFactory(beanFactory);

        try {
            // 提供给子类复写的方法,容许子类在这一步对beanFactory作一些后置处理
            postProcessBeanFactory(beanFactory);

            // 执行已经注册在容器中的bean工厂的后置处理器,在这里完成的扫描
            invokeBeanFactoryPostProcessors(beanFactory);

            // 后面的代码跟扫描无关,咱们在以后的文章再介绍
        }
		// .....
    }
}

大部分的代码都写了很详细的注释,对于其中两个比较复杂的方法咱们单独分析

  1. prepareBeanFactory
  2. invokeBeanFactoryPostProcessors
prepareBeanFactory作了什么?
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置classLoader,通常就是appClassLoader
    beanFactory.setBeanClassLoader(getClassLoader());
    // 设置el表达式解析器
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // 容器中添加一个属性编辑器注册表,关于属性编辑在《Spring官网阅读(十四)Spring中的BeanWrapper及类型转换》有过详细介绍,这里就再也不赘述了
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 添加了一个bean的后置处理器,用于执行xxxAware方法
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    
    // 自动注入模型下,若是bean中存在如下类型的依赖,不进行注入
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 为何咱们能直接将ApplicationContext等一些对象直接注入到bean中呢?就是下面这段代码的做用啦!
    // Spring在进行属性注入时会从resolvableDependencies的map中查找是否有对应类型的bean存在,若是有的话就直接注入,下面这段代码就是将对应的bean放入到resolvableDependencies这个map中
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 添加一个后置处理器,用于处理ApplicationListener
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 是否配置了LTW,也就是在类加载时期进行织入,通常都不会配置
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // 加载时期织入会配置一个临时的类加载器
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 配置一些默认的环境相关的bean
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

上面这段代码总体来讲仍是很是简单的,逻辑也很清晰,就是在为beanFactory作一些配置,咱们须要注意的是跟后置处理器相关的内容,能够看到在这一步一共注册了两个后置处理器

  • ApplicationContextAwareProcessor,用于执行xxxAware接口中的方法
  • ApplicationListenerDetector,保证监听器被添加到容器中

关于ApplicationListenerDetector请参考Spring官网阅读(八)容器的扩展点(三)(BeanPostProcessor)

invokeBeanFactoryPostProcessors作了什么?

这个方法的执行流程在Spring官网阅读(六)容器的扩展点(一)BeanFactoryPostProcessor 已经作过很是详细的分析了,其执行流程以下

整的来讲,它就是将容器中已经注册的bean工厂的后置处理器按照必定的顺序进行执行。

那么到这一步为止,容器中已经有哪些bean工厂的后置处理器呢?

还记得咱们在上篇文章中提到的ConfigurationClassPostProcessor吗?在建立AnnotatedBeanDefinitionReader的过程当中它对应的BeanDefinition就被注册到容器中了。接下来咱们就来分析ConfigurationClassPostProcessor这个类的源码

ConfigurationClassPostProcessor源码分析

它实现了BeanDefinitionRegistryPostProcessor,因此首先执行它的postProcessBeanDefinitionRegistry方法,其源码以下

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   	// 生成一个注册表ID
    int registryId = System.identityHashCode(registry);
    //.....
    // 代表这个工厂已经通过了后置处理器了
    this.registriesPostProcessed.add(registryId);
	// 从名字来看这个方法是再对配置类的bd进行处理
    processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions方法的代码很长,咱们拆分一段段分析,先看第一段

第一段
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

    // ========第一段代码========
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    
    // 你们能够思考一个问题,当前容器中有哪些BeanDefinition呢?
    // 这个地方应该能获取到哪些名字?
    String[] candidateNames = registry.getBeanDefinitionNames();
	
    for (String beanName : candidateNames) {
        // 根据名称获取到对应BeanDefinition
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        
        // 省略日志打印
        
        // 检查是不是配置类,在这里会将对应的bd标记为FullConfigurationClass或者LiteConfigurationClass
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            // 是配置类的话,将这个bd添加到configCandidates中
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    
    // 没有配置类,直接返回
    if (configCandidates.isEmpty()) {
        return;
    }

    // 根据@Order注解进行排序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });
    // .....

上面这段代码有这么几个问题:

  1. 当前容器中有哪些BeanDefinition

若是你看过上篇文章的话应该知道,在建立AnnotatedBeanDefinitionReader对象的时候Spring已经往容器中注册了5个BeanDefinition,再加上注册的配置类,那么此时容器中应该存在6个BeanDefinition,咱们能够打个断点验证

在这里插入图片描述

不出所料,确实是6个

  1. checkConfigurationClassCandidate

代码以下:

public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}
		
        // 下面这一段都是为了获取一个AnnotationMetadata
        // AnnotationMetadata包含了对应class上的注解元信息以及class元信息
		AnnotationMetadata metadata;
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// 已经解析过了,好比注册的配置类就属于这种,直接从bd中获取
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// 拿到字节码从新解析获取到一个AnnotationMetadata
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			try {
                // class属性都没有,就根据className利用ASM字节码技术获取到这个AnnotationMetadata
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
		
				return false;
			}
		}
	
        // 若是被@Configuration注解标注了,说明是一个FullConfigurationCandidate
		if (isFullConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
        
        // 若是被这些注解标注了,@Component,@ComponentScan,@Import,@ImportResource
        // 或者方法上有@Bean注解,那么就是一个LiteConfigurationCandidate
        // 也就是说你想把这个类当配置类使用,可是没有添加@Configuration注解
		else if (isLiteConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}
		// 解析@Order注解,用于排序
		Integer order = getOrder(metadata);
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}
第二段
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 第一段
    // .....
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        // beanName的生成策略,不重要
        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();
    }
	// 核心目的就是建立这个ConfigurationClassParser对象
    ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);
   // 第三段
}

这段代码核心目的就是为了建立一个ConfigurationClassParser,这个类主要用于后续的配置类的解析。

第三段
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 第一段,第二段
    // .....
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        // 在第二段代码中建立了一个ConfigurationClassParser,这里就是使用这个parser来解析配置类
        // 咱们知道扫描就是经过@ComponentScan,@ComponentScans来完成的,那么不出意外一定是在这里完成的扫描
        parser.parse(candidates);
        
        // 校验在解析过程是中是否发生错误,同时会校验@Configuration注解的类中的@Bean方法可否被复写(被final修饰或者访问权限为private都不能被复写),若是不能被复写会抛出异常,由于cglib代理要经过复写父类的方法来完成代理,后文会作详细介绍
        parser.validate();
		
        // 已经解析过的配置类
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        // 移除已经解析过的配置类,防止重复加载了配置类中的bd
        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());
        }
        // 将经过解析@Bean,@Import等注解获得相关信息解析成bd被注入到容器中
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);

        candidates.clear();
        // 若是大于,说明容器中新增了一些bd,那么须要从新判断新增的bd是不是配置类,若是是配置类,须要再次解析
        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());


    // 注册ImportRegistry到容器中
    // 当经过@Import注解导入一个全配置类A(被@Configuration注解修饰的类),A能够实现ImportAware接口
    // 经过这个Aware能够感知到是哪一个类导入的A
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

二、解析源码分析

在上面的源码分析中,咱们已经可以肯定了Spring是经过ConfigurationClassParserparse方法来完成对配置类的解析的。Spring对类的取名能够说是很讲究了,ConfigurationClassParser直译过来就是配置类解析器。接着咱们就来看看它的源码

2.一、parse方法
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<>();

    // 遍历全部的配置类,一个个完成解析
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            // 三个判断最终都会进入到同一个方法---->processConfigurationClass方法
            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);
        }
    }
    // 对ImportSelector进行延迟处理
    processDeferredImportSelectors();
}
2.二、processConfigurationClass方法
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		// 解析@Conditional注解,判断是否须要解析
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		// 判断解析器是否已经解析过这个配置类了
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		// 不为null,说明已经解析过了
		if (existingClass != null) {
			// 若是这个要被解析的配置类是被@Import注解导入的
			if (configClass.isImported()) {
				// 而且解析过的配置类也是被导入的
				if (existingClass.isImported()) {
					// 那么这个配置类的导入类集合中新增当前的配置类的导入类,(A经过@Import导入了B,那么A就是B的导入类,B被A导入)
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				// 若是已经解析过的配置类不是被导入的,那么直接忽略新增的这个被导入的配置类。也就是说若是一个配置类同时被@Import导入以及正常的
				// 添加到容器中,那么正常添加到容器中的配置类会覆盖被导入的类
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				// 就是说新要被解析的这个配置类不是被导入的,因此这种状况下,直接移除调原有的解析的配置类
				// 为何不是remove(existingClass)呢?能够看看hashCode跟equals方法
				// remove(existingClass)跟remove(configClass)是等价的
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// Recursively process the configuration class and its superclass hierarchy.
		// 下面这段代码主要是递归的处理配置类及其父类
		// 将配置类封装成一个SourceClass方便进行统一的处理
		SourceClass sourceClass = asSourceClass(configClass);
		do {
			// doxxx方法,真正干活的方法,对配置类进行处理,返回值是当前这个类的父类
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}
2.三、doProcessConfigurationClass方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    throws IOException {

    // Recursively process any member (nested) classes first
    // 递归处理内部类
    processMemberClasses(configClass, sourceClass);

    // Process any @PropertySource annotations
    // 处理@PropertySources跟@PropertySource注解,将对应的属性资源添加容器中(实际上添加到environment中)
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), PropertySources.class,
        org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        }
        else {
            logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }

    // Process any @ComponentScan annotations、
    // 处理@ComponentScan,@ComponentScans注解,真正进行扫描的地方就是这里
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
   	if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				// 核心代码,在这里完成的扫描
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				// 检查扫描出来的bd是不是配置类,若是是配置类递归进行解析
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					// 通常状况下getOriginatingBeanDefinition获取到的都是null
					// 何时不为null呢?,参考:ScopedProxyUtils.createScopedProxy方法
					// 在建立一个代理的bd时不会为null
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 判断扫描出来的bd是不是一个配置类,若是是的话继续递归处理
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}


    // Process any @Import annotations
    // 处理@Import注解
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // Process any @ImportResource annotations
    // 处理@ImportResource注解
    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);
        }
    }

    // Process individual @Bean methods
    // 处理@Bean注解
    // 获取到被@Bean标注的方法
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        // 添加到configClass中
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // Process default methods on interfaces
    // 处理接口中的default方法
    processInterfaces(configClass, sourceClass);

    // Process superclass, if any
    // 返回父类,进行递归处理
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // Superclass found, return its annotation metadata and recurse
            return sourceClass.getSuperClass();
        }
    }
    // No superclass -> processing is complete
    return null;
}

能够看到,在doProcessConfigurationClass真正完成了对配置类的解析,一共作了下面几件事

  1. 解析配置类中的内部类,看内部类中是否有配置类,若是有进行递归处理
  2. 处理配置类上的@PropertySources跟@PropertySource注解
  3. 处理@ComponentScan,@ComponentScans注解
  4. 处理@Import注解
  5. 处理@ImportResource注解
  6. 处理@Bean注解
  7. 处理接口中的default方法
  8. 返回父类,让外部的循环继续处理当前配置类的父类

咱们逐一进行分析

2.四、处理配置类中的内部类

这段代码很是简单,限于篇幅缘由我这里就再也不专门分析了,就是获取到当前配置类中的全部内部类,而后遍历全部的内部类,判断是不是一个配置类,若是是配置类的话就递归进行解析

2.五、处理@PropertySource注解

代码也很是简单,根据注解中的信息加载对应的属性文件而后添加到容器中

2.六、处理@ComponentScan注解

这个段咱们就须要看一看了,Spring在这里完成的扫描,咱们直接查看其核心方法,org.springframework.context.annotation.ComponentScanAnnotationParser#parse

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
		// 第一步就建立了一个ClassPathBeanDefinitionScanner对象
		// 在这里咱们就知道了,Spring在进行扫描时没有使用在最开始的时候建立的那个对象进行扫描
		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
		// 解析成bd时采用的beanName的生成规则
		Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
		boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
		scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
				BeanUtils.instantiateClass(generatorClass));
		// 配置这个扫描规则下的ScopedProxyMode的默认值
		ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
		if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
			scanner.setScopedProxyMode(scopedProxyMode);
		}
		else {
			Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
			scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
		}
		// 配置扫描器的匹配规则
		scanner.setResourcePattern(componentScan.getString("resourcePattern"));

		// 配置扫描器须要扫描的组件
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addIncludeFilter(typeFilter);
			}
		}

		// 配置扫描器不须要扫描的组件
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addExcludeFilter(typeFilter);
			}
		}

		// 配置默认是否进行懒加载
		boolean lazyInit = componentScan.getBoolean("lazyInit");
		if (lazyInit) {
			scanner.getBeanDefinitionDefaults().setLazyInit(true);
		}

		// 配置扫描器扫描的包名
		Set<String> basePackages = new LinkedHashSet<>();
		String[] basePackagesArray = componentScan.getStringArray("basePackages");
		for (String pkg : basePackagesArray) {
			String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
			Collections.addAll(basePackages, tokenized);
		}
		for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(declaringClass));
		}

		// 排除自身
		scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
				return declaringClass.equals(className);
			}
		});
		// 在完成对扫描器的配置后,直接调用其doScan方法进行扫描
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}

看到了吧,第一步就建立了一个ClassPathBeanDefinitionScanner,紧接着经过解析注解,对这个扫描器进行了各类配置,而后调用doScan方法完成了扫描。

2.七、处理@Import注解
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
		// 没有要导入的类,直接返回
		if (importCandidates.isEmpty()) {
			return;
		}
		// checkForCircularImports:Spring中写死的为true,须要检查循环导入
		// isChainedImportOnStack方法:检查导入栈中是否存在了这个configClass,若是存在了说明
		// 出现了A import B,B import A的状况,直接抛出异常
		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			// 没有出现循环导入,先将当前的这个配置类加入到导入栈中
			this.importStack.push(configClass);
			try {
				// 遍历全部要导入的类
				for (SourceClass candidate : importCandidates) {
					// 若是要导入的类是一个ImportSelector
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						// 反射建立这个ImportSelector
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						// 执行xxxAware方法
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
						// 若是是一个DeferredImportSelector,添加到deferredImportSelectors集合中去
						// 在全部的配置类完成解析后再去处理deferredImportSelectors集合中的ImportSelector
						if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
							this.deferredImportSelectors.add(
									new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
						}
						else {
							// 不是一个DeferredImportSelector,那么经过这个ImportSelector获取到要导入的类名
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							// 将其转换成SourceClass
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							// 递归处理要导入的类,通常状况下这个时候进入的就是另外两个判断了
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						// 若是是一个ImportBeanDefinitionRegistrar
						// 先经过反射建立这个ImportBeanDefinitionRegistrar
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
						// 再执行xxxAware方法
						ParserStrategyUtils.invokeAwareMethods(
								registrar, this.environment, this.resourceLoader, this.registry);
						// 最后将其添加到configClass的importBeanDefinitionRegistrars集合中
						// 以后会统一调用其ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,将对应的bd注册到容器中
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						// 既不是一个ImportSelector也不是一个ImportBeanDefinitionRegistrar,直接导入一个普通类
						// 并将这个类做为配置类进行递归处理
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				// 在循环前咱们将其加入了导入栈中,循环完成后将其弹出,主要是为了处理循环导入
				this.importStack.pop();
			}
		}
	}
2.八、处理@ImportResource注解

代码也很简单,在指定的位置加载资源,而后添加到configClass中。通常状况下,咱们经过@ImportResource注解导入的就是一个XML配置文件。将这个Resource添加到configClass后,Spring会在后文中解析这个XML配置文件而后将其中的bd注册到容器中,能够参考org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions方法

2.九、处理@Bean注解

将配置类中全部的被@Bean标注的方法添加到configClass的BeanMethod集合中

2.十、处理接口中的default方法

代码也很简单,Java8中接口能定义default方法,这里就是处理接口中的default方法,看其是否有@Bean标注的方法

到此为止,咱们分析完了整个解析的过程。能够发现Spring将全部解析到的配置信息都存储在了ConfigurationClass类中,可是到目前为止这些存储的信息都没有进行使用。那么Spring是在哪里使用的这些信息呢?回到咱们的第三段代码,其中有一行代码如图所示:
在这里插入图片描述

也就是在这里Spring完成了对解析好的配置类的信息处理。

2.十一、加载解析完成的配置信息
// configurationModel:被解析完成了配置类集合,其中保存了@Bean注解解析信息,@Import注解解析信息等等
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    for (ConfigurationClass configClass : configurationModel) {
        // 调用这个方法完成的加载
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}
private void loadBeanDefinitionsForConfigurationClass(
    ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
	// 判断是否须要跳过,例如A导入了B,A不知足加载的条件须要被跳过,那么B也应该被跳过
    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;
    }
	
    // 判断配置类是不是被导入进来的,实际的代码就是判断解析出来的configclass中的importedBy集合是否为空
    // 那么这个importedBy集合是作什么的呢?
    // 例如A经过@Import导入了B,那么解析B获得得configclass中得importedBy集合就包含了A
    // 简而言之,importedBy集合就是导入了这个类的其它类(可能同时被多个类导入)
    // 在前文中咱们也分析过了,被多个类同时导入时会调用mergeImportedBy方法在集合中添加一个元素
    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    // 解析@Bean标注的Method获得对应的BeanDefinition并注册到容器中
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    
	// 解析导入的配置文件,并将从中获得的bd注册到容器中
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    
    // 执行configClass中的全部ImportBeanDefinitionRegistrar的registerBeanDefinitions方法
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

这段代码阅读起来仍是很是简单的,这里我就跟你们一块儿看下BeanMethod的相关代码,主要是为了让你们对BeanDefinition的理解可以更加深刻,其源码以下:

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
		ConfigurationClass configClass = beanMethod.getConfigurationClass();
		MethodMetadata metadata = beanMethod.getMetadata();
		String methodName = metadata.getMethodName();

		// 根据@Conditional注解判断是否须要跳过
		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");

		// 从这里能够看出,若是没有配置beanName,默认会取方法名称做为beanName
		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);
		}

		// isOverriddenByExistingDefinition这个方法判断的是当前注册的bd是否被原有的存在的bd所覆盖了
        // 什么是覆盖呢?后文中咱们详细分析
		if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
            // 知足下面这个if的话意味着@Bean建立的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;
		}
		// 建立一个ConfigurationClassBeanDefinition,从这里能够看出经过@Bean建立的Bean所对应的bd全是ConfigurationClassBeanDefinition
		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
		beanDef.setResource(configClass.getResource());
		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
		
        // @Bean是静态的,那么只须要知道静态方法所在类名以及方法名就能执行这个方法了
		if (metadata.isStatic()) {
			// static @Bean method
			beanDef.setBeanClassName(configClass.getMetadata().getClassName());
			beanDef.setFactoryMethodName(methodName);
		}
		else {
            // 
			// instance @Bean method
			beanDef.setFactoryBeanName(configClass.getBeanName());
			beanDef.setUniqueFactoryMethodName(methodName);
		}
        
        // 接下来的代码就是设置一些bd的属性,而后将bd注册到容器中,相关的源码在以前的文章中已经分析过了
        // 这里我就不在分析了,参考本文推荐阅读文章的《读源码,咱们能够从第一行读起》
		//.....
	}

上面这个方法的主要目的就是将@Bean标注的方法解析成BeandDefinition而后注册到容器中。关于这个方法咱们能够对比下以前分析过的org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean方法。对比咱们能够发现,这两个方法最大的不一样在于一个是基于Class对象的,而另外一个则是基于Method对象的。

正由于如此,全部它们有一个很大的不一样点在于BeanDefinition中BeanClasss属性的设置。能够看到,对于@Bean形式建立的Bean其BeanDefinition中是没有设置BeanClasss属性的,可是额外设置了其它的属性

  • 静态方法下,设置了BeanClassName以及FactoryMethodName属性,其中的BeanClassName是静态方法所在类的类名,FactoryMethodName是静态方法的方法名
  • 实例方法下,设置了FactoryBeanName以及FactoryMethodName属性,其中FactoryBeanName是实例对应的Bean的名称,而FactoryMethodName是实例中对应的方法名

之因此不用设置BeanClasss属性是由于,经过指定的静态方法或者指定的实例中的方法也能惟一肯定一个Bean。

除此以外,注册@Bean形式获得的BeanDefinition时,还进行了一个isOverriddenByExistingDefinition(beanMethod, beanName)方法的判断,这个方法的主要做用是判断当前要注册的bean是否被以前已经存在的Bean覆盖了。可是在直接经过AnnotatedBeanDefinitionReader#doRegisterBean方法注册Bean时是没有进行这个判断的,若是存在就直接覆盖了,而不会用以前的bd来覆盖如今要注册的bd。这是为何呢?据笔者本身的理解,是由于Spring将Bean也是分红了三六九等的,经过@Bean方式获得的bd能够覆盖扫描出来的普通bd(ScannedGenericBeanDefinition),可是不能覆盖配置类,因此当已经存在的bd是一个ScannedGenericBeanDefinition时,那么直接进行覆盖,可是当已经存在的bd是一个配置类时,就不能进行覆盖了,要使用已经存在的bd来覆盖本次要注册的bd。

到此为止,咱们就完成了Spring中的整个配置类解析、注册的相关源码分析,不过还没完,咱们还得解决一个问题,就是为何要在配置类上添加@Configuration注解,在以前的源码分析中咱们知道,添加@Configuration注解的做用就是讲配置类标志成了一个full configurationClass,这个的目的是什么呢?原本是打算一篇文章写完的,不过实在是太长了,接近6w字,因此仍是拆成了两篇,预知后事如何,请看下文:
配置类为何要添加@Configuration注解呢?

总结

咱们结合上篇文章完全读懂Spring(一)读源码,咱们能够从第一行读起整理下目前Spring的执行流程

在这里插入图片描述

原图地址: 原图

清晰的知道了执行的流程,咱们再来回想下postProcessBeanDefinitionRegistry作了什么。
在这里插入图片描述 码字不易,对你有帮助的话记得点个赞,关注一波哦,万分感谢!