Spring 核心类 ConfigurationClassPostProcessor 流程讲解及源码全面分析


Spring 核心类 ConfigurationClassPostProcessor 注入流程以及相关的源码解析如下,首先对其类的注入来源进行详细分析

介绍

在 XML 配置容器方式中,一开始对 XML 文件进行解析,新加了一层层注解 @Configuration、@Bean、@Component 等等,解析&加载的实现,但是其并不影响 Spring 底层的实现,从中体现了 Spring 中强大的扩展性

例如:在 XML 配置【<context:component-scan base-package="com.vnjohn.config">】 以后,通过 ComponentScanBeanDefinitionParser 解析 XML 自定义标签时,会扫描配置的包下所有的类文件,将带有 @Component【@Service、@Controller 这些注解内部都引入了它】 注解的类都找到,加载为 ScannedGenericBeanDefinition【GenericBeanDefinition 子类】 类,放入到 beanDefinitionMap、beanDefinitionNames 集合中,等待 Bean 实例化过程进行加载

在扫描 XML 标签:<context:component-scan> 时,会新增一些注册处理器,它们负责后面的解析、加载工作,其中就承担了常用注解的解析工作(@Component、@ComponentScan、@Configuration、@PropertySource、@Import、@Bean)

以下是介绍在 SpringBoot 中 ConfigurationClassPostProcessor 类是如何被注入的过程

在这里插入图片描述

  1. SpringBootApplication#run 内部会创建 ConfigurableApplicationContext 接口下某个实例,Web 下创建的类就是它的实现类 AnnotationConfigServletWebServerApplicationContext
  2. 随即它的构造方法里面就会创建 AnnotatedBeanDefinitionReader 实例
  3. AnnotatedBeanDefinitionReader 构造方法里面又会调用:AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
  4. 此时就会创建好 ConfigurationClassPostProcessor 该类的 BeanDefinition 信息
  5. 在执行 invokeBeanFactoryPostProcessors 方法时会获取到 BDRPP 的实现类【ConfigurationClassPostProcessor & 实现了 PriorityOrdered
  6. 至此,该类 bean 实例就已经创建好了,并且会将标注的相关注解进行 beanDefinition 信息的创建,后续进入 Spring Bean 生命周期的过程中会将这些 BD 进行实例化、初始化,从而完成相关 Bean 创建工作

配置类加载过程

ConfigurationClassPostProcessor#postProcessBeanFactory:enhanceConfigurationClasses 增强所有 @Configuration 修饰的配置类,生成代理类,为了确保其下的 @Bean 方法是能够保持单例的、添加一个新的 ImportAwareBeanPostProcessor,BPP 后置处理类
在介绍 ConfigurationClassPostProcessor 类的执行流程时,先对 @Condition 注解使用进行以下说明,因为在执行过程中会涉及到该注解的逻辑

@Condition 注解使用

类或方法上增加了 @Condition 注解,在解析注解配置时会调用 shouldSkip 方法,基于 @Conditional 判断该对象是否要跳过,如果不满足 @Conditional 中 value 中的条件,就跳过该 Bean,不会注入容器

value 中的条件是具体的匹配逻辑,可以设置多个,如果匹配返回 true:代表可以正常注入,返回 false:代表不会注入容器中

代码示例如下:

// bill 会正常注入,linux 和 windows 会按照条件去匹配是否可以注入
@Conditional({WindowsCondition.class})
@Configuration
public class BeanConfig {
    @Bean(name = "bill")
    public Person person1() {
        return new Person("Bill Gates", 62);
    }

    @Conditional({LinuxCondition.class})
    @Bean("linux")
    public Person person2() {
        return new Person("Linux", 48);
    }

    @Conditional(WindowsCondition.class)
    @Bean("windows")
    public Person person3() {
        return new Person("windows", 50);
    }
}

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        Environment environment = conditionContext.getEnvironment();

        String property = environment.getProperty("os.name");
        if (property.contains("Linux")) {
            return true;
        }
        return false;
    }
}

public class WindowsCondition implements Condition {
    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        // 获取ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        // 获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        // 获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        // 获取bean定义的注册类
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        // 获得当前系统名
        String property = environment.getProperty("os.name");
        // 包含 Windows 则说明是 windows 系统,返回true
        if (property.contains("Windows")) {
            return true;
        }
        return false;
    }
}

postProcessBeanDefinitionRegistry 内核心方法

注解核心处理类:ConfigurationClassPostProcessor,执行流程如下:

在这里插入图片描述

BDRPP#postProcessBeanDefinitionRegistry 方法—>processConfigBeanDefinitions
BDRPP 接口下的 postProcessBeanDefinitionRegistry 方法会优先于 BFPP 接口下方法进行执行,此流程在介绍 refresh 方法时已经详细分析过了.

processConfigBeanDefinitions 前置准备工作

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		// 创建存放 BeanDefinitionHolder 对象集合
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		// 当前 registry 就是 DefaultListableBeanFactory,获取所有已经注册的 BeanDefinition beanName
		String[] candidateNames = registry.getBeanDefinitionNames();
		// 遍历所有要处理 beanDefinition 名称,筛选对应 beanDefinition(被注解修饰的)
		for (String beanName : candidateNames) {
			// 获取指定名称 BeanDefinition 对象
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			// 如果 beanDefinition 中 configurationClass 属性不等于空,那么意味着已经处理过,输出日志信息
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			// 判断当前 BeanDefinition 是否是一个配置类,并为 BeanDefinition 设置属性为 lite 或 full,此处设置属性值是为了后续进行调用
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				// 添加到对应的集合对象中
				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);
		});
		// 判断当前类型是否是 SingletonBeanRegistry 类型
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			// 类型的强制转换
			sbr = (SingletonBeanRegistry) registry;
			// 判断是否有自定义 beanName 生成器
			if (!this.localBeanNameGeneratorSet) {
				// 获取自定义 beanName 生成器
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				// 如果有自定义的命名生成策略
 				if (generator != null) {
					// 设置组件扫描 beanName 生成策略
					this.componentScanBeanNameGenerator = generator;
					// 设置 import bean name 生成策略
					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);

		// 创建两个集合对象,
		// 存放相关的BeanDefinitionHolder对象
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		// 存放扫描包下的所有bean
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			// 解析带有 @Controller、@Import、@ImportResource、@ComponentScan、@ComponentScans、@Bean 的 BeanDefinition
			parser.parse(candidates);
			// 将解析完的 Configuration 配置类进行校验
			// 1、配置类不能是 final
			// 2、@Bean 修饰的方法必须可以重写以支持CGLIB
			parser.validate();
			// 获取所有的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();
			// 这里判断 registry.getBeanDefinitionCount() > candidateNames.length 目的是为了知道 reader.loadBeanDefinitions(configClasses) 这一步有没有向 BeanDefinitionMap 中添加新的BeanDefinition
			// 实际上就是看配置类(例如 AppConfig 类会向 BeanDefinitionMap 中添加 bean)
			// 如果有,registry.getBeanDefinitionCount() 就会大于 candidateNames.length
			// 这样就需要再次遍历新加入的 BeanDefinition,并判断这些 bean 是否已经被解析过了,如果未解析,需要重新进行解析
			// 这里 AppConfig 类向容器中添加 bean,实际上在 parser.parse() 这一步已经全部被解析了
			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;
			}
		}
		while (!candidates.isEmpty());
		// 注册 ImportRegistry Bean 信息为了支持 ImportAware 配置类
		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();
		}
	}

该方法流程如下:

  1. 先遍历所有被自动加载的 BeanDefinition 信息,一般都是会把标注了 @Configuration 注解的类优先进行注入,然后判断当前 BD 属性 configurationClass 是否为空,若不为空,说明该类型已经被注入,否则就调用 Configuration 工具类检测类型是否标注了 @Configuration 注解,为其设置好相关的属性准备工作,该方法源码及注释如下:

  2. 对配置类进行排序,根据 order 属性值 ,属性值越大的优先进行处理

  3. 判断是否有自定义的 beanName 生成器,若有进行实例化,否则不处理,一般无特殊的要求这里使用的就是 Spring 内部的生成器

  4. 若当前环境对象为空,就创建一个标准环境对象进行后续的值处理工作

  5. 实例化 ConfigurationClassParser 核心类,会调用其 parse 方法对配置类集合进行具体解析(parse->processConfigurationClass)

第一点描述的方法源码及注释如下:

public static boolean checkConfigurationClassCandidate(
		BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
	// 获取bean定义信息中的class类名
	String className = beanDef.getBeanClassName();
	// 如果className为空,或者bean定义信息中的factoryMethod不等于空,那么直接返回
	if (className == null || beanDef.getFactoryMethodName() != null) {
		return false;
	}
	AnnotationMetadata metadata;
	// 通过注解注入的 bd 都是 AnnotatedGenericBeanDefinition,实现了AnnotatedBeanDefinition
	// spring 内部 bd 是 RootBeanDefinition,实现了 AbstractBeanDefinition
	// 此处主要用于判断是否归属于 AnnotatedBeanDefinition
	if (beanDef instanceof AnnotatedBeanDefinition &&
			className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
		// 从当前bean的定义信息中获取元数据信息
		metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
	}
	// 判断是否是 spring 中默认的 BeanDefinition
	else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
		// 获取当前 bean 对象 Class 对象
		Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
		// 如果class实例是下面四种类型或接口的子类、父接口等任何一种情况,直接返回
		if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
				BeanPostProcessor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
				EventListenerFactory.class.isAssignableFrom(beanClass)) {
			return false;
		}
		// 为给定类创建新的AnnotationMetadata实例
		metadata = AnnotationMetadata.introspect(beanClass);
	}
	// 如果上述两种情况都不符合
	else {
		try {
			// 获取className的MetadataReader实例
			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;
		}
	}
	// 获取 bean 定义元数据被 @Configuration 注解标注的属性字典值
	Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
	// 如果 bean 被 @Configuration 注解标注,且属性 proxyBeanMethods 为 true(使用代理模式),则将 bean 定义为 full
	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	// 如果 bean 被 @Configuration 注解标注,且被注解 @Component,@ComponentScan、@Import、@ImportResource 或者 @Bean 标记的方法,则将 bean 定义标记为 lite
	else if (config != null || isConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}
	// bean 定义是一个标记为 full 或 lite 候选项,有设置 order 则设置 order 属性值
	Integer order = getOrder(metadata);
	// 如果值不为空的话,那么直接设置值到具体 beanDefinition
	if (order != null) {
		// 设置 bean 定义 order 值
		beanDef.setAttribute(ORDER_ATTRIBUTE, order);
	}
	return true;
}

如果是 @Configuration 注解并且该注解属性 proxyBeanMethods 配置为 true默认值就是 true,该属性的含义就是为了注明该类下的 @Bean 方法是否被动态代理拦截实现单例,则标识为 full

如果注解属性 proxyBeanMethods 为 false 并且加了 @Bean、@Component、@ComponentScan、@Import、@ImportResource 注解的,则标识为 lite

以上两者都不是的话则不进行处理,否则将其加入到配置类集合中进行后续方法的处理

ConfigurationClassParser#parse 方法

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	// 循环遍历 configCandidates
	for (BeanDefinitionHolder holder : configCandidates) {
		// 获取 BeanDefinition
		BeanDefinition bd = holder.getBeanDefinition();
		// 根据 BeanDefinition 类型的不同,调用 parse 不同的重载方法,实际上最终都是调用 processConfigurationClass 方法
		try {
			// 注解类型
			if (bd instanceof AnnotatedBeanDefinition) {
				parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
			}
			// 有class对象的
			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);
		}
	}

	// 执行找到 DeferredImportSelector,它是 ImportSelector 的一个子类
	// ImportSelector 被设计成和 @Import 注解同样的效果,但是实现了 ImportSelector 类可以条件性的决定导入某些配置
	// DeferredImportSelector 设计是在所有其他的配置类被处理后才进行处理,因为一个配置类它内部依赖于其他 bean,其他 bean 需要优先进行构建
	this.deferredImportSelectorHandler.process();
}

parse 方法存在于多个重载方法,但最终调用的都是 processConfigurationClass 方法

// 根据注解元数据、beanName 解析配置文件,有注解元数据
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
	processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

// 根据 Class、beanName 解析配置文件,有 Class 对象
protected final void parse(Class<?> clazz, String beanName) throws IOException {
	processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}

// 根据 className、beanName 解析配置文件,读取元数据
protected final void parse(@Nullable String className, String beanName) throws IOException {
	Assert.notNull(className, "No bean class name for configuration class bean definition");
	MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
	processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}

区分三种不同的类型,优先级不同而已

  1. 存在于注解,一般在 SpringBoot 下定义的都是这种方式,只有当我们对 spring 进行扩展实现时注入业务相关的 bean,才会是如下两种类型
  2. 存在 Class、beanName,在注入 beanDefinition 时直接指定的就是 .Class
  3. 存在 className、beanName,在注入 beanDefinition 时指定的是类的全限定的名称

deferredImportSelectorHandler#process 方法内部的执行流程在该文章有介绍:
SpringBoot 自动装配流程及源码剖析

ConfigurationClassParser#doProcessConfigurationClass 方法

在实际处理配置类前,再作一些前置校验的工作,避免调用后续方法作无用的动作

protected void  processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
	// 判断是否跳过解析
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}
	// 第一次进入的时候,configurationClass size 为 0,existingClass 肯定为 null,在此处理 configuration 重复 import
	// 如果同一个配置类被处理两次,两次都属于被 import 则合并导入类返回,如果配置类不是被导入的,则移除旧的使用新的配置类
	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				// 如果要处理的配置类 configClass 在已经分析处理的配置类记录中已存在,合并两者的importBy属性
				existingClass.mergeImportedBy(configClass);
			}
			// 否则忽略新导入的配置类,因为存在 non-imported 类重写它
			return;
		} else {
			// 明确 bean 定义发现,可能取代了 import,允许移除老的已加载配置类
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}
	// 处理配置类,由于配置类可能存在父类(若父类的全类名是以java开头的,则除外),所有需要将 configClass变成 sourceClass 去解析,然后返回 sourceClass 父类
	// 如果此时父类为空,则不会进行 while 循环去解析,如果父类不为空,则会循环的去解析父类
	// SourceClass 意义:简单的包装类,目的是为了以统一的方式去处理带有注解的类,不管这些类是如何加载的
	// 如果无法理解,可以把它当做一个黑盒,不会影响看 spring 源码主流程
	SourceClass sourceClass = asSourceClass(configClass, filter);
	do {
		// 解析各种注解
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	}
	while (sourceClass != null);
	// 将解析的配置类存储起来,这样回到 parse 方法时,能取到值
	this.configurationClasses.put(configClass, configClass);
}
  1. 调用 shouldSkip 方法,基于 @Conditional 标签判断该对象是否要跳过,如果不满足 @Conditional 中 value 中的条件,就跳过该 Bean,不会注入容器
  2. 判断该配置类是否已经被处理过:如果被处理过,则判断当前类和已配置过的类是否都是被 import 导入的,是则对两者的 importedBy 属性进行合并,否则就先进行移除然后重新加入配置类
  3. 前期的校验和准备工作做完以后,再调用 doProcessConfigurationClass 进行具体的注解解析工作

由于 doProcessConfigurationClass 方法内部处理的流程较长,如下分为不同节点进行解析

processMemberClasses

递归处理内部类

// @Configuration 继承了 @Component
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
	// 递归处理内部类,因为内部类也是一个配置类,配置类上有 @configuration 注解,该注解继承 @Component,if 判断为 true,调用 processMemberClasses 方法,递归解析配置类中的内部类
	processMemberClasses(configClass, sourceClass, filter);
}
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,Predicate<String> filter) throws IOException {
    // 找到内部类,内部类中也可能是一个配置类
    Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
    // 如果不等于空的话
    if (!memberClasses.isEmpty()) {
        List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
        // 循环判断内部类是不是配置类 & 内部类不是当前配置类型
        for (SourceClass memberClass : memberClasses) {
            if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
             !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) 			{
                candidates.add(memberClass);
            }
        }
        // 对配置类进行排序操作
        OrderComparator.sort(candidates);
        // 遍历符合规则的类
        for (SourceClass candidate : candidates) {
            if (this.importStack.contains(configClass)) {
                // 出现配置类循环导入,则直接报错
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
            }
            else {
                // 将配置类入栈
                this.importStack.push(configClass);
                try {
                    // 调用 processConfigurationClass 方法,因为内部类中还可能包含内部类,所以需要在做循环解析,实际工作中是不会有这中情况的
                    processConfigurationClass(candidate.asConfigClass(configClass), filter);
                }
                finally {
                    // 解析完出栈
                    this.importStack.pop();
                }
            }
        }
    }
}

获取当前配置类的子类,对子类进行判别其是否属于配置类:@Component、@ComponentScan、@Import、@ImportResource,是就追加到 candidates 集合中,后面对其进行排序.

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
	// 不考虑接口
	if (metadata.isInterface()) {
		return false;
	}
	// 检查是否被注解 @Component、@ComponentScan、@Import、@ImportResource 标注
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}
	// 最后检查是否有 @Bean 标注的方法
	try {
		return metadata.hasAnnotatedMethods(Bean.class.getName());
	}
	catch (Throwable ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
		}
		return false;
	}
}

candidates 集合进行遍历,若当前导入栈已存在当前配置类,则直接抛出异常结束:配置类不可重复注入;如果未存在,则调用 processConfigurationClass 方法继续往回走,因为内部类可能也会是一个配置类,所以调用该方法

processPropertySource
// 如果配置类上加了 @PropertySource 注解,那么就解析加载 properties 文件,并将属性添加到 spring 上下文中
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
		sourceClass.getMetadata(), PropertySources.class,
		org.springframework.context.annotation.PropertySource.class)) {
	if (this.environment instanceof ConfigurableEnvironment) {
		processPropertySource(propertySource);
	}
	else {
		logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
				"]. Reason: Environment must implement ConfigurableEnvironment");
	}
}

默认创建的环境对象实例是 StandardEnvironment,它实现了 ConfigurableEnvironment 接口,处理使用 @PropertySource 注解修饰的类

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
	// 获取name属性
	String name = propertySource.getString("name");
	if (!StringUtils.hasLength(name)) {
		name = null;
	}
	// 获取encoding属性
	String encoding = propertySource.getString("encoding");
	if (!StringUtils.hasLength(encoding)) {
		encoding = null;
	}
	// 获取value属性
	String[] locations = propertySource.getStringArray("value");
	Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
	boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
	Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
	PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
			DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
	for (String location : locations) {
		try {
			// 处理属性值的占位符
			String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
			// 讲指定位置的资源转换成 resource 对象
			Resource resource = this.resourceLoader.getResource(resolvedLocation);
			// 添加 resource 对象为属性资源
			addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
		}
		catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
			// Placeholders not resolvable or resource not found when trying to open it
			if (ignoreResourceNotFound) {
				if (logger.isInfoEnabled()) {
					logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
				}
			}
			else {
				throw ex;
			}
		}
	}
}

获取 name、value、encoding 属性,将 value 属性转换为 String[] locations;

对 locations 数组进行遍历,先进行占位符解析工作,如:classpath:myconfig${name}.properties 再转换为 Resource 源对象,最后将其添加至 propertySources 集合中【创建标准化环境对象(StandardEnvironment)时有用到】

处理 @ComponentScan、@ComponentScans 注解
// 处理 @ComponentScan 或 @ComponentScans 注解,并将扫描包下的所有 bean 转换成填充后的 ConfigurationClass
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) {
		// 比如 basePackages = com.vnjohn, 那么在这一步会扫描出这个包及子包下的 class,然后将其解析成 BeanDefinition(BeanDefinition 可以理解为等价于 BeanDefinitionHolder)
		Set<BeanDefinitionHolder> scannedBeanDefinitions =
				this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
		// 通过上一步扫描包 com.vnjohn,有可能扫描出来的 bean 中可能也添加了 ComponentScan 或 ComponentScans 注解.
		// 所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有 ComponentScan、ComponentScans
		for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
			BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
			if (bdCand == null) {
				bdCand = holder.getBeanDefinition();
			}
			// 判断是否是一个配置类,并设置 full 或 lite 属性
			if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
				// 通过递归方法进行解析
				parse(bdCand.getBeanClassName(), holder.getBeanName());
			}
		}
	}
}

通过注解工具类解析当前配置类中是否包含了 @ComponentScan、@ComponentScans 注解,存在就进行遍历挨个调用 ComponentScanAnnotationParser#parse 方法进行包的扫描工作

扫描工作完成后,将满足条件的 BeanDefinitions 进行再次解析,对 BD 集合进行遍历,判别集合中的元素是否依然是配置类,是的话就继续往回走,调用 ConfigurationClassParser#parse 方法 方法

ComponentScanAnnotationParser#parse 扫描包的解析方法前置工作进行详细分析,如下:

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	// 创建对应的扫描类
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
	// 获取 @ComponentScan 参数,并进行参数的设置工作
	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));
	// 获取 scopedProxy 属性
	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));
	}
	// 获取 resourcePattern 属性
	scanner.setResourcePattern(componentScan.getString("resourcePattern"));
	// 获取 includeFilters 属性
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addIncludeFilter(typeFilter);
		}
	}
	// 获取 excludeFilters 属性
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addExcludeFilter(typeFilter);
		}
	}
	// 获取 lazyInit 属性
	boolean lazyInit = componentScan.getBoolean("lazyInit");
	if (lazyInit) {
		scanner.getBeanDefinitionDefaults().setLazyInit(true);
	}

	Set<String> basePackages = new LinkedHashSet<>();
	// 获取 basePackages 属性
	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);
	}
	// 获取 basePackageClasses 属性,对全限定类进行包名截取
	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);
		}
	});
	// 开始执行扫描,最终的扫描器是 ClassPathBeanDefinitionScanner
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}
  1. 创建实际进行扫描工作的类:ClassPathBeanDefinitionScanner,填充该类型所需用到的一些属性「scopedProxyMode、resourcePattern、includeFilters、excludeFilters、basePackages」
  2. 调用 ClassPathBeanDefinitionScanner#parse 方法,扫描出 basePackages 属性包及子包下的 class,然后将其解析成 BeanDefinition 信息

ClassPathBeanDefinitionScanner#parse 实际扫描工作的方法进行详细解析,开始执行扫描工作,如下:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    // 遍历basePackages
    for (String basePackage : basePackages) {
        // 扫描 basePackage,将符合要求 bean 定义全部找出来
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // 遍历所有候选的 bean 定义
        for (BeanDefinition candidate : candidates) {
            // 解析 @Scope 注解,包括 scopeName 和 proxyMode
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 使用 beanName 生成器来生成 beanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                // 处理 beanDefinition 对象,例如:此 bean 是否可以自动装配到其他 bean 中
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                // 处理定义在目标类上的通用注解,包括 @Lazy,@Primary,@DependsOn,@Role,@Description
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // 检查 beanName 是否已经注册过,如果注册过,检查是否兼容
            if (checkCandidate(beanName, candidate)) {
                // 将当前遍历的 bean 定义、beanName 封装成 BeanDefinitionHolder
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 根据 proxyMode 值,选择是否创建作用域代理
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 注册 beanDefinition
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}
  1. 先调用 findCandidateComponents(backPackage) 将符合条件的 BeanDefinition(实际是 ScannedGenericBeanDefinition) 找出来

条件1:excludeFilters 不包含
条件2:includeFilters 至少匹配一个
条件3:该类不能是接口或抽象类
findCandidateComponents->scanCandidateComponents->isCandidateComponent

  1. 处理 BeanDefinition 对象的属性信息,解析 @Scope 注解,设置 scopeName、proxyMode,通过 beanNameGenerator 生成 beanName
  2. 设置自动装配属性,例如:该 bean 是否可以自动装配到其他 bean 中
  3. AnnotationConfigUtils#processCommonDefinitionAnnotations:处理定义在目标类上的通用注解,包括「@Lazy、@Primary、@DependsOn、@Role、@Description」填充对应的属性进去
  4. checkCandidate(beanName, candidate):检查 beanName 是否已经被注册过,如果被注册过考虑其是否与当前类兼容,不兼容就抛出异常,兼容则跳过当前 BeanDefinition 操作;如果未注册过,进行如下操作:

把当前遍历的 bean 定义信息和 beanName 封装成 BeanDefinitionHolder
调用 AnnotationConfigUtils.applyScopedProxyMode,根据 proxyMode 值来选择是否要创建代理,接口基于 JDK 动态代理,类基于 CGLIB 动态代理
主动 beanDefinition,放入到 BeanDefinitionMap、BeanDefinitionNames 中

第一点描述的符合条件方法 isCandidateComponent 源码判断部分,如下:

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
	for (TypeFilter tf : this.excludeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return false;
		}
	}
	for (TypeFilter tf : this.includeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return isConditionMatch(metadataReader);
		}
	}
	return false;
}
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
	AnnotationMetadata metadata = beanDefinition.getMetadata();
	/**
	 * isIndependent:确定底层类是否是独立的,即它是否是顶级类或者嵌套类,他可以独立于封闭类构造
	 * isConcrete:判断底层类是否表示具体类,即:既不是接口也不是抽象类
	 * isAbstract && hasAnnotatedMethods:是否被标记为抽象类 && 确定基础类是否具有使用给定注解 @Lookup 标注的方法
	 */
	return (metadata.isIndependent() && (metadata.isConcrete() ||
			(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}

至此,扫描工作完成以后就到了 ComponentScanAnnotationParser#parse 方法处理的最后一步了,拿到所扫描到的 Set<BeanDefinitionHolder> 集合,遍历每一个 BeanDefinitionHolder ,判断是否是一个配置类,并设置 full 或 lite 属性,再次往回走调用 (parse—>processConfigurationClass) 方法进行后续解析工作

processImports

处理 @Import 注解,导入额外的配置类,同时完成具体类的实例化工作,该类型处理也涉及到自动装配的工作

processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

getImports—>collectImports:递归获取被 @Import 注解标注的类,被它标注的类无须加 @Component、@Configuration 等配置注解,否则该 Bean 会被添加两次,但 Spring 会进行合并的工作

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
      Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
      boolean checkForCircularImports) {
   // 如果使用 @Import 注解修饰的类集合为空,那么直接返回
   if (importCandidates.isEmpty()) {
      return;
   }
   // 通过一个栈结构解决循环引入,栈中存在该配置类则抛出异常
   if (checkForCircularImports && isChainedImportOnStack(configClass)) {
      this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
   }
   else {
      // 添加到栈中,用于处理循环引入的问题
      this.importStack.push(configClass);
      try {
         // 遍历每一个 @Import 注解的类
         for (SourceClass candidate : importCandidates) {
            // 检验配置类 Import 引入的类是否是 ImportSelector 子类:
            if (candidate.isAssignable(ImportSelector.class)) {
               // 候选类是一个导入选择器->委托来确定是否进行导入
               Class<?> candidateClass = candidate.loadClass();
               // 通过反射生成一个 ImportSelect 对象
               ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                     this.environment, this.resourceLoader, this.registry);
               // 获取选择器的额外过滤器
               Predicate<String> selectorFilter = selector.getExclusionFilter();
               if (selectorFilter != null) {
                  exclusionFilter = exclusionFilter.or(selectorFilter);
               }
               // 判断引用选择器是否是 DeferredImportSelector 接口的实例
               // 如果是则应用选择器将会在所有的配置类都加载完毕后加载
               if (selector instanceof DeferredImportSelector) {
                  // 将选择器添加到 deferredImportSelectorHandler 实例中,预留到所有的配置类加载完成后统一处理自动化配置类
                  this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
               }
               else {
                  // 获取引入的类,然后使用递归方式将这些类中同样添加了 @Import 注解引用的类
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                   Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                   // 递归处理,被 Import 进来的类也有可能 @Import 注解
                   processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
               }
            }
             // 如果是实现了 ImportBeanDefinitionRegistrar 接口的 bd:SpringBoot 中的 AutoConfigurationPackages$Registrar
             else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                 // 候选类是ImportBeanDefinitionRegistrar  -> 委托给当前注册器注册其他bean
                 Class<?> candidateClass = candidate.loadClass();
                 ImportBeanDefinitionRegistrar registrar =
                     ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                                          this.environment, this.resourceLoader, this.registry);
                 // 放到当前 configClass 的 importBeanDefinitionRegistrars 中
                 // 在 ConfigurationClassPostProcessor 处理 configClass 时会随之一起处理
                 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
             }
             else {
                 // 候选类既不是 ImportSelector 也不是 ImportBeanDefinitionRegistrar-->将其作为 @Configuration 配置类处理
                 this.importStack.registerImport(
                     currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                 // 如果 Import 类型是普通类,则将其当作带有 @Configuration 类一样处理
                 // 把 candidate 构造为 ConfigurationClass,标注为 importedBy,意味着它是通过被@Import 进来的
                 // 后面处理会用到这个判断将这个普通类注册进 DefaultListableBeanFactory
                 processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
             }
         }
      }
       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();
       }
   }
}
  1. 判断被 @Import 注解标注的类集合是否为空,不为空才进行后续的处理工作,循环遍历每一个配置类,判断它所匹配的类型

  2. 如果是 ImportSelector 接口的子类但非 DeferredImportSelector 接口的子类,就对其配置类进行递归处理,因为当前类可能还有使用 @Import 注解导入其他的配置类,递归调用的是 processImports 方法

  3. 如果是 ImportSelector & DeferredImportSelector 接口的子类,将其先暂时添加到 deferredImportSelectorHandler 集合中,待所有的配置类都加载完成以后:也就是当所有的类都调用 parse 方法结束后,再统一处理这些类型的配置类.
    回忆一下,在 ConfigurationClassParser#parse 方法中会作这步操作 > this.deferredImportSelectorHandler.process();

  4. 如果是 ImportBeanDefinitionRegistrar 接口子类,会将其进行实例化后存入集合中,待所有配置类处理完后,调用其类下的 registerBeanDefinitions 设置具体的 BeanDefinition 类型,如 SpringBoot 中设置的就是专门由 Spring 内部使用的 BD

  5. 如果以上都不是的话,则将其当作带有 @Configuration 类一样处理,将 candidate 构造为 ConfigurationClass,标注为 importedBy,意味着它是通过被 @Import 进来的

处理 @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);
	}
}

处理 @ImportResource 注解,导入 spring 配置文件,通过此方式引入的 xml 文件来通过 IOC 容器注入 Bean 实例对象

处理 @Bean 注解

检索配置类中加了 @Bean 注解的方法,将 @Bean 方法转化为 BeanMethod 对象,保存再集合中

Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
	configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
processInterfaces
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    // 找到配置类的所有接口,遍历接口
    for (SourceClass ifc : sourceClass.getInterfaces()) {
        // 找到含有 @Bean 注解的默认方法
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
        for (MethodMetadata methodMetadata : beanMethods) {
            if (!methodMetadata.isAbstract()) {
                // A default method or other concrete method on a Java 8+ interface...
                // 添加到集合中
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }
        }
        // 递归处理,因为接口可能存在父接口
        processInterfaces(configClass, ifc);
    }
}

处理接口的默认方法实现,从 JDK8 开始,接口中的方法可以有自己的默认实现,若这个接口的方法加了 @Bean 注解,也需要被解析;然后检索配置类中加了 @Bean 注解的方法,将 @Bean 方法转化为 BeanMethod 对象,保存再集合中

解析父类
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();
    }
}

解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析
对父类进行判别其是否需要处理:父类不是以 java 开头的、父类集合中未存在(防止重复处理)
满足以后返回到外层方法:doProcessConfigurationClass,do-while 循环

do {
	// 解析各种注解
	sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);

processConfigBeanDefinitions 后置结束工作

parser#validate

解析完的 Configuration 配置类进行校验

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定义的方法
		for (BeanMethod beanMethod : this.beanMethods) {
			beanMethod.validate(problemReporter);
		}
	}
}
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

在此方法调用之前,注入的 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();

判断读取器 ConfigurationClassBeanDefinitionReader 实例是否为空,若为空的话,就创建完全填充好的 ConfigurationClass 实例的读取器

reader#loadBeanDefinitions:核心方法,将完全填充好的 ConfigurationClass 实例转化为 BeanDefinition 注入 IOC 容器,循环遍历调用 loadBeanDefinitionsForConfigurationClass 方法

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
	// configClass.importedBy 属性里面存储的是 ConfigurationClass 就是将 bean 导入的类
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	// 判断当前 bean 是否含有 @Bean 注解方法,如果有,需要把这些方法产生 bean 放入到 BeanDefinitionMap 当中
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}
	// 将 @ImportResource 引入的资源注入 IOC 容器
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 如果 bean 上存在 @Import 注解,且 import 是一个实现了 ImportBeanDefinitionRegistrar 接口,则执行 ImportBeanDefinitionRegistrar#registerBeanDefinitions 方法
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

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 属性值就是导入的类

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 集合中

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 资源,XmlBeanDefinitionReader#loadBeanDefinitions 核心方法博主在介绍 refresh 方法流程时有详细分析

ending

最后,还有一步保证措施需要执行,主要是为了检测 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 是否已经被解析过了,如果未解析,需要重新进行解析

至此,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法已经全部分析完成

postProcessBeanFactory 内核心方法

该方法也是在 refresh 中 invokeBeanFactoryPostProcessors 方法会进行调用的,优先调用 BDRPP 接口 postProcessBeanDefinitionRegistry 方法,然后再调用 BFPP 接口 postProcessBeanFactory 方法

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	int factoryId = System.identityHashCode(beanFactory);
	if (this.factoriesPostProcessed.contains(factoryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + beanFactory);
	}
	this.factoriesPostProcessed.add(factoryId);
	if (!this.registriesPostProcessed.contains(factoryId)) {
		// BeanDefinitionRegistryPostProcessor 钩子显然不支持
		// 简单调用 processConfigurationClasses 懒加载在这一点上
		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
	}
	// 为满足条件的 @Configuration 注解标识的类进行动态代理,生成的代理对象
	enhanceConfigurationClasses(beanFactory);
	// ImportAwareBeanPostProcessor 处理:对代理的配置类注入 BeanFactory,方便后续从该对象中获取到容器中的实例对象以及支持获取注解的元数据信息
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

从以上代码中可以看出,processConfigBeanDefinitions 方法在前面已经仔细分析过了,在这边主要介绍的核心方法就是 enhanceConfigurationClasses:对配置类生成代理子类,后续在获取 bean 实例时直接拦截调用,实现单例

enhanceConfigurationClasses 方法

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
	for (String beanName : beanFactory.getBeanDefinitionNames()) {
		BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
		Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
		MethodMetadata methodMetadata = null;
		if (beanDef instanceof AnnotatedBeanDefinition) {
			methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
		}
		if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
			// // 配置类(full or lite)或配置类派生的 @Bean 方法,在这点上找到 bean 具体类型
			AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
			if (!abd.hasBeanClass()) {
				try {
					abd.resolveBeanClass(this.beanClassLoader);
				}
				catch (Throwable ex) {
					throw new IllegalStateException(
							"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
				}
			}
		}
		// 若 configurationClass 属性为 full,满足这个条件塞入到前面的集合中,后面的代码会对这个配置类进行代理增强处理
		if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
			if (!(beanDef instanceof AbstractBeanDefinition)) {
				throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
						beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
			}
			else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
				logger.info("Cannot enhance @Configuration bean definition '" + beanName +
						"' since its singleton instance has been created too early. The typical cause " +
						"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
						"return type: Consider declaring such methods as 'static'.");
			}
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	// 没有需要增强的配置类,立即返回
	if (configBeanDefs.isEmpty()) {
		return;
	}
	// 配置类动态代理增强的核心类
	ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
	for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
		AbstractBeanDefinition beanDef = entry.getValue();
		// 若 @Configuration 配置类被代理,就以目标类 CGLIB 进行代理增强
		beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
		// 为指定的配置类设置代理增强子类
		Class<?> configClass = beanDef.getBeanClass();
		Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
		if (configClass != enhancedClass) {
			if (logger.isTraceEnabled()) {
				logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
						"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
			}
			beanDef.setBeanClass(enhancedClass);
		}
	}
}
  1. 先获取到 BeanDefinition 信息 configurationClass 属性,若当前 BeanDefinition 未找到具体的类型,这边通过类加载器进行加载找到
  2. 判断该属性值是否等于 full,若等于说明当前就是配置类,然后将其加入到待动态代理增强的集合中,该属性值如何设置的,下面再回顾一下:
// ConfigurationClassUtils#checkConfigurationClassCandidate 方法中
// proxyBeanMethods=true 就会设置为 full
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
	beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 若 bean 被 @Configuration 注解标注,且属性 proxyBeanMethods 为 false(使用代理模式),则将 bean 定义记为 lite
else if (config != null || isConfigurationCandidate(metadata)) {
	beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
	return false;
} 
  1. 遍历待动态代理增强的集合,挨个元素进行动态代理实现,生成 CGLIB 动态代理类然后再覆盖到当前的 beanClass 属性,等类初始化、实例化时再进行创建
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
	if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
		if (logger.isDebugEnabled()) {
			logger.debug(String.format("Ignoring request to enhance %s as it has " +
					"already been enhanced. This usually indicates that more than one " +
					"ConfigurationClassPostProcessor has been registered (e.g. via " +
					"<context:annotation-config>). This is harmless, but you may " +
					"want check your configuration and remove one CCPP if possible",
					configClass.getName()));
		}
		return configClass;
	}
	// newEnhancer:创建 CGLIB 必备的 enhancer 实例设置好相关参数,createClass:注入实例
	Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
	if (logger.isTraceEnabled()) {
		logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
				configClass.getName(), enhancedClass.getName()));
	}
	return enhancedClass;
}

/**
 * 创建新的 CGLIB 实例
 */
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(configSuperClass);
	enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
	enhancer.setUseFactory(false);
	// 名称生成策略器,
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	// 自定义的动态代理类生成策略
	enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
	// 回调拦截器类:BeanMethodInterceptor、BeanFactoryAwareMethodInterceptor,当调用配置类下方法时会被拦截处理逻辑
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	return enhancer;
}

动态代理类创建完成,等到 Bean 创建过程时再将这些配置类进行实例化,通过代理对象来调用实际方法的操作

如何确保 @Bean 单例

介绍 BeanMethodInterceptor 拦截器类具体的逻辑前,先解释在 Spring 中是如何确保 @Bean 方法标注的实例是单例存在的,因为 @Configuration 配置类被加载时会被动态代理进行增强,生成代理类,然后 @Bean 方法标注的实例就会经过 BeanMethodInterceptor 拦截器处理,拦截器逻辑内部会调用 beanFactory#getBean 方法,走正常 bean 创建和获取过程,所以在 spring 内部就确保了单例

但不一定所有的配置类 @Configuration 都会是代理类,@Configuration(proxyBeanMethods = false) 如果属性设置为 false,说明该配置类无须被代理,也就是它的 configurationClass 属性为 lite,那么它下面的 @Bean 方法也就不会是单例存在,示例代码如下:

@Configuration(proxyBeanMethods = false)
public class DemoConfiguration {

    @Bean
    public Person person() {
        System.out.println(student());
        System.out.println(student());
        // 运行可以看出以上两个类地址不相同.
        return new Person();
    }

    @Bean
    public Student student() {
        return new Student();
    }
}

普通的 @Component 注解下配置 @Bean 方法不会被代理,也就是说它在获取 bean method 实例时不会走正常 spring bean 获取过程,也就不存在单例了.

BeanMethodInterceptor#intercept 方法

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
			MethodProxy cglibMethodProxy) throws Throwable {
	// 确定 bean 名称,不指定 name 属性默认就是用方法名作为 bean 名称
	ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
	String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
	// 确认当前 bean 方法是否被 @Scope 注解所标注,设置是否需要被代理标识,若当前类正在创建,对 beanName 进行替换
	if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
		String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
		if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
			beanName = scopedBeanName;
		}
	}
	// To handle the case of an inter-bean method reference, we must explicitly check the container for already cached instances.
	// 首先,检查 bean 是否为 FactoryBean,若是的话,先创建好实现该接口的实现类实例,resolveBeanReference 会再调用 getObject 方法返回具体的实例对象
	if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
			factoryContainsBean(beanFactory, beanName)) {
		// 先创建 FactoryBean 接口的实例对象,再判断是属于那种类型
		Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
		if (factoryBean instanceof ScopedProxyFactoryBean) {
			// 在前面的处理中对 @Bean 注解的方法进行了重新定义,如果 proxyMode 属性值不等于 DEFAULT 或 NO 情况下会对 BD 信息进行重新定义,class 就是 ScopedProxyFactoryBean
			// Scoped proxy factory beans are a special case and should not be further proxied
		}
		else {
			// 当前 @Bean 注入的类就是实现了 FactoryBean 接口的,在这里对其进行 CGLIB 代理增强后返回
			return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
		}
	}
	if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
		// 工厂调用 bean 方法为了注册 bean 实例,实际上调用父类方法创建实例
		// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually create the bean instance.
		if (logger.isInfoEnabled() &&
				BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
			logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
							"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
							"result in a failure to process annotations such as @Autowired, " +
							"@Resource and @PostConstruct within the method's declaring " +
							"@Configuration class. Add the 'static' modifier to this method to avoid " +
							"these container lifecycle issues; see @Bean javadoc for complete details.",
					beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
		}
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}
	// 会调用 beanFactory#getBean 方法从一级缓存中获取实例,此操作确保是单例的
	return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
  1. 确认好 bean 名称,并确认当前 @Bean 修饰的方法是否被 @Scope 注解所修饰,设置标识,且进行判断当前修饰的 bean 实例是否正在创建,若当前类仍然在创建,就替换 bean 名称
  2. 检查 bean 是否为 FactoryBean 下接口的实例,包含它的子接口,如果是的话,先创建好该接口实现类的实例,主要是判断其是否为 ScopeProxyFactory 接口类型,如果是不作任何处理,该方法入口主要针对的就是 @Bean + @Scope 注解的逻辑处理,然后在最后一行代码 resolveBeanReference 方法中会调用 getObject 方法返回具体的实例对象
// 如果作用域不是no的话就要使用代理
if (proxyMode != ScopedProxyMode.NO) {
	// BeanDefinition 重新包装为 ScopedProxyFactoryBean 类型
	BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
			new BeanDefinitionHolder(beanDef, beanName), this.registry,
			proxyMode == ScopedProxyMode.TARGET_CLASS);
	beanDefToRegister = new ConfigurationClassBeanDefinition(
			(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
}
  1. resolveBeanReference 方法最为重要,它里面的逻辑才是保证了 @Bean 实例实现单例的正确入口,beanFactory#getBean 进入到正常的 spring 创建过程,若一级缓存已经存在,就不会再次进行创建,当然,一切的前提都是 @Scope 注解的 scopeName 属性为 singleton 的情况下.

总结

该篇文章介绍了 Spring 核心类 ConfigurationClassPostProcessor 一些重要的方法,方法相关的源码也分析完毕,其中涉及到注解的解析,其实只要搞懂了 processConfigBeanDefinitions 方法里面的功能,自动装配的实现理解基本是就可以拿下了;同时,里面有针对性对每个 @Configuration 标注的配置类作了额外处理,是否进行了动态代理增强,来确保被 @Configuration 注解修饰的类下所有 @Bean 方法是否保持单例,这一切可以根据自己当前的业务使用场景来定义.

如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!

推荐专栏:Spring、MySQL,订阅一波不再迷路

大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vnjohn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值