Skip to content

Bean 的实例化过程(基于xml配置方式)

Spring 框架解析xml文件流程

解析xml文件入口

此次分析源码如何解析xml文件的的入口选择了比较常用的ClassPathXmlApplicationContext类,点击查看此类的构造方法

  1. 此方法先调用父类的构造方法
  2. 再创建解析器,解析configLocations属性
  3. 调用父类核心方法refresh(),该方法是spring容器初始化的核心方法。是spring容器初始化的核心流程,spring容器要加载必须执行该方法
java
public ClassPathXmlApplicationContext(
		String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
		throws BeansException {

	// 调用父类的构造方法
	super(parent);
	// 创建解析器,解析configLocations
	setConfigLocations(configLocations);
	// 是否自己刷新spring context
	if (refresh) {
		// 调用父类AbstractApplicationContext的refresh()的方法,是核心方法
		refresh();
	}
}

解析xml文件流程

  1. 通过构造函数,创建对应的上下文对象。调用父类AbstractApplicationContext中的refresh()方法
  2. 做了一些初始化容器的准备工作后,调用父类AbstractApplicationContext的obtainFreshBeanFactory()方法,返回ConfigurableListableBeanFactory对象
  3. obtainFreshBeanFactory()方法中,有模板方法refreshBeanFactory(),由子类去实现具体业务。而此ClassPathXmlApplicationContext读取配置文件是由AbstractRefreshableApplicationContext类去实现

注:如何判断钩子方法是调用那个类的方法,通过创建出来的对象,如:ClassPathXmlApplicationContext对象的类关系去分析即可

ClassPathXmlApplicationContext类关系图

refresh()方法中的ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();。该方法主要进行 xml 解析工作,流程如下:

  1. 创建 XmlBeanDefinitionReader 对象

xml文件解析流程

  1. 通过 Reader 对象加载配置文件

xml文件解析流程

  1. 根据加载的配置文件把配置文件封装成 document 对象

xml文件解析流程

  1. 创建 BeanDefinitionDocumentReader 对象,DocumentReader 负责对 document 对象解析

xml文件解析流程

  1. parseDefaultElement(ele, delegate);负责常规标签解析
  2. delegate.parseCustomElement(ele);负责自定义标签解析

xml文件解析流程

  1. 最终解析的标签封装成 BeanDefinition 并缓存到容器中

Xml 流程分析图

xml流程分析图

自定义标签解析(component-scan 标签为例)

自定义标签解析源码调用逻辑

spring框架是通过spi设计思想来解决自定义标签解析。在DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions()方法中实现,具体的解析委托给BeanDefinitionParserDelegate类来实现,实现流程如下:

  1. 获取自定义标签的 namespace 命名空间。如:xmlns:context="http://www.springframework.org/schema/context"
java
// 根据node获取到node的命名空间,形如:http://www.springframework.org/schema/p
String namespaceUri = getNamespaceURI(node);
  1. 根据命名空间获取NamespaceHandler对象。通过SPI机制 spring 会从所有的 jar 包中扫描 META-INF/spring.handlers 文件,建立 NamespaceUri 和 NamespaceHandler 之间映射关系。spring.handler 文件,其实就是 namespaceUri 和类的完整限定名的映射

  1. DefaultNamespaceHandlerResolver类的resolve方法中,通过反射获取 NamespaceHandler 实例
  2. 调用对应标签(如ContextNameHandler标签)的init()方法完成标签相应的元素解析类的注册,并返回NamespaceHandler实例

  1. 返回处理类的实例对象后,调用parse方法进行标签解析,最终解析的标签封装成BeanDefinition并缓存到容器中
java
handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

parse 解析方法流程分析(以<context:component-scan/>为例)

每个NameHander的init()方法注册不同标签对应的不同的 Parse 解析器,如 <context:component-scan/> 标签的解析是ComponentScanBeanDefinitionParser,其parse方法源码如下:

java
/*
 * 此解析类的parse方法主要需要处理的逻辑如下:
 * 	1. 扫描标签设置的“base-package”属性的包路径,所有.class后缀的文件
 * 	2. 将第1步扫描出来的文件所有相关信息都封装到一个Metadata对象中,再去判断扫描到的类上是否有注解
 * 	3. 将有注解的类包装成BeanDefinition对象
 * 		GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
 * 		genericBeanDefinition.setBeanClass(Xxxx.class);
 * 	4. 完成beanDefinition对象注册到spring容器中
 */
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
	// 获取标签设置的“base-package”属性的值
	String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
	basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);

	// “base-package”可以使用逗号分隔,配置多个扫描的包路径
	String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	// Actually scan for bean definitions and register them.
	// 创建注解扫描器
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
	// 进行扫描,并将扫描到的类封装成BeanDefinition对象。核心方法,重要程度【5】
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);

	/*
	 * 注册一些XxxBeanPostProcessor类,是用于使用注解DI依赖注入(如@Autowired、@Value等) 重要程度【5】
	 *   如:ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等
	 * 	这些BeanPostProcessor接口实现都会在AbstractApplicationContext的refresh()核心方法中的registerBeanPostProcessors方法中进行提前实例化
	 */
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}
  • parse方法主要的处理逻辑总结:
  1. element.getAttribute(BASE_PACKAGE_ATTRIBUTE);方法获取base-package属性
  2. configureScanner(parserContext, element)创建注解扫描器ClassPathBeanDefinitionScanner(扫描所有.class文件)
  3. 通过scanner.doScan方法,扫描类并封装成BeanDefiniton对象
  4. registerComponents(parserContext.getReaderContext(), beanDefinitions, element);方法注册相关BeanPostProcessor类,后面用于注解DI依赖注入

configureScanner 注解扫描器的创建

java
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
	// 使用默认的过滤器,默认就是扫描spring框架的@Service @Component等注解
	boolean useDefaultFilters = true;
	// 判断是否有配置“use-default-filters”属性
	if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
		// 使用xml文件中配置“use-default-filters”的值
		useDefaultFilters = Boolean.parseBoolean(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
	}

	// Delegate bean definition registration to scanner class.
	// 创建注解的扫描器,此方法的主要逻辑是往注解扫描器中注册相关注解过滤器AnnotationTypeFilter(存放到一个List集合中),用于过滤哪些注解需要扫描
	ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
	....省略
	// 解析<context:exclude-filter>与<context:include-filter>两个子标签,将配置包含与不包含的过滤器分别加入
	// ClassPathScanningCandidateComponentProvider类的 List<TypeFilter> excludeFilters 与 List<TypeFilter> includeFilters 属性中
	parseTypeFilters(element, scanner, parserContext);

	return scanner;
}
  1. 扫描过滤器中添加需要扫描的注解类型为Component.class。因此会扫码@Component注解和@Service注解,@Service注解继承自@Component注解

扫描过滤器中添加 include-filterexclude-filter

doScan 注解类的扫描

调用ClassPathBeanDefinitionScannerdoScan方法进行类扫描。通过层层递归扫描base-package下的包,先扫描出classpath:/base-package.class结尾的所有文件,然后再根据过滤器扫描出具有@Service@Component注解的类添加到对应的集合 Set<BeanDefinition>完成BeanDefinition的注册。

java
/*
 * doScan方法实现注解扫描的核心流程:
 * 	1. 扫描基础包basePackages路径下的所有.class文件
 *  2. 通过递归的方式去加载.class文件
 *  3. 判断.class文件中是否存在指定的注解,即includeFilters容器中包含注解,如: @Component
 * 	4. 将符合第3点的的类封装成BeanDefinition对象
 */
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) {
		// 循环每个配置的包路径,扫描到适合要求并有注解的类并封装成BeanDefinition对象
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		// 循环并将BeanDefinition对象中其余属性值补全
		for (BeanDefinition candidate : candidates) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			// 从metadata对象中获取此类的作用范围,是单例还是多例
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				// 支持了@Lazy、@DependOn等注解,即从metadata对象中获取扫描到的类上的注解的值,然后将值设置到BeanDefinition对象中
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);

				// 判断是否需要生成代理(不需要研究)
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);

				// 上面的逻辑都是对BeanDefinition进行创建、设置值后,最后这里是将BeanDefinition注册到BeanDefinitionRegistry容器中
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

循环每个配置的包路径,扫描到适合要求并有注解的类,封装成BeanDefinition对象返并返回

@Lazy@DependOn@Primary等注解支持

registerComponents 组件注册

registerComponents 方法中,注册了几个比较重要的如 ConfigurationClassPostProcessor(扫描@Configuration@Component@Bean注解的解析)、AutowiredAnnotationBeanPostProcessor(扫描@Value@Autowired注解)、CommonAnnotationBeanPostProcessor

例如:ConfigurationClassPostProcessor类对@Configuration@Component@Bean注解扫描与解析

invokeBeanFactoryPostProcessors 方法调用

方法的作用

AbstractApplicationContext类的refresh()核心方法,invokeBeanFactoryPostProcessors方法的作用是:在Bean实例化前,BeanDefinitionRegistry与BeanFactory初始化后,实例化BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor接口的实现类,并且调用接口的postProcessBeanDefinitionRegistry()postProcessBeanFactory()方法

java
/*
 * 在Singleton的Bean对象初始化前,对Bean工厂进行一些处理
 * 此方法完成实例化以下两个接口的实现类,并且调用postProcessBeanDefinitionRegistry()方法
 * 		BeanDefinitionRegistryPostProcessor
 *  	BeanFactoryPostProcessor
 */
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

以上两个接口的调用,是完成对 BeanDefinition 的动态修改

java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// 此方法完成 BeanFactoryPostProcessor 与 BeanDefinitionRegistryPostProcessor 接口所有实现类的实例化与postProcessBeanDefinitionRegistry()方法的调用 重要程度【5】
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

BeanDefinitionRegistryPostProcessor 接口的方法调用

接口的作用

这个接口的理解:用于获取 BeanDefinitionRegistry 对象,获取到此对象就可以获取这个对象中注册的所有 BeanDefinition 对象,就可以完成里面所有 BeanDefinition 对象的新增、修改、删除、查询操作。

在spring中的调用时机

在AbstractApplicationContext类的refresh()方法中,调用invokeBeanFactoryPostProcessors(beanFactory)方法。BeanDefinitionRegistryPostProcessor 这个接口的调用分为三步:

  1. 调用实现了 PriorityOrdered 排序接口
  2. 调用实现了 Ordered 排序接口
  3. 没有实现接口的调用

接口主要作用的案例

BeanDefinition 的增删改查操作
java
package com.moon.spring.postprocessor;

import com.moon.spring.bean.BeanToAdd;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

/**
 * 自定义 BeanDefinitionRegistryPostProcessor 实现基础功能示例
 */
// PriorityOrdered(排序,优先级)接口是用于Spring创建同一类型的Bean时进行排序
@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
    /*
     * 在spring容器加载,加载xml配置文件解析(注解扫描),生成所有BeanDefinition 后,在bean实例化前的执行此方法
     * 所以可以使用此接口方法手动 BeanDefinition 的动态修改,完成对Spring容器里面所有 BeanDefinition 对象的新增、修改、删除、查询操作
     * @param registry 这是Spring框架的BeanDefinition的注册器,此注册器可以获取所有spring容器管理的BeanDefinition对象
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 通过BeanDefinitionRegistry注册容器,可以查询所有已注册的BeanDefinition
        final String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
            System.out.println(beanDefinition);
        }

        /* *************************** 手动新增BeanDefinition注册 *************************************/
        // 创建GenericBeanDefinition对象
        GenericBeanDefinition bdToAdd = new GenericBeanDefinition();
        // 设置需要实例化的类
        bdToAdd.setBeanClass(BeanToAdd.class);

        // 如果需要实例化的类中属性赋值,需要获取MutablePropertyValues属性,赋值到此属性中
        MutablePropertyValues propertyValues = bdToAdd.getPropertyValues();
        propertyValues.addPropertyValue("value", "实现BeanDefinitionRegistryPostProcessor接口,手动创建BeanDefinition对象并注册到spring容器中");

        // 将BeanDefinition对象注册到spring容器中,spring实例化对象,必须将beanName与BeanDefinition对象进行映射。(即添加到beanDefinitionMap属性中)
        registry.registerBeanDefinition("beanToAdd", bdToAdd);

        /* *************************** 手动修改原已注册的BeanDefinition *************************************/
        // 从BeanDefinitionRegistry中获取BeanDefinition对象
        BeanDefinition bdToEdit = registry.getBeanDefinition("beanToEdit");

        // 如果需要实例化的类中属性赋值,需要获取MutablePropertyValues属性,赋值到此属性中
        MutablePropertyValues bdToEditPropertyValues = bdToEdit.getPropertyValues();
        bdToEditPropertyValues.addPropertyValue("value", "我是通过实现BeanDefinitionRegistryPostProcessor接口后修改的值");

        /* *************************** 手动删除原已注册的BeanDefinition *************************************/
        // 根据beanName删除BeanDefinition
        registry.removeBeanDefinition("beanToDelete");
    }

    /*
     * 此方法是父接口BeanFactoryPostProcessor的方法
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }

    @Override
    public int getOrder() {
        // Spring根据此数值在创建Bean时,进行排序。数值越少越优先
        return 0;
    }
}
自定义注解扫描

可以通过实现BeanDefinitionRegistryPostProcessor接口,实现自定义注解扫描及其所作用的类注册到spring容器中

  1. 创建两种自定义注解
java
/**
 * 自定义注解
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomAnnotation {
    String value() default "";
}

/**
 * 自定义注解,继承 Spring 的 @Component
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface CustomComponent {
    String value() default "";
}
  1. 分别标识在原本配置的包扫描路径(com.moon.spring)下的相关类,与标识在新配置的包扫描路径(cn.moon.autumn)下的相关类

  1. 实现BeanDefinitionRegistryPostProcessor接口,创建自定义注解扫描器
java
package com.moon.spring.postprocessor;

import com.moon.spring.annotation.CustomAnnotation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;

/**
 * 自定义 BeanDefinitionRegistryPostProcessor 案例,实现扫描自定义注解
 */
@Component
public class CustomAnnotationScanPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        /* ============ 自定义注解注册 ============ */
        // 1. 创建扫描器,将BeanDefinitionRegistry(注册器)传入
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
        // 2. 将自定义注解添加注解过滤器中
        scanner.addIncludeFilter(new AnnotationTypeFilter(CustomAnnotation.class));
        /*
         * 3. 设置扫描的包路径
         *   注:1. 如不设置扫描包路径,则不会生效。
         *      2. 设置此扫描包路径,会与spring原生@Component及其衍生注解一起会扫描
         */
        scanner.scan("cn.moon.autumn");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
  1. 测试
java
/* 自定义注解扫描测试 */
@Test
public void testCustomAnnotationScan() {
    // 读取spring类路径下的配置文件(xml文件中只配置了扫描 com.moon.spring 包)
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    // 获取实例工厂
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    // 输出工厂所有bean实例名称
    String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
    for (String name : beanDefinitionNames) {
        System.out.println(name);
    }
    /*
     * 输出结果节选如下:
     *   beanCustomComponent
     *   otherPackageBeanCustomAnnotation
     *   otherPackageBeanCustomComponent
     * 从结果总结:
     *  1. 通过实现BeanDefinitionRegistryPostProcessor接口中增加需要扫描的自定义注解,只在定义时设置的包扫描路径才生效,原xml配置的包扫描路径无法扫描到此自定义注解
     *  2. 设置扫描自定义注解的路径,也会扫描Spring原生@Component及其衍生注解
     *  3. 自定义注解继承了Spring原生@Component注解,作用的类也同样可以被扫描并注册到spring容器中
     */
}
BeanFactory 参数的修改

实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanFactory方法可以获取到BeanFactory实例,从而可以实现对BeanFactory的一些参数修改,及其所有注册的BeanDefinition对象

java
@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    }

    /*
     * 此方法是父接口BeanFactoryPostProcessor的方法
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        /*
         * BeanFactory 对象一样可以拿到所有的BeanDefinition对象,因为BeanFactory的相关实现类也都会实现 BeanDefinitionRegistry 接口
         */
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 从注册中心获取所有注册的BeanDefinition的名称
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();

        for (String bdName : beanDefinitionNames) {
            System.out.println("BeanDefinition的名称" + bdName);
            System.out.println(registry.getBeanDefinition(bdName));
        }

        /* 修改BeanFactory相关的参数 */
        DefaultListableBeanFactory beanFactory1 = (DefaultListableBeanFactory) beanFactory;
        beanFactory1.setAllowBeanDefinitionOverriding(true);
        beanFactory1.setAllowCircularReferences(true);
        beanFactory1.setAllowRawInjectionDespiteWrapping(true);
    }
}

BeanFactoryPostProcessor 接口的方法调用

此调用的流程与BeanDefinitionRegistryPostProcessor一样,在BeanDefinitionRegistryPostProcessor接口调用后进行调用

registerBeanPostProcessors 方法调用

BeanPostProcessor 源码

java
public interface BeanPostProcessor {
	/* 实例化前需要做的工作 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/* 实例化后需要做的工作 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

BeanPostProcessor 接口的作用

BeanPostProcessor(后置处理器):这个接口里面有两个方法,可以进行相应的操作,bean实例化前的操作,以及bean实例化后的操作,这个实例化在其他正常的实例化方法之前,比如可以阻止其他 bean 的 IOC 依赖注入,把实现了 BeanPostProcessor 接口的类实例化,并且加入到 BeanFactory

BeanPostProcessor 的注册

在AbstractApplicationContext类的refresh()方法中,调用registerBeanPostProcessors(beanFactory);方法。此方法完成了 BeanPostProcessor 的注册,就是把实现 BeanPostProcessor 接口的类提前实例化

  1. 此方法里面一开始就获取到 BeanFactory 中所有注册的 BeanDefinition 对象的名称 beanName。
java
public static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

	// 获取到工程里面所有实现了BeanPostProcessor接口的类,获取到BeanDefinition的名称
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
	....
}
  1. 然后判断是否实现了 PriorityOrdered 排序接口、Ordered 排序接口、或者无实现排序接口,getBean 方法是将该 ppName 对应的 BeanDefinition 对象实例化
java
/// 提前实例化BeanPostProcessor类型的bean,然后bean进行排序
for (String ppName : postProcessorNames) {
	if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		// getBean是实例化方法,是bean实例化过程
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		priorityOrderedPostProcessors.add(pp);
		// 判断类型是否为MergedBeanDefinitionPostProcessor,如果是则代码是内部使用的
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
		orderedPostProcessorNames.add(ppName);
	}
	else {
		nonOrderedPostProcessorNames.add(ppName);
	}
}
  1. 把对应的 BeanPostProcessor 对象注册到 BeanFactory 中,BeanFactory 中有一个 List 容器(private final List<BeanPostProcessor> beanPostProcessors)接收
java
// 注册到BeanFactory中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
java
/* 注册的BeanPostProcessor所有实例都存放在BeanFactory的 private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>(); 容器中 */
private static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

	for (BeanPostProcessor postProcessor : postProcessors) {
		beanFactory.addBeanPostProcessor(postProcessor);
	}
}

initMessageSource 初始化消息资源接口的实现类(待整理)

java
// 初始化消息资源接口的实现类。主要用于处理国际化(i18n),重要程度【2】
// Initialize message source for this context.
initMessageSource();

initApplicationEventMulticaster 容器注册与初始化事件管理类

源码

java
protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	// 判断spring容器中是否存在事件管理类applicationEventMulticaster
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		// 从容器中获取事件管理类实例
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		// 没有则创建一个新的事件管理类
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		// 手动创建事件管理类实例,通过BeanFactory的registerSingleton方法注册到spring容器中
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
					"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
		}
	}
}

作用

此方法是AbstractApplicationContext.refresh()方法的流程之一,作用是为容器注册与初始化事件管理类

onRefresh

源码

java
/*
 * 在AbstractApplicationContext的子类中初始化其他特殊的bean
 * 此方法重点理解模板设计模式,因为在springboot中,此方法是用来完成内嵌式tomcat启动
 */
// Initialize other special beans in specific context subclasses.
onRefresh();
java
/**
 * Template method which can be overridden to add context-specific refresh work.
 * Called on initialization of special beans, before instantiation of singletons.
 * <p>This implementation is empty.
 * @throws BeansException in case of errors
 * @see #refresh()
 */
protected void onRefresh() throws BeansException {
	// For subclasses: do nothing by default.
}

作用

此方法是AbstractApplicationContext.refresh()方法的流程之一,是典型的钩子方法,是模板设计模式。此方法是在一般的spring实现中,都是空方法,没有任何逻辑。但在SpringBoot中,就在此方法中完成一些事情,如tomcat的启动等等工作。

registerListeners 注册事件类应用的监听器

作用

此方法是AbstractApplicationContext.refresh()方法的流程之一,作用是往事件管理类中注册事件类应用的监听器,就是注册实现了ApplicationListener接口的监听器bean。前面的initApplicationEventMulticaster()方法是用于初始化事件管理类

Spring 标准事件与自定义事件使用示例

  1. 创建自定义事件类,需继承Spring的ApplicationEvent事件类
java
package com.moon.spring.event;

import org.springframework.context.ApplicationEvent;

/**
 * 自定义Spring事件,需要继承Spring的 ApplicationEvent 事件类
 */
public class CustomEvent extends ApplicationEvent {

    private String content;

    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public CustomEvent(Object source, String content) {
        super(source);
        this.content = content;
    }
    // accessor and other methods...
}
  1. 创建自定义事件监听类,需实现Spring的ApplicationListener接口,实现onApplicationEvent方法,当监听到相应事件发布时会执行该方法
java
package com.moon.spring.listener;

import com.moon.spring.event.CustomEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 自定义spring事件监听器,需实现spring框架的 ApplicationListener 接口
 */
// 实现ApplicationListener接口可以指定事件的类型,也可以不指定。
// @Component  // 如果要容器加载后直接发布事件被监听到,需要使用@Component等注解将当前类注册到spring容器中
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("自定义事件CustomEvent发布,内容是:" + event.getContent());
    }
}

// public class CustomEventListener implements ApplicationListener {
//     @Override
//     public void onApplicationEvent(ApplicationEvent event) {
//         /*
//          * 如果不指定监听的事件类型,此时方法的入参是spring的事件类ApplicationEvent
//          * 可以在方法进行类型的判断,再执行相应的逻辑
//          */
//         if (event instanceof CustomEvent) {
//             // do something...
//         }
//     }
// }
  1. 创建Spring标准事件监听类,也需要实现Spring的ApplicationListener接口,只需要指定接口泛型为spring提供的标准事件即可,当监听到相应的事件发布时,onApplicationEvent方法执行
java
package com.moon.spring.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
 * spring标准事件监听类,监听ContextRefreshedEvent事件,容器完成加载成功后发布此事件
 */
@Component
public class SpringRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("========SpringRefreshedListener容器加载完成了=========");
    }
}
  1. 测试
java
@Test
public void testPublishEvent() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.moon.spring");
    /*
     * 如果容器加载完成后直接手动发布事件,则相应的事件监听类必须要使用xml配置或者@Component等注解注册到spring容器中
     *  如监听类没有使用@Component注解,则此次发布的事件无法监听到
     */
    context.publishEvent(new CustomEvent(context, "我是自定义事件!"));

    // 如果容器启动时没有将监听类注册到spring容器,可以在启动容器后手动设置监听类,然后再发布事件
    context.addApplicationListener(new CustomEventListener());
    context.publishEvent(new CustomEvent("可以传入任何值", "我是手动设置监听后,再发布的自定义事件!!"));

    // spring框架提供的标准事件
    context.start(); // 调用当前方法,spring会发布ContextStartedEvent事件
    context.stop(); // 调用当前方法,spring会发布ContextStoppedEvent事件

    /*
     * 输出结果如下:
     *  ========SpringRefreshedListener容器加载完成了=========
     *  自定义事件CustomEvent发布,内容是:我是手动设置监听后,再发布的自定义事件!!
     *  ========ContextStartedListener上下文开始事件监听========
     *  ========ContextStoppedListener上下文停止事件监听========
     */
}

Spring 事件的处理流程

官网:Event handling in the ApplicationContext is provided through the ApplicationEvent class and the ApplicationListener interface. If a bean that implements the ApplicationListener interface is deployed into the context, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified. Essentially, this is the standard Observer design pattern.

Spring框架是通过ApplicationEvent类和ApplicationListener接口提供了ApplicationContext中对于事件处理功能。如果将实现ApplicationListener接口的监听类注册到spring容器中,则每次ApplicationEvent发布到ApplicationContext时,都会调用到该监听类的相应方法。这个本质就是标准的观察者设计模式。

Spring 提供的标准事件列表

事件说明
ContextRefreshedEvent上下文更新事件,在调用ConfigurableApplicationContext接口上的refresh()方法初始化或刷新ApplicationContext时被触发
ContextStartedEvent上下文开始事件,在调用ConfigurableApplicationContext接口上的start()方法开始/重新开始容器时触发该事件
ContextStoppedEvent上下文停止事件,在调用ConfigurableApplicationContext接口上的stop()方法停止容器时触发该事件
ContextClosedEvent上下文关闭事件,在调用ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁
RequestHandledEvent请求处理事件,在Web应用中,当一个http请求(request)结束触发该事件。此事件仅适用于使用Spring的DispatcherServlet的Web应用程序。
ServletRequestHandledEventRequestHandledEvent的子类,添加了特定于Servlet的上下文信息

源码

此方法是AbstractApplicationContext.refresh()方法的流程之一,作用是往事件管理类中注册事件类应用的监听器

java
/*
 * 往事件管理类中注册事件类应用的监听器,就是注册实现了ApplicationListener接口的监听器bean
 * 	此方法会与initApplicationEventMulticaster()方法成对出现的
 */
// Check for listener beans and register them.
registerListeners();
  • 注册监听类
java
/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
protected void registerListeners() {
	// Register statically specified listeners first.
	// 获取原有静态监听器,并且注册
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	// 从spring容器中获取实现ApplicationListener接口的监听器类的beanName
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	// Publish early application events now that we finally have a multicaster...
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			// 发布事件
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}
  • 通过事件管理器实现类SimpleApplicationEventMulticaster,进行事件的发布与监听器的onApplicationEvent方法的调用
java
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	// getApplicationListeners方法是获取前端在registerListeners()方法中注册了的所有监听类集合
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		// 循环集合,发布事件并调用相应监听类实现的onApplicationEvent方法
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}

ContextRefreshedEvent 事件的执行时机

AbstractApplicationContext.refresh()方法的流程中的finishRefresh()方法中,完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布ContextRefreshedEvent事件

java
/**
 * Finish the refresh of this context, invoking the LifecycleProcessor's
 * onRefresh() method and publishing the
 * {@link org.springframework.context.event.ContextRefreshedEvent}.
 */
protected void finishRefresh() {
	// Clear context-level resource caches (such as ASM metadata from scanning).
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}

【重点】Bean实例化核心方法 finishBeanFactoryInitialization

此方法是Bean实例化的核心流程,所以单独一个章节

java
/*
 * 实例化所有剩余的(非lazy init)单例。(就是没有被@Lazy修饰的单例Bean)
 * 此方法是spring中最重要的方法(没有之一),重要程度【5】。
 * 所以此方法要重点理解分析,此方法具体作用如下:
 * 		1. bean实例化过程
 * 		2. ioc
 * 		3. 注解支持
 * 		4. BeanPostProcessor的执行
 *		5. Aop的入口
 */
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
java
/**
 * Finish the initialization of this context's bean factory,
 * initializing all remaining singleton beans.
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// 设置类型转换器(暂时未研究)
	// Initialize conversion service for this context.
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// 此方法没有什么作用,暂时未研究
	// Register a default embedded value resolver if no bean post-processor
	// (such as a PropertyPlaceholderConfigurer bean) registered any before:
	// at this point, primarily for resolution in annotation attribute values.
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// 暂时未研究
	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();

	// 此方法为重点,重要程度【5】
	// Instantiate all remaining (non-lazy-init) singletons.
	beanFactory.preInstantiateSingletons();
}

preInstantiateSingletons 实例化主流程方法

DefaultListableBeanFactory抽象类中的preInstantiateSingletons方法,此方法是具体实例化过程

java
@Override
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	/* 在分析xml解析时研究过,就是所有beanDefinition对象对应的beanName都缓存到beanDefinitionNames容器中 */
	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		// 把父BeanDefinition里面的属性拿到子BeanDefinition中,相当于涉及两个BeanDefinition的合并
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

		// 如果配置的bean不是抽象的,单例的,非懒加载的就实例化
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);

				// 判断bean是否实现了FactoryBean接口,暂时未研究
				if (bean instanceof FactoryBean) {
					FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(
								(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				// 实例化过程,重要程度【5】
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

通过判断!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit(),即判断当前准备创建的类是:非抽象、单例类、非懒加载。如果符合条件,则实例化。

在此处实例化会分成普通bean实例以及实现factorybean接口的bean实例化。其核心方法是getBean(beanName);

getSingleton 方法(获取单例)

源码

核心代码位置:

java
AbstractBeanFactory.doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)

此方法开始就通过Object sharedInstance = getSingleton(beanName);方法获取缓存中的实例,判断缓存中是否存在 Bean 的实例(无,则新创建 Bean)

java
protected <T> T doGetBean(
		String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
		throws BeansException {
	/*
	 * 将方法传入的bean名称转成对应spring容器的保存真正的beanName
	 * 	因为传入的参数可以是alias,也可能是FactoryBean的name,所以需要进行解析,包含以下内容:
	 * 		1. 如果是FactoryBean,则去掉修饰符“&”
	 * 		2. 沿着引用链获取alias对应的最终name
	 */
	String beanName = transformedBeanName(name);
	Object bean;

	/*
	 * 检查缓存或者实例工厂中是否有对应的单例
	 * 	在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
	 * 	Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提前曝光(将对应的ObjectFactory加入到缓存)
	 * 	一旦下一个bean创建需要依赖上一个bean,则直接使用ObjectFactory对象
	 */
	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	// 如果缓存里面能拿到实例
	if (sharedInstance != null && args == null) {
		// 实例已存在
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// 这个方法是FactoryBean接口的调用入口
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
    ......
    // Create bean instance.
    if (mbd.isSingleton()) {
    	// 此逻辑是重点,因为大部分情况都是单例的
    	sharedInstance = getSingleton(beanName, () -> {
    		try {
    			// 创建bean实例核心逻辑
    			return createBean(beanName, mbd, args);
    		}
    		catch (BeansException ex) {
    			// Explicitly remove instance from singleton cache: It might have been put there
    			// eagerly by the creation process, to allow for circular reference resolution.
    			// Also remove any beans that received a temporary reference to the bean.
    			destroySingleton(beanName);
    			throw ex;
    		}
    	});
    	// 此方法是FactoryBean接口的调用入口
    	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    ......
}

getSingleton 两个重载方法

java
/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference)


/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 * @param beanName the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 * with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)

doGetBean方法中执行流程,有getSingleton两个重载的方法

  • 第一个getSingleton方法是根据beanName从缓存中获取单例对象。并且检查是否允许循环依赖
  • 第二个getSingleton方法也是根据beanName从缓存中获取单例对象,如果缓存中没有,则创建一个新的实例对象

getSingleton 从缓存中获取 Bean 实例的过程

java
/* 根据beanName从缓存中获取实例 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// 1. 先从一级缓存查找获取对象实例(如果类的实例化全部完成后,都是从此容器中获取;如第一次进入此方法时,里面是没有相应的实例)
	Object singletonObject = this.singletonObjects.get(beanName);
	// 如果bean还正在创建,还没创建完成,其实就是堆内存有了,属性还没有DI依赖注入
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			// 2. 再从二级缓存中查找获取对象实例
			singletonObject = this.earlySingletonObjects.get(beanName);

			// 判断如果没有查找到,并且允许bean提前暴露
			if (singletonObject == null && allowEarlyReference) {
				// 3. 从三级缓存中拿到对象工厂
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					// 从工厂中拿到对象
					singletonObject = singletonFactory.getObject();
					// 升级到二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
					// 删除三级缓存
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}
  • 此方法的主要处理流程:
  1. 先从singletonObjects(一级缓存)中获取单例实例
  2. 判断一级缓存中没有,并且是正在创建中,则再从earlySingletonObjects(二级缓存)中获取
  3. 如果二级缓存中没有,并且是允许实例提前暴露,则再从singletonFactories(三级缓存)中获取。
  4. 如果三级缓存中也没有,则直接返回null;如果三级缓存中存在实例,则将实例存入二级缓存,并且将其实例对象从三级缓存中删除。(这个操作主要是用于循环依赖

beforeSingletonCreation

方法开始,调用this.singletonObjects.get(beanName);方法,从一级缓存中获取实例,如果一级缓存中有,说明bean实例化已完成,则直接返回;如果一级缓存中没有,说明bean还没有实例化,则进行创建

beforeSingletonCreation(beanName);方法把 beanName 添加到 singletonsCurrentlyInCreation 的 Set 容器中,在这个集合里面的 bean 都是正在实例化的 bean,就是实例化还没做完的 BeanName

java
/**
 * Callback before singleton creation.
 * <p>The default implementation register the singleton as currently in creation.
 * @param beanName the name of the singleton about to be created
 * @see #isSingletonCurrentlyInCreation
 */
protected void beforeSingletonCreation(String beanName) {
	// 把beanName添加到singletonsCurrentlyInCreation的Set容器中,在这个集合里面的bean都是正在实例化的bean
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
		// 如果需要创建的beanName不在inCreationCheckExclusions容器(存储排除创建的)中,并且singletonsCurrentlyInCreation容器(存储正在创建的)已经存在,抛出异常
		throw new BeanCurrentlyInCreationException(beanName);
	}
}

singletonFactory.getObject

在执行Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法的过程中,调用了singletonObject = singletonFactory.getObject();方法(即会调用外层的lambda表达式的逻辑)。调到 getObject 方法,完成 bean 的实例化。

afterSingletonCreation

getObject方法调用完后,就代表着 Bean 实例化已经完成了,此后还需要进行以下两步操作:

  1. 调用afterSingletonCreation(beanName);方法,主要的作用是,要bean实例创建完成后,根据 beanName 从singletonsCurrentlyInCreation容器(存储正在实例化的bean的集合)中删除该bean
java
/**
 * Callback after singleton creation.
 * <p>The default implementation marks the singleton as not in creation anymore.
 * @param beanName the name of the singleton that has been created
 * @see #isSingletonCurrentlyInCreation
 */
protected void afterSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
		throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
	}
}

注:如果正在实例化的容器中,根据beanName没有可删除的元素时,会抛出异常

  1. 调用addSingleton(beanName, singletonObject);方法,主要的作用是,创建对象成功后,把bean对象实例缓存到singletonObjects一级缓存中,删除二、三级缓存(earlySingletonObjectssingletonFactories),并注册bean实例化名称到容器(registeredSingletons)中
java
/**
 * Add the given singleton object to the singleton cache of this factory.
 * <p>To be called for eager registration of singletons.
 * @param beanName the name of the bean
 * @param singletonObject the singleton object
 */
protected void addSingleton(String beanName, Object singletonObject) {
	synchronized (this.singletonObjects) {
		// 设置实例到一级缓存
		this.singletonObjects.put(beanName, singletonObject);
		// 将创建好的bean的名称从三级缓存中移除
		this.singletonFactories.remove(beanName);
		// 将创建好的bean的名称从二级缓存中移除
		this.earlySingletonObjects.remove(beanName);
		// 保存已注册到容器的bean实例的名称
		this.registeredSingletons.add(beanName);
	}
}

涉及相关重要的核心属性

DefaultSingletonBeanRegistry类中的singletonObjects属性,此属性是Map结构容器,用于存在完全实例化的对象。

完全实例化对象:指的是此类创建出对象,并且类里的所有属性与DI(依赖注入)都全部已经完成

createBean 方法

源码位置

createBean的代码位置:AbstractBeanFactory.doGetBean() 方法中调用,其具体实现在AbstractAutowireCapableBeanFactory.createBean,此方法是 bean 实例化核心方法。

在实例化bean的方法中,会把 bean 实例化,并且包装成 BeanWrapper。注:但此时不涉及DI(依赖注入)

doCreateBean 方法

createBeanInstance 方法

doCreateBean方法中对应创建 Bean 实例的方法是createBeanInstance。会将bean实例化,并且包装成BeanWrapper对象返回

java
instanceWrapper = createBeanInstance(beanName, mbd, args);

此方法主要处理的内容

  1. 实例化factoryMethod方法相应的实例
  2. 实例化标识@Autowired注解的有参构造函数
  3. 实例化没有@Autowired注解的有参构造函数
  4. 实例化无参构造函数

获取bean的Class对象

该方法首先通过beanName,反射获取将要实例化的bean的Class对象

java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	// Make sure bean class is actually resolved at this point.
	// 通过反射获取Class对象
	Class<?> beanClass = resolveBeanClass(mbd, beanName);
	....

createBeanInstance 对 FactoryMethodName 属性的处理

源码分析

进入createBeanInstance(beanName, mbd, args);方法中,会有判断当前创建中类(BeanDefinition对象)的FactoryMethodName属性是否为空,如果不为空,则调用instantiateUsingFactoryMethod()方法进行factory-method的实例处理,核心代码如下:

这个方法主要逻辑是:如果有FactoryMethodName属性,则反射调用类中的 factoryMethod 方法。这要知道 @Bean 方法的原理,实际上 spring 会扫描有 @Bean 注解的方法,然后把方法名称设置到 BeanDefinition 的 factoryMethod 属性中,接下来就会调到上面截图中的方法实现 @Bean 方法的调用。该方法里面的参数解析过程不需要了解。

java
public BeanWrapper instantiateUsingFactoryMethod(
		String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

	// 创建一个包装类
	BeanWrapperImpl bw = new BeanWrapperImpl();
	this.beanFactory.initBeanWrapper(bw);

	Object factoryBean;
	Class<?> factoryClass;
	// 此标识用于判断配置的factory-method方法是否为静态方法
	boolean isStatic;

	// 获取factoryBean的name(相当于factory-method所在的类的名称)
	String factoryBeanName = mbd.getFactoryBeanName();
	if (factoryBeanName != null) {
		if (factoryBeanName.equals(beanName)) {
			throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
					"factory-bean reference points back to the same bean definition");
		}
		// 如果配置了factory-bean属性,则先实例此factoryBean
		factoryBean = this.beanFactory.getBean(factoryBeanName);
		/*
		 * 判断当前正在实例化的bean是单例的,并且根据beanName在容器中找到此实例已存在,抛出异常。
		 * 	因为配置了factory-method属性,当前实例是从factory-method属性相应的方法来实例化的
		 */
		if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
			throw new ImplicitlyAppearedSingletonException();
		}
		// 获取配置的factory-bean的Class对象
		factoryClass = factoryBean.getClass();
		// 设置方法标识为false,即factoryMethod要为非静态方法
		isStatic = false;
	}
	else {
		// It's a static factory method on the bean class.
		// 如果没配置factory-bean属性(即factoryBeanName值为空),进入此分支,此时如果也没有配置class属性,则抛出异常
		if (!mbd.hasBeanClass()) {
			throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
					"bean definition declares neither a bean class nor a factory-bean reference");
		}
		factoryBean = null;
		// 如果没有配置factory-bean属性,则获取当前类的Class类对象
		factoryClass = mbd.getBeanClass();
		// 设置方法标识为true,即factoryMethod需要为静态方法
		isStatic = true;
	}

	Method factoryMethodToUse = null;
	ArgumentsHolder argsHolderToUse = null;
	Object[] argsToUse = null;

	if (explicitArgs != null) {
		argsToUse = explicitArgs;
	}
	else {
		Object[] argsToResolve = null;
		synchronized (mbd.constructorArgumentLock) {
			factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
			if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
				// Found a cached factory method...
				argsToUse = mbd.resolvedConstructorArguments;
				if (argsToUse == null) {
					argsToResolve = mbd.preparedConstructorArguments;
				}
			}
		}
		if (argsToResolve != null) {
			// 对方法参数的解析,获取参数列表,再一个个去判断参数类型,还要判断参数上是否有注解,比较难理解。暂时未研究
			argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
		}
	}

	if (factoryMethodToUse == null || argsToUse == null) {
		// Need to determine the factory method...
		// Try all methods with this name to see if they match the given arguments.
		factoryClass = ClassUtils.getUserClass(factoryClass);

		List<Method> candidates = null;
		if (mbd.isFactoryMethodUnique) {
			if (factoryMethodToUse == null) {
				factoryMethodToUse = mbd.getResolvedFactoryMethod();
			}
			if (factoryMethodToUse != null) {
				candidates = Collections.singletonList(factoryMethodToUse);
			}
		}
		if (candidates == null) {
			candidates = new ArrayList<>();
			// 获取类中所有方法对象
			Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
			for (Method candidate : rawCandidates) {
				/*
				 * 判断当前循环的方法是否与上面的isStatic标识一致,并且方法的名称等于配置的factoryMethod属性值
				 * 注:Modifier.isStatic()方法是jdk的方法,用于判断方法是否为静态方法
				 */
				if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
					candidates.add(candidate);
				}
			}
		}
		.....
}

factory-method 两种调用形式总结

  1. 配置factory-bean属性,factory-method指定类中的非静态方法
  2. 如不配置factory-bean属性,则必须配置class属性,并且factory-method指定类中的静态方法

createBeanInstance 对不同类型的构造函数处理

标识 @Autowired 注解的有参构造函数实例化过程

测试示例:

java
@Component
public class AutowiredConstructorComponent {
    /**
     * 用于测试标识`@Autowired`注解的有参构造函数实例化过程
     */
    @Autowired
    public AutowiredConstructorComponent(ComponentA a, ComponentB b) {
        System.out.println(a);
        System.out.println(b);
    }
}

如果没有配置factoryMethod属性,则继续往下执行到determineConstructorsFromBeanPostProcessors方法,此方法是 BeanPostProcessor 接口类的首次应用,最终会调到 AutowiredAnnotationBeanPostProcessor 类的方法,在方法中会扫描有注解的构造函数然后完成装配过程,然后会将标识了@Autowired注解的构造函数返回

java
// Candidate constructors for autowiring?
// 寻找当前正在实例化的bean中是否有 @Autowired 注解的构造函数。核心代码,重要程度【5】
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // 此方法获取类的构造函数(多个,返回数组)
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
		mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
	// 如果ctors不为空,就说明构造函数上有@Autowired注解
	return autowireConstructor(beanName, mbd, ctors, args);
}

determineConstructorsFromBeanPostProcessors() 方法源码如下:主要处理逻辑是,获取所有的 BeanPostProcessor 接口类型的求对象,然后判断是否是SmartInstantiationAwareBeanPostProcessor 类型的,然后循环调用接口的 determineCandidateConstructors 方法,该方法的作用是获取所有@Autowired注解的构造函数

注:此循环中所有SmartInstantiationAwareBeanPostProcessor类型的实现类都会进入if判断中,并且执行了determineCandidateConstructors方法,但如果不是处理此个功能的实现类只需要返回 null 即可,所以此处的逻辑只会AutowiredAnnotationBeanPostProcessor会起作用

java
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
		throws BeansException {

	if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
		// getBeanPostProcessors()方法获取所有注册到BeanFactory里的BeanPostProcessor,在此处进行循环调用
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			// 筛选实现了SmartInstantiationAwareBeanPostProcessor接口的BeanPostProcessor
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
				/*
				 * 此处只有AutowiredAnnotationBeanPostProcessor类会起作用,其他的实现类(不关注此功能的)只需要返回null即可
				 * 	这里是spring进行了功能的埋点,日后如果需要进行功能扩展,
				 * 	只需要实现SmartInstantiationAwareBeanPostProcessor接口,将业务逻辑写在determineCandidateConstructors方法中
				 */
				Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
				if (ctors != null) {
					return ctors;
				}
			}
		}
	}
	return null;
}

上面已经拿到正在实例化的类的带有@Autowired构造函数,然后autowireConstructor方法是获取构造参数的过程

java
/* AbstractAutowireCapableBeanFactory 类 */
protected BeanWrapper autowireConstructor(
		String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
	return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

调用ConstructorResolver类中的autowireConstructor方法,处理标识有@Autowired注解的构造函数

此处的descriptor.resolveCandidate方法实际是通过getBean方法来获取实例

当上面的构造函数的入参都创建完成后,通过构造函数对象反射实例化

总结:由以上源码分析可知,不管是Field,Method、或者是构造函数,凡是使用@Autowired注解,如果自动注入的参数是一个引用的类型,就会触发这个引用类型的getBean方法来进行实例化,获取bean实例

无 @Autowired 注解的有参构造函数实例化过程

当实例化的类中有一个无@Autowired的有参数构造函数时,spring是可以正常实例化该类;如果多个无标识@Autowired的有参构造函数时,实例化时会报错,但报错非spring框架的错误,而是会报实例化时找不到构造函数。因为这种情况下,spring框架实例化会去找无参构造函数。如不让程序报错,增加无参构造函数即可

java
public AutowiredConstructorComponent(ComponentA a, ComponentB b) {
    System.out.println(a);
    System.out.println(b);
}

public AutowiredConstructorComponent(ComponentA a) {
    System.out.println(a);
}

分析源码AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors

无参构造函数的实例化过程

通过上面有@Autowired注解与无注解的有参构造方法处理后,如果都没有,则走到无参数构造函数的实例化。这就是简单的反射实例化。大部分类的实例化都会走无参构造的逻辑

java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	......

	// 通过无参构造函数的实例化bean,实际上大部分的实例都是采用的无参构造函数的方式实例化
	// No special handling: simply use no-arg constructor.
	return instantiateBean(beanName, mbd);
}

小结

为什么spring框架要设计可以使用@Autowired注解标识有参构造函数的方式来实例化对象,如果类只一个构造函数,或者不写构造函数(此时会有默认的构造函数)都可以支持类到的实例化。

因为类是可以定义多个构造函数,所以通过设计这种注解的的方式,方便使用者去指定以那个构造函数用于实例化

类中注解的收集 applyMergedBeanDefinitionPostProcessors

实例化完成后,接下来就需要对类中的属性进行依赖注入操作。类里面属性和方法的依赖注入往往都标识了 @Autowired 或者 @Resource 注解,核心方法就是applyMergedBeanDefinitionPostProcessors

java
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
	if (!mbd.postProcessed) {
		try {
			/*
			 * 此方法是对实例化的bean的注解收集,对类中注解的装配过程。重要程度【5】
			 * 	这个接口是BeanPostProcessor接口的典型运用,需要重点理解,其中BeanPostProcessor接口的实现类相应处理的注解如下:
			 * 		CommonAnnotationBeanPostProcessor  支持了@PostConstruct,@PreDestroy,@Resource注解
			 * 		AutowiredAnnotationBeanPostProcessor 支持 @Autowired,@Value注解
			 */
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Post-processing of merged bean definition failed", ex);
		}
		mbd.postProcessed = true;
	}
}

注解的收集,也是通过不同的 BeanPostProcessor 接口类型实例来一个个循环处理的。

CommonAnnotationBeanPostProcessor

第1个是调用 CommonAnnotationBeanPostProcessor 类,这个类完成了 @Resource 注解的属性或者方法的收集。这个类还对 @PostConstruct@PreDestory 等注解的支持

java
/*
 * 1、扫描类里面的属性或者方法
 * 2、判断属性或者方法上面是否有@PostConstruct @PreDestroy @Resource注解
 * 3、如果有注解的属性或者方法,包装成一个类
 */
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	// 调用父类(InitDestroyAnnotationBeanPostProcessor)的方法,扫描@PostConstruct、@PreDestroy注解
	super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
	// 扫描目标类的属性和方法上面是否有@Resource注解,如果有则收集起来封装成InjectionMetadata对象
	InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
	// 设置InjectionMetadata对象的checkedElements属性
	metadata.checkConfigMembers(beanDefinition);
}

CommonAnnotationBeanPostProcessor类的构造方法中,设置@PostConstruct@PreDestroy注解的支持

在父类(InitDestroyAnnotationBeanPostProcessor)中处理收集被@PostConstruct@PreDestroy注解标注的方法,具体流程如下:

  1. 看缓存里面有没有 InjectionMetadata 对象
java
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
	// 先从缓存里查找当前类的LifecycleMetadata对象,此对象就是包装了目标对象与相关的生命周期方法
	if (this.lifecycleMetadataCache == null) {
		// Happens after deserialization, during destruction...
		// 没有则去初始化类与LifecycleMetadata对象的映射,放到缓存中
		return buildLifecycleMetadata(clazz);
	}
	// Quick check on the concurrent map first, with minimal locking.
	LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
	if (metadata == null) {
		synchronized (this.lifecycleMetadataCache) {
			metadata = this.lifecycleMetadataCache.get(clazz);
			if (metadata == null) {
				metadata = buildLifecycleMetadata(clazz);
				this.lifecycleMetadataCache.put(clazz, metadata);
			}
			return metadata;
		}
	}
	return metadata;
}
  1. 循环遍历类中的所有的方法,判断方法上是否有@PostConstruct注解如果有的话加入到 initMethods 集合,判断方法上是否有@PreDestroy 注解,如果有加入到 destroyMethods 集合中去
java
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
	// 判断当前实例化类的方法上是否有@PostConstruct或者@PreDestroy注解
	if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
		return this.emptyLifecycleMetadata;
	}

	List<LifecycleElement> initMethods = new ArrayList<>();
	List<LifecycleElement> destroyMethods = new ArrayList<>();
	Class<?> targetClass = clazz;

	// 循环类中所有的方法
	do {
		final List<LifecycleElement> currInitMethods = new ArrayList<>();
		final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

		/* doWithLocalMethods(Class<?> clazz, MethodCallback mc),此方法就是循环调用函数式接口MethodCallback里的doWith()方法,方法里通过反射调用Method对象 */
		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
			// 判断方法上是否有@PostConstruct注解,包装成LifecycleElement对象,加入到LifecycleMetadata.initMethods容器中
			if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
				LifecycleElement element = new LifecycleElement(method);
				currInitMethods.add(element);
				if (logger.isTraceEnabled()) {
					logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
				}
			}
			// 判断方法上是否有@PreDestroy注解,包装成LifecycleElement对象,加入到LifecycleMetadata.destroyMethods容器中
			if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
				currDestroyMethods.add(new LifecycleElement(method));
				if (logger.isTraceEnabled()) {
					logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
				}
			}
		});

		// 使用List集合收集所有初始化和销毁方法
		initMethods.addAll(0, currInitMethods);
		destroyMethods.addAll(currDestroyMethods);
		// 循环递归查询父类
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);

	// 包装成LifecycleMetadata对象并返回
	return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
			new LifecycleMetadata(clazz, initMethods, destroyMethods));
}

收集被 @Resource 注解的标注的方法

在执行完父类的super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);方法后,调用findResourceMetadata()方法收集@Resource注解,收集过程如下:

  1. 看缓存里面有没有 InjectionMetadata 对象
java
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
	// Fall back to class name as cache key, for backwards compatibility with custom callers.
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// 先从缓存中查询
	// Quick check on the concurrent map first, with minimal locking.
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		// 如果缓存中没有,则收集并设置到缓存中
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if (metadata != null) {
					metadata.clear(pvs);
				}
				// 收集@Resource注解,主要逻辑在此方法上
				metadata = buildResourceMetadata(clazz);
				// 收集后将数据缓存起来
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}
  1. 从类中获取所有 Field 对象,循环 field 对象,判断 field 有没有 @Resource 注解,如果有注解封装成 ResourceElement 对象

  1. 再从类中获取所有 Method 对象,循环 Method 对象,判断 Method 有没有 @Resource 注解,如果有注解封装成 ResourceElement 对象

  1. 最终把两个 fieldMethod 封装的对象集合封装到 InjectionMetadata 对象中,并加入 injectionMetadataCache 的 Map 缓存中

AutowiredAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessor类,对@Autowired@Value注解的属性和方法的收集。收集过程基本上跟@Resource注解的收集差不多,详见源码注释

IOC\DI 依赖注入(populateBean)

populateBean 源码位置

DI 前是否需要注入判断

在依赖注入核心方法populateBean中,方法开始时在依赖引入类属性之前,会循环所有实现InstantiationAwareBeanPostProcessors接口,会调用接口中的postProcessAfterInstantiation方法,如果此方法返回值为false,会直接中止,程序不再往下执行依赖注入部分的逻辑,这样会使当前创建中实例的属性没有DI注入。如果不去针对某个类型,而是直接返回false的话,全部实例的属性都没有DI注入

注:此部分运用的示例详见spring-note\spring-analysis-note\spring-source-study-2021\09-spring-beanpostprocessor\CustomInstantiationAwareBeanPostProcessor.java

@Resource 和 @Autowired 注解依赖注入

在Bean实例化完成、并且收集完@Resource@Autowired注解以后,通过上面的依赖注入前的校验后,开始处理依赖注入的逻辑

依赖注入又是一个BeanPostProcessor类型接口的运用,前面已经完成对@Resource@Autowired注解的收集,此时就是根据收集到的注解进行反射调用。

研究其中的子类org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor的实现逻辑

java
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	// 获取之前进行的@Autowired注解收集的元数据(此方法在之前的注解收集过程里研究过)
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		// 进行反射完成依赖注入
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

循环收集到的metaData对象中的List集合,调用里面的每个InjectedElement对象的inject方法完成依赖注入。

java
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	// injectedElements集合是以前收集到的@Autowired注解的字段、方法对象
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		// 循环所有需要注入的元素
		for (InjectedElement element : elementsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Processing injected element of bean '" + beanName + "': " + element);
			}
			// 循环调用每个元素/方法进行注入处理
			element.inject(target, beanName, pvs);
		}
	}
}

element.inject其实就是通过反射来完成依赖注入调用。注:其中 value 值的获取,如果依赖的属性是一个引用类型必定会触发该属性的BeanFactory.getBean()操作,从 spring 容器中获取到对应的实例。

  • 字段属性依赖注入
java
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
    ....
	/*
	 * 属性DI,依赖注入
	 */
	@Override
	protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Field field = (Field) this.member;
		Object value;
		if (this.cached) {
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		else {
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			try {
				// 这里会触发依赖注入属性的getBean操作
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			synchronized (this) {
				if (!this.cached) {
					if (value != null || this.required) {
						this.cachedFieldValue = desc;
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
								this.cachedFieldValue = new ShortcutDependencyDescriptor(
										desc, autowiredBeanName, field.getType());
							}
						}
					}
					else {
						this.cachedFieldValue = null;
					}
					this.cached = true;
				}
			}
		}
		if (value != null) {
		    // 反射注入
			ReflectionUtils.makeAccessible(field);
			field.set(bean, value);
		}
	}
}
  • 方法的依赖注入类似的逻辑
java
private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
    ....
	/*
	 * 方法的DI注入
	 */
	@Override
	protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		if (checkPropertySkipping(pvs)) {
			return;
		}
		Method method = (Method) this.member;
		Object[] arguments;
		if (this.cached) {
			// Shortcut for avoiding synchronization...
			arguments = resolveCachedArguments(beanName);
		}
		else {
			int argumentCount = method.getParameterCount();
			arguments = new Object[argumentCount];
			DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
			Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			for (int i = 0; i < arguments.length; i++) {
				MethodParameter methodParam = new MethodParameter(method, i);
				DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
				currDesc.setContainingClass(bean.getClass());
				descriptors[i] = currDesc;
				try {
					Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
					if (arg == null && !this.required) {
						arguments = null;
						break;
					}
					arguments[i] = arg;
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
				}
			}
			synchronized (this) {
				if (!this.cached) {
					if (arguments != null) {
						DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
						registerDependentBeans(beanName, autowiredBeans);
						if (autowiredBeans.size() == argumentCount) {
							Iterator<String> it = autowiredBeans.iterator();
							Class<?>[] paramTypes = method.getParameterTypes();
							for (int i = 0; i < paramTypes.length; i++) {
								String autowiredBeanName = it.next();
								if (beanFactory.containsBean(autowiredBeanName) &&
										beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
									cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
											descriptors[i], autowiredBeanName, paramTypes[i]);
								}
							}
						}
						this.cachedMethodArguments = cachedMethodArguments;
					}
					else {
						this.cachedMethodArguments = null;
					}
					this.cached = true;
				}
			}
		}
		if (arguments != null) {
			try {
    			// 反射调用方法
				ReflectionUtils.makeAccessible(method);
				method.invoke(bean, arguments);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}
	}
    ....
}
  • @Resource注解标识依赖注入
java
/**
 * A single injected element.
 * 单个注入元素
 */
public abstract static class InjectedElement {
    ....
	/**
	 * Either this or {@link #getResourceToInject} needs to be overridden.
	 */
	protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
			throws Throwable {

		if (this.isField) {
			Field field = (Field) this.member;
			ReflectionUtils.makeAccessible(field);
			field.set(target, getResourceToInject(target, requestingBeanName));
		}
		else {
			if (checkPropertySkipping(pvs)) {
				return;
			}
			try {
				Method method = (Method) this.member;
				ReflectionUtils.makeAccessible(method);
				method.invoke(target, getResourceToInject(target, requestingBeanName));
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}
	}
    ....
}

上述过程是对@Autowired@Resource以及@Value注解修饰的FieldMethod等完成依赖注入

@Autowired 自动匹配小结(待研究分析,补充)
  1. @Autowired 本质上是根据成员变量或方法参数的类型进行装配
  2. 如果待装配类型是 Optional,需要根据 Optional 泛型找到 bean,再封装为 Optional 对象装配
  3. 如果待装配的类型是 ObjectFactory,需要根据 ObjectFactory 泛型创建 ObjectFactory 对象装配(此方式可以延迟 bean 的获取)
  4. 如果待装配的成员变量或方法参数上用 @Lazy 标注,会创建代理对象装配(此方法可以延迟真实 bean 的获取,并且被装配的代理不作为 bean)
  5. 如果待装配类型是数组,需要获取数组元素类型,根据此类型找到多个 bean 进行装配
  6. 如果待装配类型是 Collection 或其子接口,需要获取 Collection 泛型,根据此类型找到多个 bean
  7. 如果待装配类型是 ApplicationContext 等特殊类型,该实例是保存在 BeanFactoryresolvableDependencies 成员属性中,该属性是 map 集合,key 是特殊类型,value 是其对应对象。装配对象时,不能直接根据 key 进行查找,而是用 isAssignableFrom 逐一尝试右边类型是否可以被赋值给左边的 key 类型进行匹配
  8. 如果待装配类型有泛型参数,需要利用 ContextAnnotationAutowireCandidateResolver 按泛型参数类型筛选
  9. 如果待装配类型有 @Qualifier 注解,需要利用 ContextAnnotationAutowireCandidateResolver 按注解提供的 bean 名称筛选
  10. @Primary 标注的 @Component@Bean 的处理
  11. 与成员变量名或方法参数名同名 bean 的处理
@Autowird 装配测试示例(待补充!)

@Value 属性值注入

其实@Value的属性值注入,与@Autowired注解注入流程是一样。在AbstractAutowireCapableBeanFactory#doCreateBean的方法,执行到applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);时,会对@Value注解的收集,然后在populateBean处理对属性的注入,主要AutowiredAnnotationBeanPostProcessor这个 BeanPostProcessor 实现

@Autowired主要的区别就是,@Value注入的是非引用类型,所以不会触发 getBean 的操作

进入resolveEmbeddedValue方法中,会循环一个List<StringValueResolver> embeddedValueResolvers的容器,里面是存放着xml配置或者@Bean注册的配置文件占位符解析器。

此占位符解析器的注册流程详见《Spring 配置文件的解析》章节,核心注册的代码位置如下:

@Value 装配底层 - 按类型装配的步骤小结(待分析)
  1. 查看需要的类型是否为 Optional,若为是则进行封装(非延迟),否则流程向下走
  2. 查看需要的类型是否为 ObjectFactoryObjectProvider,若为是则进行封装(延迟),否则流程向下走
  3. 查看需要的类型(成员或参数)上是否用 @Lazy 修饰,若为是则返回代理,否则流程向下走
  4. 解析 @Value 的值
    1. 如果需要的值是字符串,先解析 ${ },再解析 #{ }
    2. 如果不是字符串,需要用 TypeConverter 接口进行转换
  5. 看需要的类型是否为 StreamArrayCollectionMap,若为是则按集合处理,否则流程向下走
  6. BeanFactoryresolvableDependencies 中找有没有类型合适的对象注入,没有找到则流程向下走
  7. BeanFactory 及父工厂中找类型匹配的 bean 进行筛选,筛选时会考虑 @Qualifier 及泛型
  8. 结果个数为 0 抛出 NoSuchBeanDefinitionException 异常
  9. 如果结果大于 1,再根据 @Primary 进行筛选
  10. 如果结果仍大于 1,再根据成员名或变量名进行筛选
  11. 结果仍大于 1,抛出 NoUniqueBeanDefinitionException 异常
@Value 解析测试示例

示例代码:spring-note\spring-sample\36-annotation-value

  • 测试 bean,其中 SpringConfiguration 是一个被 Spring 管理的 bean
java
public class ValueBean {

    @Value("${JAVA_HOME}")
    private String home;
    @Value("18")
    private int age;

    // 使用 spEl 表达式(全称 SpringEL)
    @Value("#{@springConfiguration}")
    private SpringConfiguration config;

    // 使用
    @Value("#{'hello, ' + '${JAVA_HOME}'}")
    private String value;
}
  • 测试代码
java
public class SpringValueTest {
    // 创建注解扫描的容器
    private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);

    // 模拟解析流程 - 测试读取系统变量
    @Test
    public void test1() throws NoSuchFieldException {
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        // 获取 @Value("${JAVA_HOME}") 注解的属性
        Field field = ValueBean.class.getDeclaredField("home");
        DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(field, false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dependencyDescriptor).toString();
        System.out.println(value);

        // 解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);
        System.out.println(value);
    }

    // 模拟解析流程 - 测试读取字符串值,然后类型转换
    @Test
    public void test2() throws NoSuchFieldException {
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        // 获取 @Value("18") 注解的属性
        Field field = ValueBean.class.getDeclaredField("age");
        DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(field, false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dependencyDescriptor).toString();
        System.out.println(value);

        // 解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);
        // 通过 TypeConverter 接口将字符串类型转成与类对象匹配的数值类型
        Object age = beanFactory.getTypeConverter()
                .convertIfNecessary(value, dependencyDescriptor.getDependencyType());
        System.out.println(age.getClass());
    }

    // 模拟解析流程 - 测试读取 spEl 表达式
    @Test
    public void test3() throws NoSuchFieldException {
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        // 获取  @Value("#{@springConfiguration}") 注解的属性
        Field field = ValueBean.class.getDeclaredField("config");
        DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(field, false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dependencyDescriptor).toString();
        System.out.println(value);

        // 先解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);

        // 再解析 #{} @xxx
        Object configValue = beanFactory.getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(beanFactory, null));
        // 通过 TypeConverter 转成与类对象匹配的类型
        Object result = beanFactory.getTypeConverter()
                .convertIfNecessary(configValue, dependencyDescriptor.getDependencyType());
        System.out.println(result);
    }

    // 模拟解析流程 - 测试读取复杂的 spEl 表达式
    @Test
    public void test4() throws NoSuchFieldException {
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        // 获取  @Value("#{'hello, ' + '${JAVA_HOME}'}") 注解的属性
        Field field = ValueBean.class.getDeclaredField("value");
        DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(field, false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dependencyDescriptor).toString();
        System.out.println(value);

        // 先解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);
        System.out.println(value);

        // 再解析 #{} @xxx
        Object configValue = beanFactory.getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(beanFactory, null));
        // 通过 TypeConverter 转成与类对象匹配的类型
        Object result = beanFactory.getTypeConverter()
                .convertIfNecessary(configValue, dependencyDescriptor.getDependencyType());
        System.out.println(result);
    }
}

xml 配置的依赖注入

比如在spring的xml配置文件的 <bean> 标签中配置以下属性

xml
<!-- property子标签测试(此方式几乎不使用,直接使用@Value实现) -->
<bean class="com.moon.spring.bean.PropertyBean" id="propertyBean">
    <property name="username" value="MoonZero"/>
    <property name="password" value="123"/>
</bean>

标签的依赖注入实现逻辑代码位置如下:

这块逻辑是针对xml配置依赖注入的,基本上现在基于xml配置的依赖很少使用,没必要研究

initializeBean - Bean 实例化和 IOC 依赖注入完成后逻辑处理

源码位置与逻辑处理内容

核心代码位置在AbstractAutowireCapableBeanFactory类中的doCreateBean()方法中。initializeBean方法主要是

java
// bean实例化+ioc依赖注入完以后的调用,非常重要,重要程度【5】
exposedObject = initializeBean(beanName, exposedObject, mbd);

此方法主要处理的内容如下:

  1. 调用Aware接口
  2. 调用@PostConstruct注解的方法,主要是通过BeanPostProcessor接口来实现该功能
  3. 调用实现了InitializingBean接口的类中的afterPropertiesSet方法,调用init-method中配置的方法
  4. 代理实例的创建,用BeanPostProcessor接口来完成代理实例的生成

对某些 Aware 接口的调用(实例化Bean后执行流程1)

此步骤主要是对于当前实例中的bean实现某些Aware的接口的方法调用,如BeanNameAwareBeanClassLoaderAwareBeanFactoryAware

java
private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		// 调用实现BeanNameAware接口的setBeanName()方法,可以获取当前实例化的beanName
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		// 调用实现BeanFactoryAware接口的setBeanFactory()方法,可以获取当前BeanFactory对象
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

@PostConstruct 注解方法与某些Aware接口的调用(实例化Bean后执行流程2)

applyBeanPostProcessorsBeforeInitialization方法,作用是对类中某些特殊方法的调用,比如@PostConstruct,Aware接口。此处又是一个 BeanPostProcessor 接口的运用。核心代码位置

java
/* AbstractAutowireCapableBeanFactory类中的initializeBean()方法 */
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
	// 对类中某些特殊方法的调用,比如@PostConstruct,Aware接口。重要程度【5】
	wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
java
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean;
	/*
	 * 循环容器中所有BeanPostProcessor,着重理解以下几个实现类
	 *  1、ApplicationContextAwareProcessor  对某此Aware接口方法的调用
	 *  2、InitDestroyAnnotationBeanPostProcessor  @PostConstruct注解方法的调用
	 *  3、ImportAwareBeanPostProcessor  对ImportAware类型实例setImportMetadata方法调用。(这个对理解springboot有很大帮助。此时暂时不深入了解)
	 */
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}
ApplicationContextAwareProcessor

ApplicationContextAwareProcessor类是相关Aware类型的接口的调用,支持EnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware等接口

java
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	// 判断是否为所支持的Aware接口的类型,如不支持,直接返回bean
	if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
			bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
			bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
		return bean;
	}

	AccessControlContext acc = null;

	if (System.getSecurityManager() != null) {
		acc = this.applicationContext.getBeanFactory().getAccessControlContext();
	}

	if (acc != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareInterfaces(bean);
			return null;
		}, acc);
	}
	else {
		// 调用Aware接口的方法
		invokeAwareInterfaces(bean);
	}

	return bean;
}
java
/* ApplicationContextAwareProcessor 调用所支持的 Aware 接口类型的方法 */
private void invokeAwareInterfaces(Object bean) {
	if (bean instanceof EnvironmentAware) {
		((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
	}
	if (bean instanceof EmbeddedValueResolverAware) {
		((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
	}
	if (bean instanceof ResourceLoaderAware) {
		((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
	}
	if (bean instanceof ApplicationEventPublisherAware) {
		((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
	}
	if (bean instanceof MessageSourceAware) {
		((MessageSourceAware) bean).setMessageSource(this.applicationContext);
	}
	if (bean instanceof ApplicationContextAware) {
		((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
	}
}
InitDestroyAnnotationBeanPostProcessor

从前面了解到,有 @PostConstruct 注解的方法会收集到一个 metaData 对象中,现在就是通过 BeanPostProcessor 接口调到 CommonAnnotationBeanPostProcessor 类,然后在类中拿到 metaData 对象,根据对象里面的容器来反射调用有注解的方法。核心逻辑(InitDestroyAnnotationBeanPostProcessor为例,此类用于调用@PostConstruct相应的方法)代码如下:

java
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	// 获取生命周期相关方法的Metadata对象
	LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
	try {
		// 调用@PostConstruct注解的方法
		metadata.invokeInitMethods(bean, beanName);
	}
	catch (InvocationTargetException ex) {
		throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
	}
	return bean;
}
java
public void invokeInitMethods(Object target, String beanName) throws Throwable {
	Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
	Collection<LifecycleElement> initMethodsToIterate =
			(checkedInitMethods != null ? checkedInitMethods : this.initMethods); // 获取之前收集 @PostConstruct 注解的 initMethods 容器中
	if (!initMethodsToIterate.isEmpty()) {
		for (LifecycleElement element : initMethodsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
			}
			// 反射调用
			element.invoke(target);
		}
	}
}

@PostConstruct 注解的会收集到 initMethods 容器中,接下来就是方法的反射调用。

java
public void invoke(Object target) throws Throwable {
	ReflectionUtils.makeAccessible(this.method);
	// 反射调用,从源码可以知道,调用的方法是没有入参的。
	this.method.invoke(target, (Object[]) null);
}
ImportAwareBeanPostProcessor

ImportAwareBeanPostProcessorConfigurationClassPostProcessor的内部类,是对ImportAware接口类型实例的setImportMetadata方法调用。

此接口的主要用途是,如果需要获取某个类上的多个注解的信息,可以通过实现ImportAware接口,并通过@Import注解导入,然后在实现的setImportMetadata方法获取到该类上所有注解的元数据。所以这接口需要配合@Import注解使用

java
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
	// 判断当前bean的类型是否ImportAware
	if (bean instanceof ImportAware) {
		// 获取ImportRegistry接口的实例
		ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
		// 获取实现了ImportAware接口,并且通过@Import注解引入。使用@Import注解所在的类的相关其他注解数据
		AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
		if (importingClass != null) {
			// 传入注解数据,并调用setImportMetadata方法
			((ImportAware) bean).setImportMetadata(importingClass);
		}
	}
	return bean;
}

注:通过@Import注解导入的类,在spring容器中注册的名称不是默认的“类名首字母小写”,而是“类的全限定名”

番外:ImportAware 接口的运用示例
  • 创建ImportAware接口的实现类。注意:此实现类不需要使用@Component之类的注解,而是通过@Import注解的方式,让spring容器管理
java
public class CustomImportAware implements ImportAware {
    /**
     * Set the annotation metadata of the importing @{@code Configuration} class.
     * <p>
     * 设置导入类的注解元数据。
     * 即通过实现此接口的类,在相关的配置类中使用@Import注解导入时,可以获取到其配置类上相关所有的注解元数据
     *
     * @param importMetadata 注解元数据
     */
    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        System.out.println("CustomImportAware.setImportMetadata()方法执行了....");
        System.out.println(importMetadata);
    }
}
  • 在配置类(或其他类上),通过@Import注解引入上面的ImportAware接口的实现类
java
@Configuration
@PropertySource("classpath:application.properties")
@Import(CustomImportAware.class)
public class SpringConfiguration {
}
  • 测试代码
java
@Test
public void testImportAware() {
    String[] beanNamesForType = context.getBeanNamesForType(CustomImportAware.class);
    for (String beanName : beanNamesForType) {
        System.out.println(beanName);
    }
    // 注意:通过@Import注解导入的类,在spring容器中注册的名称不是默认的“类名首字母小写”,而是“类的全限定名”
    CustomImportAware customImportAware = context.getBean("com.moon.spring.aware.CustomImportAware", CustomImportAware.class);
    System.out.println(customImportAware);
}
  • 启动项目测试,debug可以看到setImportMetadata方法的入参importMetadata包含了SpringConfiguration类中的所有注解的元数据

InitializingBean 接口和 init-method 属性的调用(实例化Bean后执行流程3)

InitializingBean 接口介绍

实现InitializingBean接口的类,spring会在实例化该类以后,会调用接口的afterPropertiesSet()方法

java
package com.moon.spring.bean;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

/**
 * Spring 框架中 InitializingBean 接口的示例
 * <p>如果需要在一个类实例化以后去做一些逻辑处理,那么就可以借助这个InitializingBean接口来完成
 */
@Component
public class CustomInitializingBean implements InitializingBean {

    public CustomInitializingBean() {
        System.out.println("CustomInitializingBean无参构造方法执行了....");
    }

    /*
     * 实现此接口的 afterPropertiesSet 方法,是在当前bean实例化后被调用的
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("CustomInitializingBean类实现InitializingBean接口的afterPropertiesSet()方法执行了....");
    }

    /*
     * 在xml配置文件中<bean>标签中,配置init-method属性
     *  注意:通过xml配置文件的方式实现类创建后执行init-method,相应的方法的执行顺序是在实现了InitializingBean接口的afterPropertiesSet()方法执行之后
     */
    public void initMehtod() {
        System.out.println("xml配置的CustomInitializingBean.initMethod()方法执行了....");
    }
}

也可以通过xml配置文件的方式,实现与InitializingBean接口一样的效果,只要在<bean>标签中配置init-method属性,值为需要执行的方法名称

xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-lazy-init="false">

    <!--
        配置init-method属性示例
            用于定义 Bean 实例创建后的执行初始化方法,会在 Bean 组装之后调用。注意:该方法必须是一个无参数的方法
     -->
    <bean class="com.moon.spring.bean.CustomInitializingBean" id="customInitializingBean" init-method="initMehtod"/>

</beans>

注意:通过xml配置文件的方式实现类创建后执行init-method,相应的方法的执行顺序是在实现了InitializingBean接口的afterPropertiesSet()方法执行之后。init-method配置的方法必须是无参数的方法

测试:

java
private final ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

/** InitializingBean接口基础使用测试 */
@Test
public void testBaseInitializingBean() {
    CustomInitializingBean customInitializingBean = context.getBean("customInitializingBean", CustomInitializingBean.class);
    System.out.println(customInitializingBean);
}

启动spring,运行结果如下

源码实现过程分析

执行流程往下就是对实现了InitializingBean接口的类与在xml配置文件中<bean>标签中配置了init-method属性的相应方法的调用

从源码可以看出,实现了 InitializingBean 接口的类就必然会调用到 afterPropertiesSet() 方法,且 Init-method 属性调用是在 afterPropertiesSet() 方法之后

java
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBe
		throws Throwable {
	// 判断是否为InitializingBean接口实现
	boolean isInitializingBean = (bean instanceof InitializingBean);
	// 首先调用实现InitializingBean接口的afterPropertiesSet()方法
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("aft
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanNa
		}
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) ()
					((InitializingBean) bean).afterPropertiesSet();
					return null;
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 直接调用afterPropertiesSet()方法
			((InitializingBean) bean).afterPropertiesSet();
		}
	}
	// 然后调用xml配置文件中的init-method属性相应的方法
	if (mbd != null && bean.getClass() != NullBean.class) {
		// 获取调用的方法名称
		String initMethodName = mbd.getInitMethodName();
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName))
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			// 此方法为调用xml配置文件中的init-method属性相应的方法
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

@PostConstruct、InitializingBean接口、init-method 小结

InitializingBean.afterPropertiesSetinit-method和有@PostConstruct注解的方法其实核心功能都是一样的,只是调用时序不一样而已,都是在该类实例化和 IOC 做完后调用的,可以在这些方法中做一些在 spring 或者 servlet 容器启动的时候的初始化工作。比如缓存预热,比如缓存数据加载到内存,比如配置解析,等等初始化工作。

从源码的分析可知,这3种初始化方法的调用时序是:@PostConstruct -> InitializingBean.afterPropertiesSet -> init-method(xml配置)

AOP入口

在这个方法里面最后还有一个重要的逻辑

java
/* AbstractAutowireCapableBeanFactory */
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    ......
    // 此部分也是一个 BeanPostProcessor 接口的运用,在这里会返回 bean 的代理实例,这个就是 AOP 的入口【暂未研究】
    if (mbd == null || !mbd.isSynthetic()) {
    	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

这也是一个 BeanPostProcessor 接口的运用,在这里会返回 bean 的代理实例,这个就是 AOP 的入口。

循环依赖

注:此部分的逻辑是在IOC/DI依赖注入之前,为了方便理解,先分析了依赖注入与bean实例化后操作流程再来分析

循环依赖流程图

TODO: 循环依赖参照流程图(引用其他资料。)有时间自己再重新整理

图片出处:https://www.processon.com/view/link/5df9ce52e4b0c4255ea1a84f

循环依赖需要注意的问题

SpringBoot 2.6.x 以前是默认允许循环依赖的,即如果代码出现了循环依赖问题,一般情况下也不会报错。Spring 的解决办法是三级缓存机制,提前暴露的对象存放在三级缓存中,二级缓存存放过渡 bean(半成品),一级缓存存放最终形态的 bean。但是这种机制也有一些缺点,比如增加了内存开销(需要维护三级缓存,也就是三个 Map),降低了性能(需要进行多次检查和转换)。并且循环依赖是有限制条件的,还有少部分情况是不支持循环依赖的,比如:

  • 循环依赖只会出现在单例实例无参构造函数实例化情况下,包含采用 setter 方法注入、属性自动注入。
  • 多例的 bean 的循环依赖会直接报错;@Async 注解的 bean 无法支持循环依赖。
  • 有参构造函数的加 @Autowired 的方式循环依赖会直接报错。(解决方法:在有参构造方法参数列表中增加 @Lazy 注解,让对象延迟加载即可)
  • 还有一种 AB 循环依赖的情况,一个是构造器注入,一个是 setter 注入。由于 Spring 在创建 Bean 时默认会根据自然排序进行创建,假设 A 会先于 B 进行创建,会有以下两种情况:
    • A 中注入的 B 为 setter 注入,B 中注入的 A 为构造器注入,可以成功注入。
    • B 中注入的 A 为 setter 注入,A 中注入的 B 为构造器注入,注入失败。

循环依赖解决方案

SpringBoot 2.6.x 以后官方不再推荐编写存在循环依赖的代码,建议开发者自己写代码时减少不必要的互相依赖。循环依赖本身就是一种设计缺陷,开发者不应该过度依赖 Spring 而忽视了编码的规范和质量,说不定未来某个 SpringBoot 版本就彻底禁止循环依赖的代码。

SpringBoot 2.6.x 以后,如果不想重构循环依赖的代码的话,也可以采用下面这些方法:

  • 在全局配置文件中设置允许循环依赖存在:spring.main.allow-circular-references=true。最简单粗暴的方式,不太推荐。
  • 在导致循环依赖的 Bean 上添加 @Lazy 注解,这是一种比较推荐的方式。注:@Lazy 用来标识类是否需要延迟加载,可以作用在类上、方法上、构造器上、方法参数上、成员变量中。
java
public A(@Lazy B b) {
    System.out.println("A的构造方法执行了...");
    this.b = b;
}

public B(@Lazy A a) {
    System.out.println("B的构造方法执行了...");
    this.a = a;
}

循环依赖步骤与源码分析

注:以最简单的两个单例A与B相互引用为案例说明

  • 从A类实例化开始,流程执行到AbstractBeanFactory.doGetBean()方法中,此时spring容器中没有A实例,A类为单例,所以执行到getSingleton方法。

  • getSingleton方法中的beforeSingletonCreation(beanName),会给将A实例的beanName加入singletonsCurrentlyInCreation的set容器,标识A类实例正在创建中
java
protected void beforeSingletonCreation(String beanName) {
	// 把beanName添加到singletonsCurrentlyInCreation的Set容器中,在这个集合里面的bean都是正在实例化的bean
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
		// 如果需要创建的beanName不在inCreationCheckExclusions容器(存储排除创建的)中,并且singletonsCurrentlyInCreation容器(存储正在创建的)已经存在,抛出异常
		throw new BeanCurrentlyInCreationException(beanName);
	}
}
  • 然后singletonFactory.getObject();会调用lambda表达式中的createBean方法
  • A 类无参构造函数实例化后,将实例设置到三级缓存中,此部分的源码位置,在AbstractAutowireCapableBeanFactory类的doCreateBean方法中,注解收集方法applyMergedBeanDefinitionPostProcessors执行后,依赖注入populateBean方法执行前
java
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
/*
 * 判断单例的bean是否需要提前暴露
 * 	判断依据是:当前实例化的bean是否为单例、是否允许循环依赖、是否正在创建中
 *
 * isSingletonCurrentlyInCreation(beanName) 方法的作用是:
 * 	判断singletonsCurrentlyInCreation容器中,是否存在当前bean的名称,从而判断当前bean是否正在创建中
 */
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
		isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	/*
	 * 添加当前创建好的bean实例(但还没有DI依赖注入)加入到三级缓存,对理解循环依赖帮助非常大,重要程度【5】。
	 * 此匿名内部类要完成的逻辑是,直接将已经创建好的bean实例返回(在堆内存中存在,但还没有DI依赖注入,引用类型的属性为null)
	 */
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
  • 将当前A实例(未依赖注入,所有属性值都为空)放到singletonFactories三级缓存,建立beanName与ObjectFactory<?>接口对象的映射
java
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		// 如果一级缓存不存在
		if (!this.singletonObjects.containsKey(beanName)) {
			// 设置三级缓存
			this.singletonFactories.put(beanName, singletonFactory);
			// 删除二级缓存
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}
  • 当A类执行 populateBean() 方法进行依赖注入,这里触发了 B 类属性的 getBean() 操作
  • B类实例化开始的流程与A类实例化的流程一样,当执行无参构造函数实例化后,也与A实例一样,将B实例设置到三级缓存中
  • 当B类执行 populateBean() 方法进行依赖注入时,这里又会触发了 A 类属性的 getBean() 操作
  • A 类之前正在实例化,所以singletonsCurrentlyInCreation 集合中有已经有这个 A 类的实例了,三级缓存里面也有了,所以此时,A类执行到getSingleton(beanName);方法,可以从三级缓存中拿到的提前暴露的A实例,该实例还没有进行 B 类属性的依赖注入的,B 类属性为空。

具体流程:具体通过Object sharedInstance = getSingleton(beanName);这个方法(先从一级缓存中获取,没有则再从二级缓存中获取,如果没有,并且允许 bean 提前暴露则从三级缓存中获取对象工厂,调用getObject方法并从工厂中拿到实例对象成功后,升级到二级缓存,并删除三级缓存。往后再有别的类引用此实例的话,就直接从二级缓存中进行取)

  • B类拿到了A的提前暴露实例注入到引入A类属性中了
  • 依赖注入后,B类实例化已经完成,B类的实例化是由A类实例化中B属性的依赖注入触发的 getBean() 操作进行的,现在B类已经实例化,所以A类中B属性就可以完成依赖注入了,此时A类B属性已经有值了
  • B类A属性指向的就是A类实例堆空间,所以这时候B类A属性也会有值了。

earlySingletonObjects (二级缓存)的作用总结

earlySingletonObjectsDefaultSingletonBeanRegistry类中的一个Map集合,作用是用于存放提前暴露的bean实例的映射。

当创建的实例中存在循环依赖的情况时,当第1次触发getBean操作时,会将没有依赖注入的bean实例的引入放到一个singletonFactories(三级缓存)容器中,此容器是beanName与ObjectFactory<?>的映射;

当第2次触发getBean操作时,在doGetBean方法中调用getSingleton(beanName)时,此时通过beanName在singletonFactories(三级缓存)容器中相关的ObjectFactory<?>对象,调用其getObject()获取到依赖的实例引用,然后将实例放入earlySingletonObjects(二级缓存),再删除singletonFactories(三级缓存)容器中的beanName映射

当第3次或往后的多次循环依赖同一个对象,触发getBean操作时,此时就会直接从earlySingletonObjects(二级缓存)中获取到实例对象,不需要每次都通过ObjectFactory<?>接口的getObject()方法调用来获取对象实例,提高性能。

注:其实singletonFactories(三级缓存)在多次的循环依赖情况下,只会触发一次就会被删除,将实例放到earlySingletonObjects(二级缓存)中

有参构造函数的 @Autowired 循环依赖

  1. 创建A类的实例是在方法 createBeanInstance(beanName, mbd, args) 中通过无参或标识@Autowired注解的有参构造函数实例化进行的
  2. 如果A类的有参构造函数的参数是引用类型B类,创建当前实例的时候,就是触发B类的getBean实例化操作。

  1. 因为A类在执行createBeanInstance方法时,由于构造函数中的参数是引用类型B类,会触发B类的实例化getBean操作,此时A类的实例化还没有完成,也还没有执行到addSingletonFactory方法,所以无法提前暴露当前A类实例对象
  2. 此时B类的实例化也执行到createBeanInstance方法,由于B类构造函数的参数是引用类型A类,所以又会触发A类的第2次getBean操作,此时在getSingleton中的一、二、三缓存都没有A类的实例,所以程序又调用getSingleton方法创建A类的实例

  1. beforeSingletonCreation方法中,会将当前创建的A类的beanName放入用于存放正在实例化bean的名称的Set容器(singletonsCurrentlyInCreation),因为一开始第1次实例化A类时,此singletonsCurrentlyInCreation容器已经存在A类的名称,所以往里面增加时就返回false,从而进入if代码块,抛出异常。

如果是通过属性加@Autowired方式进行循环依赖,在执行populateBean方法进行属性依赖注入之前就会把 bean 放入三级缓存中,从而在populateBean方法进行依赖注入操作时触发 getBean 操作时就可以直接从三级缓存中获取到提前暴露的实例引入

多例模式的循环依赖

多例模式也是不支持循环依赖,原理同上有参构造函数的循环依赖,多例每次创建的三级缓存都不一样,所以第2次触发getBean操作时找不到对应的三级缓存,校验的时候也会报错误。

在当前线程ThreadLocal<Object> prototypesCurrentlyInCreation对象中,存入当前创建中的实例名称

非单例,无法加入三级缓存

在第2次getBean操作时,从当前线程的ThreadLocal对象中获取到的beanName与当前创建中的实例名称一样,从而抛出异常。

Bean 的销毁

DisposableBeanAdapter(销毁处理器)的注册

在依赖注入完成并调用了相关的Aware接口、生命周期方法后,程序往下执行到registerDisposableBeanIfNecessary方法。此方法会在 bean 创建完成后就会对这个 bean 注册一个销毁的 DisposableBeanAdapter 对象, disposableBeans集合负责对需要销毁的 bean 进行放置。

注:其实此处的Bean的销毁准确来说,并不是真正的销毁内存中的一个对象,销毁对象是由JVM来实现,这里Spring只是在Bean销毁前做的一些逻辑处理

java
/** AbstractAutowireCapableBeanFactory.doCreateBean()  **/
// Register bean as disposable.
try {
	// 注册bean销毁时的处理类DisposableBeanAdapter,注册此类是为了等tomcat这些应用服务器进行调用
	registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
	throw new BeanCreationException(
			mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
java
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
	AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
	if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
		if (mbd.isSingleton()) {
			// Register a DisposableBean implementation that performs all destruction
			// work for the given bean: DestructionAwareBeanPostProcessors,
			// DisposableBean interface, custom destroy method.
			// 注册beanName与DisposableBeanAdapter映射关系到 一个叫disposableBeans的容器中
			registerDisposableBean(beanName,
					new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
		}
		else {
			// A bean with a custom scope...
			Scope scope = this.scopes.get(mbd.getScope());
			if (scope == null) {
				throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
			}
			scope.registerDestructionCallback(beanName,
					new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
		}
	}
}

注册beanName与DisposableBeanAdapter的映射关系

java
public void registerDisposableBean(String beanName, DisposableBean bean) {
	synchronized (this.disposableBeans) {
		this.disposableBeans.put(beanName, bean);
	}
}

这个DisposableBeanAdapter对象就是负责bean销毁的类。在这个类中收集了该bean是否实现了 DisposableBean 接口,是否配置 destroy-method 属性,过滤了 DestructionAwareBeanPostProcessor 类型的接口。

java
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
		List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {

	Assert.notNull(bean, "Disposable bean must not be null");
	this.bean = bean;
	this.beanName = beanName;
	this.invokeDisposableBean =
			(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
	this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
	this.acc = acc;
	// 判断当前的Bean实例是否实现了 DisposableBean 接口,并从BeanDefinition对象中获取相应bean的destroyMethod的名称,没有null
	String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
	if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
			!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
		this.destroyMethodName = destroyMethodName;
		// 反射获取销毁方法的Method对象
		Method destroyMethod = determineDestroyMethod(destroyMethodName);
		if (destroyMethod == null) {
			if (beanDefinition.isEnforceDestroyMethod()) {
				throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
						destroyMethodName + "' on bean with name '" + beanName + "'");
			}
		}
		else {
			Class<?>[] paramTypes = destroyMethod.getParameterTypes();
			if (paramTypes.length > 1) {
				throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
						beanName + "' has more than one parameter - not supported as destroy method");
			}
			else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
				throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
						beanName + "' has a non-boolean parameter - not supported as destroy method");
			}
			destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
		}
		this.destroyMethod = destroyMethod;
	}
	// 过滤Spring容器中所有的BeanPostProcessor,获取所有DestructionAwareBeanPostProcessor类型的List集合
	this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
java
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
	List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
	if (!CollectionUtils.isEmpty(processors)) {
		filteredPostProcessors = new ArrayList<>(processors.size());
		for (BeanPostProcessor processor : processors) {
			// 只过滤DestructionAwareBeanPostProcessor类型
			if (processor instanceof DestructionAwareBeanPostProcessor) {
				DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
				if (dabpp.requiresDestruction(bean)) {
					filteredPostProcessors.add(dabpp);
				}
			}
		}
	}
	return filteredPostProcessors;
}

Bean 销毁的时的调用处理

测试代码:

java
private final ApplicationContext context =
        new AnnotationConfigApplicationContext("com.moon.spring");

@Test
public void testDisposableBeanBasic() {
    DestroyDemoBean bean = context.getBean("destroyDemoBean", DestroyDemoBean.class);
    System.out.println(bean);

    /*
     * AutowireCapableBeanFactory 对象的 destroyBean 方法,需要传入的Bean对象,
     * 如果此bean类实现DisposableBean接口,则调用destroy方法
     * 否则只做销毁bean的操作
     */
    // context.getAutowireCapableBeanFactory().destroyBean(bean);

    // 调用上下文对象关闭方法,会调用到容器中所有 DisposableBean 类型的 destroy 方法
    ((AnnotationConfigApplicationContext) context).close();
}

而 bean 销毁时机是在 tomcat 关闭的时候就会调用到 servlet 中的销毁方法。具体是通过类ContextLoaderListener中的 contextDestroyed 方法,通过 closeWebApplicationContext 方法一直往下找此为 servlet 规范的使用,在这个方法中就会最终掉用到 DisposableBeanAdapter 类的destroy()方法,该方法就会根据前面的收集进行调用。具体的流程如下:

java
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    ......
    /**
	 * Close the root web application context.
	 * web应用关闭时调用此方法
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
	    // 在此方法中,最终会调用到spring 的 DisposableBeanAdapter 类的 destroy() 方法
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}
}

FactoryBean 接口

接口作用与使用示例详见《Spring笔记01-基础.md》文档

源码分析

FactoryBean 类型接口触发的位置:AbstractBeanFactory --> doGetBean()

java
// Create bean instance.
if (mbd.isSingleton()) {
	/* 此逻辑是重点,因为大部分情况都是单例的 */
	sharedInstance = getSingleton(beanName, () -> {
		try {
			// 创建bean实例核心逻辑
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			// Explicitly remove instance from singleton cache: It might have been put there
			// eagerly by the creation process, to allow for circular reference resolution.
			// Also remove any beans that received a temporary reference to the bean.
			destroySingleton(beanName);
			throw ex;
		}
	});
	// 此方法是FactoryBean接口的调用入口
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

FactoryBean接口调用主要逻辑

  • 判断 beanName 是否以&开头,并且是FactoryBean接口类型,如果是,直接返回。
  • 判断
java
protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// Don't let calling code try to dereference the factory if the bean isn't a factory.
	// 如果Bean不是工厂,请不要让调用代码尝试取消引用工厂
	// 根据方法传入的名称判断当前实例是否为FactoryBean接口类型
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		// 进入此if代码块,说明bean实例是FactoryBean接口类型,但如果不是,则抛出异常
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
		}
		if (mbd != null) {
			// 设置BeanDefinition的isFactoryBean标识为true
			mbd.isFactoryBean = true;
		}
		return beanInstance;
	}

	// Now we have the bean instance, which may be a normal bean or a FactoryBean.
	// If it's a FactoryBean, we use it to create a bean instance, unless the
	// caller actually wants a reference to the factory.
	/*
	 * 代码执行到这里,说明beanName不是以"&"开头的,
	 * 此时判断如果传入的实例不是FactoryBean接口类型的,则直接返回传入的实例(相当于此方法没有任何作用)
	 */
	if (!(beanInstance instanceof FactoryBean)) {
		return beanInstance;
	}

	// 以下逻辑说明了当前实例beanInstance是FactoryBean接口类型的,并且beanName不是以&开头
	Object object = null;
	if (mbd != null) {
		mbd.isFactoryBean = true;
	}
	else {
		// 从缓存(factoryBeanObjectCache容器)里面获取FactoryBean类型的实例
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// 如果缓存没有实例,执行创建实例。其实就是调用`FactoryBean`接口的`getObject`方法获取实例
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		// 重点关注此方法,调用接口的`getObject`方法获取实例,重要程度【5】
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

判断beanName是否有&的前缀

java
public static boolean isFactoryDereference(@Nullable String name) {
	// 判断bean的名称带有"&"的前缀
	return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

getObjectFromFactoryBean方法的主要执行逻辑是:先从factoryBeanObjectCache缓存中获取,如果缓存为空,则调用FactoryBean.getObect()方法获取实例,最后会判断一级缓存中已存在,则会在专门保存FactoryBean类型的factoryBeanObjectCache缓存多保存一份

java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	if (factory.isSingleton() && containsSingleton(beanName)) {
		synchronized (getSingletonMutex()) {
			// 先从factoryBeanObjectCache缓存容器中获取
			Object object = this.factoryBeanObjectCache.get(beanName);
			if (object == null) {
				// 缓存没有,则调用getObject方法
				object = doGetObjectFromFactoryBean(factory, beanName);
				// Only post-process and store if not put there already during getObject() call above
				// (e.g. because of circular reference processing triggered by custom getBean calls)
				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					if (shouldPostProcess) {
						// 判断如果当前beanName的实例是正在创建中,则直接返回
						if (isSingletonCurrentlyInCreation(beanName)) {
							// Temporarily return non-post-processed object, not storing it yet..
							return object;
						}
						beforeSingletonCreation(beanName);
						try {
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
						finally {
							afterSingletonCreation(beanName);
						}
					}
					if (containsSingleton(beanName)) {
						// 把实例缓存到factoryBeanObjectCache的map容器中,这个是单独缓存FactoryBean类型实例的map
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			return object;
		}
	}
	else {
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (shouldPostProcess) {
			try {
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}

调用getObject方法获取实例

java
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
	Object object;
	try {
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 调用getObject方法
			object = factory.getObject();
		}
	}
	catch (FactoryBeanNotInitializedException ex) {
		throw new BeanCurrentlyInCreationException(beanName, ex.toString());
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
	}

	// Do not accept a null value for a FactoryBean that's not fully
	// initialized yet: Many FactoryBeans just return null then.
	if (object == null) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		object = new NullBean();
	}
	return object;
}

小结

FactoryBean接口类型实例的调用具体调用位置是在getSingleton方法之后getObjectForBeanInstance的方法中,主要处理的内容如下:

  1. 如果 bean 实例不是 FactoryBean 类型的或者 name 以&开始的则直接返回实例。
  2. 如果 bean 是 FacotyBean 类型并且不是以&开头,会通过方法 doGetObjectFromFactoryBean 调用 FactoryBean 内部继承实现的 getObject 方法,并且判断一级缓存中如果存在该 bean 实例把实例缓存到factoryBeanObjectCache对应的Map中,这个是单独缓存FactoryBean类型实例的Map容器

从源码分析可知:从开始循环所有创建的Bean实例名称集合时,如果是FactoryBean类型,则会拼加&的前缀。所以BeanFactory.getBean("beanName")只能获取到FactoryBean接口的getObject()方法返回的实例。该方法返回的实例会有单独的缓存存储,跟其他实例不是同一个缓存,对应的缓存是:factoryBeanObjectCache

Bean 的多例及作用域

多例Bean测试

通过@Scope注解可以设置bean为多例

java
package com.moon.spring.bean;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * 用于测试 Spring Bean 的多例情况与作用范围
 */
@Component
// @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) // Bean实例是单例,默认不需要设置
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // Bean实例是多例
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean类的无参构造函数执行了....");
    }
}

测试Spring Bean的实例作用范围

java
@Test
public void testPrototype() throws InterruptedException {
    /*
     * 测试单例与多例
     *      单例情况:每个线程获取的实例的hashCode都一样
     *      多例情况:每个线程获取的实例的hashCode都不一样
     *      多例情况,一个线程多次获取实例,其hashCode也是不一样
     */
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " --> " + context.getBean("prototypeBean"));
            System.out.println(Thread.currentThread().getName() + " --> " + context.getBean("prototypeBean"));
        }).start();
        Thread.sleep(1000);
    }
}

单例:

多例:

多例Bean源码分析

  • Bean 的多例模式,在容器启动时不会进行实例化,在方法 preInstantiateSingletons 中有判断,如果 bean 不是抽象的、单例的、非懒加载的才会进行实例化,多例模式需要在手动调用 getBean 触发。存放正在创建的多例 bean 对象的集合是 prototypesCurrentlyInCreation,此容器是ThreadLocal<Object>,为了确保同一个线程的同一次getBean操作不会重复创建实例
  • Bean 的多例模式不支持循环依赖 doGetBean 方法中有判断,因为多例的 Bean 不进行实例化,所以没法从一级缓存中获取,所以直接就走此方法 isPrototypeCurrentlyInCreation,如果 scope 是 Prototype 的,校验是否有出现循环依赖,如果有则直接报错。

多例Bean注意项

  • scope 作用域:默认是单例模式,即 scope="singleton"。另外 scope 还有 prototype、request、session、global session 作用域。scope="prototype"表示多例。注:request 和 session 作用域只会在 web 环境才会存在(此时 bean 的管理是由 tomcat 进行的)
  • Scope 是 Prototype 时,不管是否同一个线程,只要是 getBean() 方法就会得到一个新的实例
  • Scope 是 Prototype 时,在spring容器启动中,是不会创建实例,需要主动调用 getBean() 时才会创建实例
  • Request 作用域时,是把实例存储到 request 对象中(此时 bean 的管理是由 tomcat 进行的), 通过 request.getAttruibte/setAttibute 进行操作
  • Session 作用域时,是把实例存储到 session 对象中,通过 session.getAttruibte/setAttibute 进行操作
  • ClassPathApplicationContext 容器是没有 request 和 session 的作用域
  • WebXmlApplicationContext 容器是有 request 和 session 的作用域,但是如何添加呢?

Request与Session作用域(!!后面需要补充tomcat部署时的截图。目前因为没有配置好web.xml文件与springMVC)

定义两个作用域测试bean。注:需要引入spring-web的依赖

java
@Component
@Scope(value = RequestAttributes.REFERENCE_REQUEST/*,proxyMode = ScopedProxyMode.TARGET_CLASS*/)
public class RequestScopeBean {
}

@Component
@Scope(value = RequestAttributes.REFERENCE_SESSION/*,proxyMode = ScopedProxyMode.TARGET_CLASS*/)
public class SessionScopeBean {
}

如果直接使用单元测试,调用spring容器的getBean()方法,则会直接报错

java
@Test
public void requestSessoinScopeTest() {
    applicationContext.getBean("requestScopeBean");
}

因为spring框架的scopes容器没有request作用域

自定义作用域

自定义作用域源码分析

阅读AbstractBeanFactory类的源码发现,有一个public的方法registerScope,该方法可以往spring构架中的scopes容器中注册(添加自定义作用域)。所以只要通过实现BeanFactoryPostProcessor接口,拿到spring的BeanFactory对象,即可调用该方法往作用域scopes容器中注册自定义作用域

java
/* 该方法实现向spring容器中注册一个Scope(bean作用范围)对象 */
@Override
public void registerScope(String scopeName, Scope scope) {
	Assert.notNull(scopeName, "Scope identifier must not be null");
	Assert.notNull(scope, "Scope must not be null");
	if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
		throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
	}
	Scope previous = this.scopes.put(scopeName, scope);
	if (previous != null && previous != scope) {
		if (logger.isDebugEnabled()) {
			logger.debug("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
		}
	}
	else {
		if (logger.isTraceEnabled()) {
			logger.trace("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
		}
	}
}
  • 自定义scope作用域的调用位置。主要会从scopes容器获取已经注册的Scope接口实例,然后调用Scope接口实例的get方法,当前调用入参的ObjectFactory.getObject()方法时,就会调用到lambda表达式的代码,创建实例返回
java
protected <T> T doGetBean(
		String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
		throws BeansException {
    ....省略
    else {
		/* 其他作用范围的bean的实例化 */
		String scopeName = mbd.getScope();
		if (!StringUtils.hasLength(scopeName)) {
			throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
		}
		// 从scopes的Map容器中,根据scopeName获取Scope接口实例
		Scope scope = this.scopes.get(scopeName);
		if (scope == null) {
			throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
		}
		try {
			/*
			 * 此处会调用Scope接口的get方法,其中第二个入参为ObjectFactory对象
			 * 在实现Scope接口的get方法中,调用ObjectFactory.getObject()方法,
			 * 即调用到此lambda表达式的代码,会返回spring创建的实例
			 *
			 * 注:这里spring只会创建,不会保存到缓存中,意味着实例的管理由自己来实现
			 */
			Object scopedInstance = scope.get(beanName, () -> {
				beforePrototypeCreation(beanName);
				try {
					return createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
			});
			// 此方法是FactoryBean接口的调用入口
			bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
		}
		catch (IllegalStateException ex) {
			throw new BeanCreationException(beanName,
					"Scope '" + scopeName + "' is not active for the current thread; consider " +
					"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
					ex);
		}
	}
    ....省略
}
  • Scope接口的remove(String name)方法的调用
java
@Override
public void destroyScopedBean(String beanName) {
	RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
	if (mbd.isSingleton() || mbd.isPrototype()) {
		throw new IllegalArgumentException(
				"Bean name '" + beanName + "' does not correspond to an object in a mutable scope");
	}
	String scopeName = mbd.getScope();
	// 从scope容器中获取自定义的scope对象
	Scope scope = this.scopes.get(scopeName);
	if (scope == null) {
		throw new IllegalStateException("No Scope SPI registered for scope name '" + scopeName + "'");
	}
	// 调用自定义的scope对象的remove方法
	Object bean = scope.remove(beanName);
	if (bean != null) {
		destroyBean(beanName, bean, mbd);
	}
}
自定义作用域实现
  1. 写一个类实现 scope 接口,实现get()方法,该方法是管理生成bean实例作用域的逻辑
java
package com.moon.spring.scope;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

/**
 * 自定义bean作用域,需要实现Scope接口
 * <p>此自定义作用域的需求是,在同一个线程中获取都是同一个实例,不同线程获取不同实例</p>
 */
public class CustomScope implements Scope {

    private final ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    /**
     * 获取bean实例的方法,此方法可以实现管理生成bean实例作用域逻辑
     */
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        System.out.println("=====自定义作用域CustomScope.get()执行=====");

        // 如果当前线程存在创建完成的实例,直接返回
        if (threadLocal.get() != null) {
            return threadLocal.get();
        }

        // 此处调用ObjectFactory接口的getObject方法,相应源码就是调用spring框架的createbean方法获得一个实例
        Object object = objectFactory.getObject();
        // 设置到ThreadLocal容器并返回
        threadLocal.set(object);
        return object;
    }

    @Override
    public Object remove(String name) {
        Object o = threadLocal.get();
        threadLocal.remove();
        return o;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {

    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return null;
    }
}
  1. 要获取BeanFactory对象,必须实现BeanFactoryPostProcessor或者``接口才能获取 BeanFactory 对象。调用 BeanFactory.registerScope 方法把自定义的 scope 注册进去
java
package com.moon.spring.scope;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * 实现BeanFactoryPostProcessor接口,用于注册自定义bean作用域
 */
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    // 实现postProcessBeanFactory方法,注册自定义作用域
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerScope("MooNkirAScope", new CustomScope());
    }
}
  1. 编写测试bean。测试结果如下:
java
@Component
@Scope("MooNkirAScope")
public class CustomScopeBean {
}

Bean作用域总结

Spring框架Bean的作用域的本质是对Bean实例的管理。

  1. 单例模式Bean的实例是存储在DefaultSingletonBeanRegistry类中的singletonObjects的map容器中
  2. 实现FactoryBean接口后所创建的Bean实例,是存储在FactoryBeanRegistrySupport类中的factoryBeanObjectCache的Map容器中
  3. 多例模式Bean的实例是没有存缓存中,每次获取时创建
  4. Request与Session模式Bean的实例是存储在web容器相应的request与session对象中
  5. 自定义作用域其实是自已定义Bean实例的管理方式,存储到缓存或者直接创建由定义者决定

Bean 的实例化过程(基于注解驱动的 Spring 执行过程分析)

注:Spring基于纯注解的Bean实例化过程,基本上与xml的流程差不多,目前项目几乎都是基于注解驱动开发的,所以基于注解的方式的实例化是重点

AnnotationConfigApplicationContext 基于注解配置上下文对象

创建基于注解的上下文对象 AnnotationConfigApplicationContext 一般都会调用以下的构造方法

  • 通过传入一个或者多个扫描包名来创建容器
  • 通过传入一个或者多个配置类的字节码对象来创建容器

使用包扫描的构造函数

构造函数源码

java
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    // ...省略
    /**
     * Create a new AnnotationConfigApplicationContext, scanning for components
     * in the given packages, registering bean definitions for those components,
     * and automatically refreshing the context.
     * @param basePackages the packages to scan for component classes
     */
    public AnnotationConfigApplicationContext(String... basePackages) {
	    this();
	    // 如果入参为基础包,则进行包扫描的操作
	    scan(basePackages);
	    refresh();
    }
    // ...省略
}

scan 方法说明

它是根据传入的类路径下(classpath*)的包解析Bean对象中注解的(包括类上以及类成员的),使用的是ClassPathBeanDefinitionScanner类中的doScan方法,该方法最终将得到的BeanDefinitionHolder信息存储到LinkedHashSet中,为后面初始化容器做准备。

doScan()中的findCandidateComponents方法调用ClassPathScanningCandidateComponentProvider类中的scanCandidateComponents方法,而此方法又去执行了PathMatchingResourcePatternResolver类中的doFindAllClassPathResources方法,找到指定扫描包的URL(是URL,不是路径。因为是带有file协议的),然后根据磁盘路径读取当前目录及其子目录下的所有类。接下来执行AnnotationConfigUtils类中的processCommonDefinitionAnnotations方法,剩余执行流程与通过字节码方式的一样。

使用类字节码的构造函数

构造函数源码

java
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    // ...省略
    /**
     * Create a new AnnotationConfigApplicationContext, deriving bean definitions
     * from the given component classes and automatically refreshing the context.
     * @param componentClasses one or more component classes &mdash; for example,
     * {@link Configuration @Configuration} classes
     */
    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
	    // 子类的构造方法执行时,第一步会默认调父类的无参构造方法,即public GenericApplicationContext()
	    // 调用无参构造方法,用来注册与初始化框架的本身一些核心类,主要完成一些解析器与扫描器的注册
	    this();
	    // 将传入的类字节码对象(配置类)注册到BeanDefinition中
	    register(componentClasses);
	    refresh();
    }
    // ...省略
}

register 方法说明

它是根据传入的配置类字节码解析Bean对象中注解的(包括类上的和类中方法和字段上的注解。如果类没有被注解,那么类中方法和字段上的注解不会被扫描)。使用的是AnnotatedGenericBeanDefinition,里面包含了BeanDefinition和Scope两部分信息,其中BeanDefinition是传入注解类的信息,即构造方法传入的项目的配置类;scope是指定bean的作用范围,默认情况下为单例。

同时,借助AnnotationConfigUtils类中processCommonDefinitionAnnotations方法判断是否使用了@Primary@Lazy@DependsOn等注解来决定Bean的加载时机。

ConfigurationClassBeanDefinitionReader类中的registerBeanDefinitionForImportedConfigurationClass方法会把导入的在自己配置类通过@Bean注解创建的类注册到容器中。而loadBeanDefinitionsForBeanMethod方法会解析@Bean注解,把被@Bean注解修饰的方法返回值存入容器。

AnnotationConfigApplicationContext 无参构造方法

无论是基于包扫描的构造函数或者是基于配置类字节码对象的构造函数中,都会调用 AnnotationConfigApplicationContext 类的 this() 无参构造方法。

AnnotationConfigApplicationContext 类的无参构造方法中,主要是初始化注解的读取器 AnnotatedBeanDefinitionReader 与扫描器 ClassPathBeanDefinitionScanner

在执行this.reader = new AnnotatedBeanDefinitionReader(this);时,创建注解读取器AnnotatedBeanDefinitionReader时,在调用AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)方法时完成注解与相应处理类的注册到BeanDefinitionRegistry对象中,会注册一些比较重要的BeanPostProcessor处理类,如:ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor

java
/**
 * Create a new AnnotationConfigApplicationContext that needs to be populated
 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
 */
/*
 * AnnotationConfigApplicationContext(Class<?>... annotatedClasses)
 * AnnotationConfigApplicationContext(String... basePackages)
 * 	以上两个构造函数,创建容器的第一步会调用此无参构造方法
 */
public AnnotationConfigApplicationContext() {
	// 创建读取注解的BeanDefinition读取器
	this.reader = new AnnotatedBeanDefinitionReader(this);
	/*
	 * 创建扫描器,用于扫描包或类,封装成BeanDefinition对象
	 * 		spring默认的扫描器其实不是这个scanner对象
	 * 		而是在后面自己又重新new了一个ClassPathBeanDefinitionScanner
	 * 		spring在执行工程后置处理器ConfigurationClassPostProcessor时,去扫描包时会new一个ClassPathBeanDefinitionScanner
	 * 	这个scanner是为了可以手动调用AnnotationConfigApplicationContext对象的scan方法
	 */
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}
java
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
	this.registry = registry;
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	// 完成相关注解与其相应的处理的类的注册到BeanDefinitionRegistry对象中
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

注:上面的registerAnnotationConfigProcessors()方法,在xml自定义标签标签时的逻辑一致。因为基于纯注解配置,没有了xml配置文件,其实以前基于xml自定义标签(如<context:component-scan>等)来配置注解扫描的解析,也会调用AnnotationConfigUtils.registerAnnotationConfigProcessors()方法,来完成这些组件的注册。

ClassPathScanningCandidateComponentProvider 的 registerDefaultFilters

ClassPathScanningCandidateComponentProviderregisterDefaultFilters() 方法是Spring注册注解类型过滤器的处理逻辑

详情查询源代码工程\spring-note\Spring-Framework\

AbstractApplicationContext 的 refresh()

AbstractApplicationContextrefresh() 方法是初始化容器与创建实现主流程【重点流程】

java
/*
 * 该方法是spring容器初始化的核心方法。是spring容器初始化的核心流程
 * 	 此方法是典型的父类模板设计模式的运用,里面设置很多抽象方法。
 * 	 根据不同的上下文对象,会调用不同的上下文对象子类方法中
 *
 * 核心上下文子类有:
 * 	ClassPathXmlApplicationContext
 * 	FileSystemXmlApplicationContext
 * 	AnnotationConfigApplicationContext
 * 	EmbeddedWebApplicationContext(springboot的上下文对象)
 *
 * 注:此方法重要程度【5】,必看
 */
@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 为容器初始化做准备,设置一些初始化信息,例如启动时间。验证必须要的属性等等。重要程度【0】
		// Prepare this context for refreshing.
		prepareRefresh();
		/*
		 *  告诉子类刷新内部bean工厂。实际就是重新创建一个Bean工厂
		 *  此方法的重要程度【5】,主要的作用如下:
		 *  1. 创建BeanFactory对象
		 *  2. xml解析
		 * 		传统标签解析,如:bean、import等
		 * 		自定义标签解析,如:<context:component-scan base-package="com.moon.learningspring"/>
		 * 		自定义标签解析流程:
		 * 			1. 根据当前解析标签的头信息找到对应的namespaceUri
		 * 			2. 加载spring所以jar中的spring.handlers文件。并建立映射关系
		 * 			3. 根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
		 * 			4. 调用类的init方法,init方法是注册了各种自定义标签的解析类
		 * 			5. 根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
		 *  3. 将解析出来的xml标签封装成BeanDefinition对象
		 */
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// 准备使用创建的这个BeanFactory,此方法给beanFactory设置一些属性值以及添加一些处理器,即准备Spring的上下文环境,重要程度【1】
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);
		try {
			// Allows post-processing of the bean factory in context subclasses.
			// 由子类实现对BeanFacoty的添加一些后置处理器(BeanPostProcessor)。例如,在web环境中bean的作用范围等等。(可以暂时不研究)
			postProcessBeanFactory(beanFactory);
			/*
			 * 在Singleton的Bean对象初始化前,对Bean工厂进行一些处理
			 * 此方法完成实例化实现了以下两个接口的类,并且调用postProcessBeanDefinitionRegistry()方法
			 * 		BeanDefinitionRegistryPostProcessor
			 *  	BeanFactoryPostProcessor
			 */
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);
			// 把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中。即注册拦截bean创建的处理器
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			// 初始化消息资源接口的实现类。主要用于处理国际化(i18n),重要程度【2】
			// Initialize message source for this context.
			initMessageSource();
			// 为容器注册与初始化事件管理类
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();
			/*
			 * 在AbstractApplicationContext的子类中初始化其他特殊的bean
			 * 此方法重点理解模板设计模式,因为在springboot中,此方法是用来完成内嵌式tomcat启动
			 */
			// Initialize other special beans in specific context subclasses.
			onRefresh();
			/*
			 * 往事件管理类中注册事件类应用的监听器,就是注册实现了ApplicationListener接口的监听器bean
			 * 	此方法会与initApplicationEventMulticaster()方法成对出现的
			 */
			// Check for listener beans and register them.
			registerListeners();
			/*
			 * 实例化所有剩余的(非lazy init)单例。(就是没有被@Lazy修饰的单例Bean)
			 * 此方法是spring中最重要的方法(没有之一),重要程度【5】。
			 * 所以此方法要重点理解分析,此方法具体作用如下:
			 * 		1. bean实例化过程
			 * 		2. ioc
			 * 		3. 注解支持
			 * 		4. BeanPostProcessor的执行
			 *		5. Aop的入口
			 */
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);
			// Last step: publish corresponding event.
			// 完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)
			finishRefresh();
		}
		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}
			// Destroy already created singletons to avoid dangling resources.
			// 如果刷新失败那么就会将已经创建好的单例Bean销毁掉
			destroyBeans();
			// Reset 'active' flag.
			// 重置context的活动状态
			cancelRefresh(ex);
			// Propagate exception to caller.
			throw ex; // 抛出异常
		}
		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			// 重置的Spring内核的缓存。因为可能不再需要metadata给单例Bean了
			resetCommonCaches();
		}
	}
}

AbstractBeanFactory 的 doGetBean

AbstractBeanFactorydoGetBean()方法,是实例化和获取Bean对象的主要流程

详情查询源代码工程\spring-note\Spring-Framework\

BeanNameGenerator及其实现类

BeanNameGenerator 接口位于 org.springframework.beans.factory.support 包下面:

java
public interface BeanNameGenerator {
	/**
	 * Generate a bean name for the given bean definition.
	 * @param definition the bean definition to generate a name for
	 * @param registry the bean definition registry that the given definition
	 * is supposed to be registered with
	 * @return the generated bean name
	 */
	String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}

它有两个实现类,分别是:

  • DefaultBeanNameGenerator是给资源文件加载bean时使用(BeanDefinitionReader中使用)
  • AnnotationBeanNameGenerator是为了处理注解生成beanName的情况。

DefaultBeanNameGeneratorAnnotationBeanNameGenerator详见代码工程的注释

ConfigurationClassPostProcessor 类

registerAnnotationConfigProcessors()方法中,会完成很多注解处理类的注册,ConfigurationClassPostProcessor类的作用就是支持了@Configuration@Component@ComponentScan@Import@ImportResource@PropertySource@Order 等注解的注册,对于理解 springboot 帮助很大,真正的可以做到零 xml 配置

类作用分析

java
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware

从类的继承关系可以看出,ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口,所以此类主要的作用就是在处理容器实例化前对BeanDefinition进行操作并且加入到BeanDefinitionRegistry注册中心中

此类也实现了PriorityOrdered,并且设置优先为最低,会在所有的BeanDefinitionRegistryPostProcessor接口实现类都调用后,才会进行调用

java
@Override
public int getOrder() {
	return Ordered.LOWEST_PRECEDENCE;  // within PriorityOrdered
}

bean实例化前的处理

ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口,所以实例化bean前会调用postProcessBeanDefinitionRegistry方法

java
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	// 此方法会完成很多注解处理类的注册,核心逻辑,重要程度【5】
	processConfigBeanDefinitions(registry);
}

包含所支持的注解的类收集

调用processConfigBeanDefinitions方法,完成有包含可支持注解的BeanDefinition收集

java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	// 获取所有的beanNames
	String[] candidateNames = registry.getBeanDefinitionNames();

    // 此循环所有BeanDefinition的作用是判断要创建的类上是否有需要处理的注解
	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		// 如果有该标识就不再处理
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		// 判断类上是否有@Configuration、@Component,或者类中的方法有@Bean注解,如果是则放入List集合容器configCandidates
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

	// Return immediately if no @Configuration classes were found
	// 如果容器为空,即没有找到以上的注解,则直接返回
	if (configCandidates.isEmpty()) {
		return;
	}
	....省略
}

通过BeanDefinitionRegistry对象获取到容器中所有BeanDefinition,循环所有并调用ConfigurationClassUtils.checkConfigurationClassCandidate方法,判断循环当前类上是否有包含需要处理的注解(如:@Configuration@Component,或者类中的方法有@Bean注解)

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

	String className = beanDef.getBeanClassName();
	if (className == null || beanDef.getFactoryMethodName() != null) {
		return false;
	}

	AnnotationMetadata metadata;
	// 如果是扫描注解产生的BeanDefinition
	if (beanDef instanceof AnnotatedBeanDefinition &&
			className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
		// Can reuse the pre-parsed metadata from the given BeanDefinition...
		metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
	}
	// 非扫描注解产生的BeanDefinition
	else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
		// Check already loaded Class if present...
		// since we possibly can't even load the class file for this Class.
		Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
		if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
				BeanPostProcessor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
				EventListenerFactory.class.isAssignableFrom(beanClass)) {
			return false;
		}
		metadata = AnnotationMetadata.introspect(beanClass);
	}
	else {
		try {
			MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
			metadata = metadataReader.getAnnotationMetadata();
		}
		catch (IOException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Could not find class file for introspecting configuration annotations: " +
						className, ex);
			}
			return false;
		}
	}

	// 从metadata中获取@Configuration注解
	Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
	// 判断如果有@Configuration注解,设置一个标识(CONFIGURATION_CLASS_FULL="full"),代表完全匹配标识
	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	/*
	 * 判断是否有@Component、@ComponentScan、@Import、@ImportResource注解或者方法上面有@Bean注解,
	 * 或者类上面没注解(xml配置实例化)但方法上面有@Bean注解
	 * 如果是,则设置一个标识(CONFIGURATION_CLASS_LITE="lite"),代表部分匹配标识
	 */
	else if (config != null || isConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}

	// 获取@Order注解值,用于排序
	// It's a full or lite configuration candidate... Let's determine the order value, if any.
	Integer order = getOrder(metadata);
	if (order != null) {
		beanDef.setAttribute(ORDER_ATTRIBUTE, order);
	}

	return true;
}

判断是否为所支持的注解

java
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
	// Do not consider an interface or an annotation...
	if (metadata.isInterface()) {
		return false;
	}

	// Any of the typical annotations found?
	// 判断是否包含@Component,@ComponentScan,@Import,@ImportResource
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}

	// Finally, let's look for @Bean methods...
	try {
		// 判断是否有@Bean注解
		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;
	}
}

Set集合candidateIndicators所包含的支持的注解名称

ConfigurationClassParser - 解析候选BeanDefinition中的相关注解

收集完候选的BeanDefinition后,程序继续往下执行,会创建一个注解的解析类ConfigurationClassParser,然后对筛选出来的

java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    ....省略
    // Parse each @Configuration class
	// 此处创建一个重要的ConfigurationClassParser类(对候选BeanDefinition的解析),是对@ComponentScan @Configuration支持
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);

	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	// 用于存放已经处理过的类,因为有些类会通过@Import重复导入一些类
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		// ConfigurationClassParser类的解析核心流程,重要程度【5】
		// 将相关的支持的注解进行封装,即把类上面的特殊注解解析出来最终封装成BeanDefinition
		parser.parse(candidates);
		parser.validate();
        ....省略
	}
	while (!candidates.isEmpty());
    ....省略
}

调用ConfigurationClassParser.parse方法循环解析

java
public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			// 扫描注解得到的BeanDefinition
			if (bd instanceof AnnotatedBeanDefinition) {
				parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
			}
			// 非扫描注解得到的BeanDefinition(如自己手动创建的BeanDefinition注册到BeanDefinitionRegistry)
			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);
		}
	}
	// 这行代码不能忽视
	this.deferredImportSelectorHandler.process();
}
java
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
	// 将metadata对象与beanName再封装成ConfigurationClass对象
	processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

doProcessConfigurationClass方法进行相关注解的解析。

java
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
	// 对@Condition注解的支持,过滤掉不需要实例化的类
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}

	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				existingClass.mergeImportedBy(configClass);
			}
			// Otherwise ignore new imported config class; existing non-imported class overrides it.
			return;
		}
		else {
			// Explicit bean definition found, probably replacing an import.
			// Let's remove the old one and go with the new one.
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}

	// Recursively process the configuration class and its superclass hierarchy. --> 翻译:递归处理配置类及其超类层次结构
	/*
	 * 封装成SourceClass对象(ConfigurationClassParser的内部类),此对象主要封装了处理类的Class对象与类相关信息的metadata对象
	 * 这个对象理解为跟类或者接口对应,然后把metadata对象包装进去了
	 */
	SourceClass sourceClass = asSourceClass(configClass, filter);
	do {
		// 处理相关注解解析,核心代码,重要程度【5】
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	}
	while (sourceClass != null);

	this.configurationClasses.put(configClass, configClass);
}

@Conditional 实现原理

注解作用

@Conditional注解作用是根据条件选择是否注入的bean对象到Spring容器中。该注解可以作用在类、方法上。该注解的value属性的值老百姓提供一个或者多个Condition接口的实现类,实现类中需要编写具体代码实现注册到ioc容器的条件。重写接口的matches方法,返回true表示通过校验可实例化到容器

源码分析

@Conditional注解处理源码位置:ConfigurationClassParser.processConfigurationClass()。如果进入if代码块,则不会执行到最后增加到configurationClasses,就不会加入到BeanDefinitionRegistry

java
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
	// 对@Condition注解的支持,过滤掉不需要实例化的类
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}
	....省略
	this.configurationClasses.put(configClass, configClass);
}

主要的校验在ConditionEvaluator类的shouldSkip方法中

java
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
	// 判断当前类上是否有注解没有@Conditional注解,则直接结束,不作校验
	if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
		return false;
	}

	if (phase == null) {
		if (metadata instanceof AnnotationMetadata &&
				ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
			return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
		}
		return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
	}

	List<Condition> conditions = new ArrayList<>();
	// 获取@Conditional注解的value值
	for (String[] conditionClasses : getConditionClasses(metadata)) {
		for (String conditionClass : conditionClasses) {
			// 根据value属性配置的字节码,反射实例化Condition对象
			Condition condition = getCondition(conditionClass, this.context.getClassLoader());
			conditions.add(condition);
		}
	}

	// 排序
	AnnotationAwareOrderComparator.sort(conditions);

	// 调用每个condition实例的matches方法
	for (Condition condition : conditions) {
		ConfigurationPhase requiredPhase = null;
		if (condition instanceof ConfigurationCondition) {
			requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
		}
		// 调用matches方法
		if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
			return true;
		}
	}

	return false;
}

使用示例

注:此事例只是基础使用,真正功能实现不严谨

  • 创建条件注解
java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(CustomOnClassCondition.class)
public @interface MoonConditionalOnClass {
    Class<?>[] value() default {};
    String[] name() default {};
}
  • 编写条件校验实现类
java
public class CustomOnClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (metadata.isAnnotated(MoonConditionalOnClass.class.getName())) {
            Class<?>[] classes = metadata.getAnnotations().get(MoonConditionalOnClass.class).getClassArray("value");
            try {
                for (Class<?> clazz : classes) {
                    ClassUtils.forName(clazz.getName(), ClassUtils.getDefaultClassLoader());
                }
                return true;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}
  • 标识待创建的类
java
@Component
@MoonConditionalOnClass(Dog.class)
public class ConditionalBean {
}

@Component 实现原理

@ComponentConfigurationClassParser.doProcessConfigurationClass方法中,去处理该注解

java
// 判断类上面是否有@Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
	// Recursively process any member (nested) classes first --> 翻译:首先递归处理任何成员(嵌套)类
	// 递归处理有@Component注解的内部类
	processMemberClasses(configClass, sourceClass, filter);
}

调用processMemberClasses方法,获取当前类中的所有内部类(如果包含内部类有该注解,则会递归处理)

java
/**
 * Register member (nested) classes that happen to be configuration classes themselves.
 */
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
		Predicate<String> filter) throws IOException {

	// 获取当前类的内部类并又包装成sourceClass对象
	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 {
					/*
					 * candidate 是 configClass 的内部类,此处将内部类包装成ConfigurationClass类
					 *  即相对来说变成了外部类,然后调用processConfigurationClass方法,进行递归处理
					 */
					processConfigurationClass(candidate.asConfigClass(configClass), filter);
				}
				finally {
					this.importStack.pop();
				}
			}
		}
	}
}

@PropertySource 与 @PropertySources 实现原理

@PropertySource@PropertySourcesConfigurationClassParser.doProcessConfigurationClass方法中,会循环当前类中所有此两个注解进行解析

java
// Process any @PropertySource annotations
// 处理 @PropertySources 和 @PropertySource 注解
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");
	}
}

读取并封装@PropertySource@PropertySources注解的信息。在this.environment.resolveRequiredPlaceholders(location)方法,就是用来解析占位符,如不是占位符,则直接返回原数据

java
/**
 * Process the given <code>@PropertySource</code> annotation metadata.
 * @param propertySource metadata for the <code>@PropertySource</code> annotation found
 * @throws IOException if loading a property source failed
 */
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
	String name = propertySource.getString("name");
	if (!StringUtils.hasLength(name)) {
		name = null;
	}
	String encoding = propertySource.getString("encoding");
	if (!StringUtils.hasLength(encoding)) {
		encoding = null;
	}
	// 获取配置文件路径
	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中的配置属性封装成Properties对象中,并创建PropertySource对象加入到Environment对象中
			addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
		}
		catch (IllegalArgumentException | FileNotFoundException | UnknownHostException 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;
			}
		}
	}
}

根据配置的location值,通过流的方式读取配置文件,并转成Resource对象,然后调用addPropertySource方法,获取Environment对象中的MutablePropertySourcesPropertySources的子类),然后将每个配置文件转成的PropertySource加入到MutablePropertySources中。注:如果出现多个@PropertySource配置的name名称一样的,会将PropertySource进行合并成CompositePropertySource类型,其实将新旧的值都保存起来再合并

java
private void addPropertySource(PropertySource<?> propertySource) {
	String name = propertySource.getName();
	// 获取Environment对象中的MutablePropertySources
	MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();

	// 如果已经存在了该配置文件的PropertySource则进行合并
	if (this.propertySourceNames.contains(name)) {
		// We've already added a version, we need to extend it
		PropertySource<?> existing = propertySources.get(name);
		if (existing != null) {
			PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
					((ResourcePropertySource) propertySource).withResourceName() : propertySource);
			// 合并二次后的类型
			if (existing instanceof CompositePropertySource) {
				((CompositePropertySource) existing).addFirstPropertySource(newSource);
			}
			else {
				if (existing instanceof ResourcePropertySource) {
					existing = ((ResourcePropertySource) existing).withResourceName();
				}
				// 其实就是CompositePropertySource里面有一个Set,Set里面装了新和旧的PropertySource对象
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(newSource);
				composite.addPropertySource(existing);
				// 合并
				propertySources.replace(name, composite);
			}
			return;
		}
	}

	if (this.propertySourceNames.isEmpty()) {
		propertySources.addLast(propertySource);
	}
	else {
		// 用于计算插入的位置index
		String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
		// 把propertySource对象存入MutablePropertySources的list中
		propertySources.addBefore(firstProcessed, propertySource);
	}
	// 将解析过的@PropertySource的name值加到集合中
	this.propertySourceNames.add(name);
}

@ComponentScan 实现原理

测试@ComponentScan配置扫描

  • 创建配置类,在类上增加@ComponentScan注解,作用相当于xml配置文件中的<context:component-scan base-package="com.moon.spring"/>标签
java
package com.moon.spring.config;

import org.springframework.context.annotation.ComponentScan;

/**
 * 测试 @ComponentScan 注解配置类
 */
@ComponentScan(basePackages = {"com.moon.spring"})
public class ComponentScanConfig {
}
  • 测试,将Spring的xml配置文件注释后,传入上面创建的测试配置类ComponentScanConfig类,创建AnnotationConfigApplicationContext对象
java
// @RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration(locations = {"classpath:spring.xml"})
public class MyTest {
    @Test
    public void componentScanTest() {
        applicationContext = new AnnotationConfigApplicationContext(ComponentScanConfig.class);
        System.out.println("@ComponentScan Test --> " + applicationContext.getBean("userServiceImpl"));
    }
}

开启xml配置注解扫描标签的差异

  • 如果不开启xml配置文件中的注解扫描时,运行AnnotationConfigApplicationContext测试,会发现BeanDefinitionRegistry对象中的BeanDefinitionNames只有当前传入的类名称

  • 如果开启xml配置文件中的注解扫描时,同样运行AnnotationConfigApplicationContext测试,会发现BeanDefinitionRegistry对象中的BeanDefinitionNames已经注册很多BeanDefinition名称

以上的差异是因为在spring的核心方法AbstractApplicationContext.refresh()方法中,执行的逻辑时序是先解析xml配置文件,再调用BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry()方法读取已经注册的BeanDefinition名称

解析流程

@ComponentScanConfigurationClassParser.doProcessConfigurationClass方法中,去处理该注解

java
// Process any @ComponentScan annotations --> 翻译:处理任何@ComponentScan注解
// 从metaData对象中获取是否有@ComponentScans或@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
		sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
// 判断是否存在@ComponentScans注解,并且是否需要跳过
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
		// 处理@ComponentScan注解,此parse方法里面的逻辑,基本上跟<component-scan>自定义标签解析的逻辑差不多
		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
		// 扫描到@Component生成beanDefinition后,又递归去校验类上面是否有特殊注解
		for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
			BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
			if (bdCand == null) {
				bdCand = holder.getBeanDefinition();
			}
			// 判断是否是候选的BeanDefinition,如果是则又递归调用parse方法
			if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
				parse(bdCand.getBeanClassName(), holder.getBeanName());
			}
		}
	}
}

this.componentScanParser.parse()方法的处理逻辑基本上自定义标签<context:component-scan>解析逻辑差不多,先创建扫描器,解析配置了includeFilters属性与excludeFilters属性,最后调用ClassPathBeanDefinitionScanner.doScan方法进行扫描

与自定义标签扫描调用的方法一样

值得注意的是,在处理包扫描后,此时扫描出来类都只是包含@Component注解,然而这些类上可能还会有其他的注解(如:@Import@Bean等等注解)。此时就又会调用ConfigurationClassUtils.checkConfigurationClassCandidate方法进行是否有候选待处理的注解,如果有,则再递归调用ConfigurationClassParser.parse方法

@Import 实现原理

@ImportConfigurationClassParser.doProcessConfigurationClass方法中,去处理该注解

java
// 解析@Import注解,其注解的作用是引入一个(或多个)类,getImports(sourceClass) 获取类上面的@Import注解导入的类并封装成SourceClass的set集合
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

getImports 收集所有导入的类数据

收集@Import注解value属性配置导入的多个类字节码对象,又将每个导入的类包装成SourceClass对象。

java
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
	Set<SourceClass> imports = new LinkedHashSet<>();
	Set<SourceClass> visited = new LinkedHashSet<>();
	collectImports(sourceClass, imports, visited);
	return imports;
}
java
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
		throws IOException {

	if (visited.add(sourceClass)) {
		// 获取当前类所有注解
		for (SourceClass annotation : sourceClass.getAnnotations()) {
			String annName = annotation.getMetadata().getClassName();
			// 判断如果当前是@Import注解,则跳过;不是则递归再调用collectImports方法
			if (!annName.equals(Import.class.getName())) {
				// 递归调用
				collectImports(annotation, imports, visited);
			}
		}
		// 最后将@Import注解的value属性配置的多个类又包装成SourceClass对象,增加到Set<SourceClass> imports 集合容器中
		imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
	}
}

processImports

processImports方法是处理@Import注解的主要逻辑源码与分析如下:

java
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
		boolean checkForCircularImports) {

	// 如果收集@Import注解导入的类set集合为空,则不处理直接返回
	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)) {
					// Candidate class is an ImportSelector -> delegate to it to determine imports
					Class<?> candidateClass = candidate.loadClass();
					// 反射实例化
					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);
					}
					// 判断@Import注解引入的是DeferredImportSelector类型
					if (selector instanceof DeferredImportSelector) {
						// 如果为延迟导入处理则加入集合当中,比较复杂,SpringBoot中自动配置会用到
						this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
					}
					else {
						// 调用ImportSelector接口的selectImports方法,获取方法返回的类全限定名称数组
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						// 根据ImportSelector接口方法的返回值来进行递归操作,将返回的类都封装成SourceClass对象
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
						// 递归处理,有可能import进来的类上又有@Import注解
						processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
					}
				}
				// 判断@Import注解引入的是ImportBeanDefinitionRegistrar类型
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
					// Candidate class is an ImportBeanDefinitionRegistrar ->
					// delegate to it to register additional bean definitions
					Class<?> candidateClass = candidate.loadClass();
					// 反射实例化
					ImportBeanDefinitionRegistrar registrar =
							ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
									this.environment, this.resourceLoader, this.registry);
					/*
					 * 加入到Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars容器中,
					 *  这里还没有调用registerBeanDefinitions方法
					 */
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
				else {
					// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
					// process it as an @Configuration class
					// 如果当前的类既不是ImportSelector也不是ImportBeanDefinitionRegistar就按@Configuration注解解析流程去处理
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					// 如果都不是,则调用@Configuration注解的处理方法
					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();
		}
	}
}
  • 方法的第一行语句importCandidates.isEmpty()的判断就说明了,如果没有收集到@Import注解导入的类,则程序不会继续往下执行。意味着ImportSelectorDeferredImportSelectorImportBeanDefinitionRegistrar等接口的实现也不会被调用了。
  • 判断是否ImportSelector接口类型,通过反射实例化import导入的类(不会注册到spring ioc容器)
    • 此处会一个分支,如果当前又是DeferredImportSelector接口类型,会延迟导入处理,加入一个容器中,SpringBoot中自动配置会用到
    • 否则直接调用ImportSelector接口的selectImports方法,获取方法返回值后封装成SourceClass对象数组,递归调用processImports方法(因为有可能import导入的类上又有@Import注解)
  • 判断是否ImportBeanDefinitionRegistrar接口类型,也通过反射实例化import导入的类(不会注册到spring ioc容器),加入到Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars容器中,这里还没有调用接口的registerBeanDefinitions方法
  • 判断都不是以上两种类型,按@Configuration注解解析流程去处理,调用processConfigurationClass方法解析

ImportSelector 与 ImportBeanDefinitionRegistrar 接口运用小示例

  • 创建自定义注解用于测试
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface CustomAnnotation {
    String[] value() default {};
}
  • 创建配置类,使用@Import注解导入
java
@ComponentScan(Constants.BASE_PACKAGES)
// 使用@Import注解导入一个(或多个)类,导入的类不需要再使用@Component相关注解即可
@Import({Bird.class, Cat.class, ImportSelectorDemo.class, ImportBeanDefinitionRegistrarDemo.class})
// 用于测试导入ImportSelector与ImportBeanDefinitionRegistrar接口实现方法是否以下注解信息
@CustomAnnotation({"MooN", "L", "kirA"})
public class AppConfig {
}
  • ImportSelector接口示例
java
public class ImportSelectorDemo implements ImportSelector {
    /**
     * 此方法用于批量导入bean对象到ioc容器
     *
     * @param importingClassMetadata 导入类上相关注解信息,此示例是获取到AppConfig类上的所有注解
     * @return 需要注册到ioc容器的bean的全限定名数组
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("ImportSelectorDemo.selectImports() 方法执行了....");

        /* 获取导入类的所有注解信息 */
        MergedAnnotations annotations = importingClassMetadata.getAnnotations();
        // 获取@CustomAnnotation自定义注解数据
        if (importingClassMetadata.hasAnnotation(CustomAnnotation.class.getName())) {
            MergedAnnotation<CustomAnnotation> customAnnotation = annotations.get(CustomAnnotation.class);
            Optional<String[]> value = customAnnotation.getValue("value", String[].class);
            value.ifPresent(v -> {
                for (String s : v) {
                    System.out.println("CustomAnnotation注解的value值:" + s);
                }
            });
        }

        // 获取@ComponentScan注解数据
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            Optional<String[]> value = annotations.get(ComponentScan.class).getValue("value", String[].class);
            value.ifPresent(v -> {
                for (String s : v) {
                    System.out.println("ComponentScan注解的value值:" + s);
                }
            });
        }

        // 返回需要实例化类的全限定名数组
        return new String[]{Parent.class.getName(), Son.class.getName()};
    }
}
  • ImportBeanDefinitionRegistrar接口示例
java
public class ImportBeanDefinitionRegistrarDemo implements ImportBeanDefinitionRegistrar {
    /**
     * 此方法无返回值,需要在方法中手动注册bean到注册中心容器中
     *
     * @param importingClassMetadata 使用@Import注解的类上所有的注解信息,
     *                               此示例即SpringConfiguration类上所有注解信息
     * @param registry               BeanDefinition注册中心
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
                                        BeanNameGenerator importBeanNameGenerator) {
        System.out.println("ImportBeanDefinitionRegistrarDemo.registerBeanDefinitions() 方法执行了....");

        /* importingClassMetadata 一样可以获取导入类的所有注解信息 */
        MergedAnnotations annotations = importingClassMetadata.getAnnotations();

        // 需要手动将实例化类加入到registry注册中心
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(Student.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.addPropertyValue(new PropertyValue("username", "ImportBeanDefinitionRegistrar接口修改的名称"));
        beanDefinition.setPropertyValues(propertyValues);
        String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);
        System.out.println("BeanNameGenerator类生成的BeanDefinition的名称是:" + beanName); // com.moon.spring.bean.Student
        // 注册BeanDefinition
        registry.registerBeanDefinition(beanName, beanDefinition);
    }
}
  • 控制台打印相关测试到容器的类,测试结果如下:

DeferredImportSelector 接口调用流程与使用示例

基础使用示例
  • 创建DeferredImportSelector接口实现
java
/**
 * DeferredImportSelector 接口实现示例
 * 具体方法的时序是:
 * DeferredImportSelector.getImportGroup.getImportGroup
 * --> DeferredImportSelector.Group.process
 * --> DeferredImportSelector.Group.selectImports
 */
public class DeferredImportSelectorDemo implements DeferredImportSelector {
    /**
     * 此方法是DeferredImportSelector继承了父接口ImportSelector。
     * 此方法不会被调用,只能是通过手动调用
     *
     * @param importingClassMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("DeferredImportSelectorDemo.selectImports()方法执行了....");
        // 返回需要实例化的类全限定名数组
        return new String[]{Chocolate.class.getName()};
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return null;
    }

    /**
     * 返回一个实现了DeferredImportSelector.Group接口的类的Class对象
     *
     * @return
     */
    @Override
    public Class<? extends Group> getImportGroup() {
        return DeferredImportSelectorGroupImpl.class;
    }

    /**
     * 内部类,实现了DeferredImportSelector.Group接口
     */
    private static class DeferredImportSelectorGroupImpl implements DeferredImportSelector.Group {

        private List<Entry> list = new ArrayList<>();

        /**
         * 处理流程,收集需要加入到Spring容器实例化的类
         *
         * @param metadata 使用@Import注解导入的类的所有注解元数据
         * @param selector 外部类 DeferredImportSelectorDemo 实例
         */
        @Override
        public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
            System.out.println("DeferredImportSelectorGroupImpl.process()方法执行了....");
            // 调用外部类方法,将selectImports方法,获取要创建的类集合
            for (String s : selector.selectImports(metadata)) {
                // 创建Entry对象增加到内部属性集合中
                list.add(new Entry(metadata, s));
            }
        }

        /**
         * 将process收集到的数据(封装成Group.Entry对象),返回
         *
         * @return
         */
        @Override
        public Iterable<Entry> selectImports() {
            System.out.println("DeferredImportSelectorGroupImpl.selectImports()方法执行了....");
            // 返回process方法收集的数据
            return this.list;
        }
    }
}
  • 使用@Import注解导入
java
@ComponentScan(Constants.BASE_PACKAGES)
@Import({DeferredImportSelectorDemo.class})
public class AppConfig {
}
  • 测试
java
@Test
public void testDeferredImportSelectorBasic() {
    Chocolate bean = context.getBean(Chocolate.class);
    System.out.println(bean);
    /*
     * 调用方法的时序如下
     * ImportSelectorDemo.selectImports() 方法执行了....
     * DeferredImportSelectorGroupImpl.process()方法执行了....
     * DeferredImportSelectorDemo.selectImports()方法执行了....
     * DeferredImportSelectorGroupImpl.selectImports()方法执行了....
     */
}
源码分析

源码位置:ConfigurationClassParser.processImports

主要的处理逻辑:

java
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
	// 将方法的入参再包装成DeferredImportSelectorHolder对象
	DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
	if (this.deferredImportSelectors == null) {
		// 创建DeferredImportSelectorGroup接口的处理类
		DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
		// 注册并调用DeferredImportSelector接口的方法
		handler.register(holder);
		// 收集后调用
		handler.processGroupImports();
	}
	else {
		this.deferredImportSelectors.add(holder);
	}
}

首先调用DeferredImportSelector接口的getImportGroup方法,获取返回实现了Group接口的类,没有实现Group接口,则会父接口ImportSelectorselectImports方法

java
public void register(DeferredImportSelectorHolder deferredImport) {
	// 首先调用getImportGroup方法,返回实现了Group接口的类
	Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
	// 建立实现了Group接口类和DeferredImportSelectorGrouping的映射关系
	DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
			// 这里如果getImportGroup方法没有返回实现Group接口的类,则后面调用就是父接口ImportSelector的selectImports方法
			(group != null ? group : deferredImport),
			key -> new DeferredImportSelectorGrouping(createGroup(group)));
	grouping.add(deferredImport);
	this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
			deferredImport.getConfigurationClass());
}

createGroup方法中,返回Group接口的实现,这里就会判断,如果没有自定义的Group实现或者没有重写getImportGroup()方法返回实现的话,这里就是使用Spring提供的默认的实现:DefaultDeferredImportSelectorGroup

收集完成后,如果有Group接口实现,则会调用了process方法后再调用selectImports方法;如果没有Group接口的实现,则直接会调用父接口的selectImports方法。无论那种逻辑,还是会获取到需要实例化的类全限定名(包装成Entry对象)集合,最后就会递归去调用processImports处理每个待实例化的类。

java
public void processGroupImports() {
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
		Predicate<String> exclusionFilter = grouping.getCandidateFilter();
		// 这里调用了Group接口的selectImports()方法
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
			try {
				// 又递归处理每一个返回的Entry
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
						Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
						exclusionFilter, false);
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
								configurationClass.getMetadata().getClassName() + "]", ex);
			}
		});
	}
}
java
public Iterable<Group.Entry> getImports() {
	// 调用了实现了Group接口的process方法
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	// 在这里调用了实现了Group接口的selectImports方法
	return this.group.selectImports();
}

@ImportResource 实现原理

@ImportResourceConfigurationClassParser.doProcessConfigurationClass方法中,去处理该注解,其处理流程与xml配置文件解析处理流程一样

java
// Process any @ImportResource annotations
// 解析@ImportResource注解,其注解的作用是引入一个xml配置文件,目前的项目都是基于注解开发,所以没什么用
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);
		// 建立xml文件和reader的映射关系
		configClass.addImportedResource(resolvedResource, readerClass);
	}
}

@Bean 实现原理

@BeanConfigurationClassParser.doProcessConfigurationClass方法中,去收集该注解所标识的方法,放到ConfigurationClass类的beanMethods容器(Set<BeanMethod>)中

java
/* 处理@Bean注解,重要程度【5】 */
// Process individual @Bean methods
// 收集有@Bean注解的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
	// 加入到ConfigurationClass的beanMethods容器中
	configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

// 处理接口里面方法有@Bean注解的,逻辑差不多
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);

注解收集与解析完成后的处理

parser.parse(candidates)注解解析方法完成后,ConfigurationClassPostProcessor.processConfigBeanDefinitions的方法继续往下执行

java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    ....省略
	do {
		// ConfigurationClassParser类的解析核心流程,重要程度【5】
		// 将相关的支持的注解进行封装,即把类上面的特殊注解解析出来最终封装成BeanDefinition
		parser.parse(candidates);
		parser.validate();

        // 从configurationClasses容器中,获取上面解析完成的类后所包装成的ConfigurationClass对象
		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		configClasses.removeAll(alreadyParsed);

		// Read the model and create bean definitions based on its content
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
        // 设置BeanDefinition的属性值,具体执行 @Import/@ImportSource/@Bean 的逻辑。重要程度【5】
		this.reader.loadBeanDefinitions(configClasses);
		// 将已经解析完成了的类放到一个set集合中
		alreadyParsed.addAll(configClasses);

		candidates.clear();
		// 比较差异又走一遍解析流程
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			Set<String> alreadyParsedClasses = new HashSet<>();
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());
    ....省略
}

但前面都是主要处理与解析了注解,但一些通过 @Import@ImportSource@Bean导入进来的类或者内部类都还没有加入到BeanDefinitionRegistry注册中心,只是在ConfigurationClassParser.processConfigurationClass方法,将这些类都放到Map<ConfigurationClass, ConfigurationClass> configurationClasses的容器中

所以获取前面已解析的后的类集合,在loadBeanDefinitions方法中循环处理@Import@ImportSource@Bean等注解导入的类封装成BeanDefinition与解析xml资源文件,还有调用实现了ImportBeanDefinitionRegistrar接口的方法

java
private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator 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;
	}

	// 判断是否通过@Import注解导入的类或者是内部类,将封装成BeanDefinition
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	// 循环当前类中所有@Bean注解的方法,将方法返回封装成BeanDefinition
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}

	// 执行有@ImportResource注解的逻辑,主要是调用了xml配置文件的解析逻辑
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 调用ImportBeanDefinitionRegistra接口的方法
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

@Import 导入类的处理

调用registerBeanDefinitionForImportedConfigurationClass方法,对@Import导入的类封装成BeanDefinition,填充类标识了的注解信息,并注册

java
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
	// 获取当前类的注解元信息
	AnnotationMetadata metadata = configClass.getMetadata();
	AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

	ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
	configBeanDef.setScope(scopeMetadata.getScopeName());
	// 生成bean的名称
	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);
	// 注册ImportBeanDefinitionRegistrar
	this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
	configClass.setBeanName(configBeanName);

	if (logger.isTraceEnabled()) {
		logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
	}
}

@Bean 注解的处理

前面已经收集过每个标识了@Bean注解的方法,并封装成BeanMethod对象。此处调用loadBeanDefinitionsForBeanMethod方法,封装成BeanDefinition对象,并注册

需要注意的是:通过@Bean注解创建的对象,会设置其相应的BeanDefinition的factoryBeanName属性值为当前类的名称,factoryMethodName属性值为当前方法名

@ImportedResources 注解的处理

调用loadBeanDefinitionsFromImportedResources进入xml文件的解析,与前面的xml配置文件解析逻辑一样

java
private void loadBeanDefinitionsFromImportedResources(
		Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

	Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();

	importedResources.forEach((resource, readerClass) -> {
		// Default reader selection necessary?
		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 {
				// Instantiate the specified BeanDefinitionReader
				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解析方法(与xml方式配置的处理解析一样)
		// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
		reader.loadBeanDefinitions(resource);
	});
}

ImportBeanDefinitionRegistrar 接口的调用

在前面注解的解析时,将@Import注解导入的ImportBeanDefinitionRegistrar接口类型反射实例化,并存入importBeanDefinitionRegistrars的容器中

loadBeanDefinitionsFromRegistrars方法中,循环调用所有ImportBeanDefinitionRegistrar接口的实现

java
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
	registrars.forEach((registrar, metadata) ->
			registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

比较差异

执行完parseloadBeanDefinitions方法后,会获取最新注册器中所有BeanDefinition数量,与原来的比较差异,如果不一样,又要执行多一次解析流程

@Configuration 注解

@Configuration 与 @Component 的差异

手动调用 @Bean 注解方法获取对象

手动调用实现FactoryBean接口的getObject方法

  • 创建FactoryBean接口实现
java
public class MyFactoryBean implements FactoryBean<Bird> {

    @Override
    public Bird getObject() throws Exception {
        return new Bird();
    }

    @Override
    public Class<?> getObjectType() {
        return Bird.class;
    }
}
  • 使用@Bean注解创建FactoryBean接口实现类实例,并在其他方法调用该getObject方法

  • 运行测试结果:使用@Component注解时,两个hashCode的结果不一样;而使用@Configuration注解时,两个hashCode的结果一致

源码分析

经上面差异测试,可以知道,在调用@Bean注解的方法获取对象时,不是通过类实例本身调用,而是通过代理调用

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,分别实现了postProcessBeanDefinitionRegistrypostProcessBeanFactory方法。而在前面的源码分析中,此两个方法的调用时序是:先postProcessBeanDefinitionRegistrypostProcessBeanFactory

postProcessBeanDefinitionRegistry方法主要处理注解解析与收集,还有一些接口的调用;而postProcessBeanFactory方法就是处理@Configuration注解生成代理的逻辑

postProcessBeanFactory 方法

java
/* 将配置类替换为CGLIB增强的子类,用于运行时请求生成bean实例 */
@Override
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 hook apparently not supported...
		// Simply call processConfigurationClasses lazily at this point then.
		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
	}
	// 将标识@Configuration的类生成CGlib增加子类
	enhanceConfigurationClasses(beanFactory);
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

生成CGlib代理子类

enhanceConfigurationClasses方法中,会将原来标识了@Configuration的类生成增强的子类。注:CGlib的作用只是动态生成一个增强的字节码文件并加载到jvm中,而真正的实例化由spring来处理

java
// 创建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));
	// 设置Callback调用处理筛选器
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	// 设置Callback数组
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	return enhancer;
}

代理调用MethodInterceptor的筛选

isMath方法中,判断调用哪个callback方法的逻辑

所以当前的method带有@Bean注解的话,就会调用BeanMethodInterceptor这个实例的intercept方法

BeanMethodInterceptor 类调用代理方法

上面筛选后就是使用代理调用方法的逻辑,在BeanMethodInterceptor.intercept方法中实现普通的@Bean方法的代理调用

以下是在@Bean注解的方法调用FactoryBean接口实现的处理

Spring 相关功能与设计

BeanPostProcessor 接口理解

BeanPostProcessor 接口类型实例是针对某种特定功能的埋点,在这个点会根据接口类型来过滤掉不关注这个点的其他类,只有真正关注的类才会在这个点进行相应的功能实现。

获取有 @Autowired 注解的构造函数埋点

  • 作用:用于收集创建中Bean实例中有@Autowired注解的构造函数
  • 此功能实现的BeanPostProcessor接口类型是:SmartInstantiationAwareBeanPostProcessor
  • 调用的方法是:determineCandidateConstructors

收集注解的方法和属性埋点

  • 作用:收集@Resource@Autowired@Value@PostConstruct@PreDestroy等注解,并收集的信息封装成InjectionMetadata对象
  • 此功能实现的BeanPostProcessor接口类型是:MergedBeanDefinitionPostProcessor
  • 调用的方法是:postProcessMergedBeanDefinition

解决循环依赖提前暴露bean实例的埋点

  • 作用:用于从三级缓存中暴露bean的实例,如果当前bean不需要增加装饰或者生成代理,则直接返回,此设计方便日后增强
  • 此功能实现的BeanPostProcessor接口类型是:SmartInstantiationAwareBeanPostProcessor
  • 调用的方法是:getEarlyBeanReference

阻止依赖注入的埋点

  • 作用:在实例属性依赖注入前,阻止继续执行依赖注入的逻辑
  • 此功能实现的BeanPostProcessor接口类型是:InstantiationAwareBeanPostProcessor
  • 调用的方法是:postProcessAfterInstantiation

IOC/DI 依赖注入埋点

  • 此功能实现的BeanPostProcessor接口类型是:InstantiationAwareBeanPostProcessor
  • 调用的方法是:postProcessProperties(新版本才是调用此方法)

Spring 配置文件的解析

基础使用示例

准备测试类、xml配置、properties文件

java
@Data
public class PropertyBean {
    private String username;
    private String password;
}
  • 配置bean标签,在property标签中使用el表达式,指定properties文件的相应的key
xml
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.moon.spring"/>
<!-- 配置读取配置文件 -->
<bean class="com.moon.spring.bean.PropertyBean" id="propertyBean">
    <!--
        通过property标签可以给属性注入相应的值,
        但此时将value部分设置为占位符${},实现读取properties文件指定的key,有两种解决方案:

        第1种:使用传统的xml配置文件方式,设置context:property-placeholder标签(也可以自定义),指定要读取的配置文件
        第2种:xml文件的解析是将每个bean标签封装在一个BeanDefinition对象,可以通过实现 BeanDefinitionRegistryPostProcessor 接口
              在spring容器启动的过程中,修改 BeanDefinition 的 MutablePropertyValues 属性即可
    -->
    <property name="name" value="${moon.name}"/>
    <property name="password" value="${moon.password}"/>
</bean>
properties
moon.name=MooNkirA
moon.password=123456

传统xml配置读取properties配置文件

  • xml设置读取配置文件方式1,直接配置<context:property-placeholder>标签即可
xml
<context:property-placeholder location="classpath:application.properties"/>
  • xml设置读取配置文件方式2-1:直接配置实例化spring提供的配置参数解析类
xml
<!--
    xml设置读取配置文件方式2-1:配置实例PropertySourcesPlaceholderConfigurer 或者 PropertyPlaceholderConfigurer(已过时)
-->
<bean id="propertyConfigurerForProject"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="order" value="1"/>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
    <property name="location">
        <value>classpath:application.properties</value>
    </property>
</bean>

<!-- 或者创建PropertySourcesPlaceholderConfigurer -->
<bean id="propertySourcesPlaceholderConfigurer"
      class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="order" value="1"/>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
    <property name="location">
        <value>classpath:application.properties</value>
    </property>
</bean>
  • xml设置读取配置文件方式2-2,也可以配置一个自定义配置文件处理类,继承spring框架的PropertySourcesPlaceholderConfigurer类或者~~PropertyPlaceholderConfigurer类~~(此类已过时,在spring 5.2版本后,使用前面那个类),通过locations属性指定需要读取的配置文件位置即可
java
<!--
    xml设置读取配置文件方式2:可以自定义properties文件处理类,该类继承spring框架的PropertySourcesPlaceholderConfigurer类或者PropertyPlaceholderConfigurer类(已过时),
    此方式应该与注解的@PropertySource的实现原理一样,通过locations属性指定需要读取的配置文件位置
-->
<bean class="com.moon.spring.config.PropertyConfiguration" id="propertyConfiguration">
    <property name="locations">
        <list>
            <!-- 可以指定多个配置文件 -->
            <value>classpath:application.properties</value>
        </list>
    </property>
</bean>
  • 测试
java
private final ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
/* 测试xml配置中的property占位符赋值 */
@Test
public void testPropertiesByXml() {
    PropertyBean bean = context.getBean("propertyBean", PropertyBean.class);
    System.out.println(bean.getUsername() + " :: " + bean.getPassword());
}

通过BeanDefinitionRegistryPostProcessorr接口修改BeanDefinition

  • 使用上面示例原始的xml配置文件(但不需要配置context:property-placeholder标签)与properties文件
  • 创建使用@Value注解占位符注入属性的测试类
java
@Component
@Data
public class PlaceholderBean {
    @Value("${moon.name}")
    private String name;
    @Value("${moon.password}")
    private String password;
}
  • 创建配置类,使用@PropertySource注解引入配置文件。
java
@Configuration
/*
 * @PropertySource注解用于引入配置文件,与xml的配置
 * <context:property-placeholder location="classpath:application.properties"/>
 * 作用一样,也可实现将注入属性值为占位符时替换成相应的值
 *
 * 注:但此注解在使用@Value(${xx.xx})的情况,能成功解析占位符并替换成配置文件中的值
 * xml配置<property name="abc" value="${xx.xx}"/> 却无法解析占位符
 */
@PropertySource("classpath:application.properties")
public class SpringConfiguration {
}
  • 创建PropertyBeanDefinitionRegistryPostProcessor类,分别实现BeanDefinitionRegistryPostProcessorEnvironmentAware接口,前者是可以获取到BeanDefinitionRegistry注册中心,后者是为了获取到Environment环境对象。由此可以通过Environment对象获取可以配置文件的值,然后将值设置到相应的BeanDefinition中的MutablePropertyValues属性即可
java
@Component
public class PropertyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {

    // 注入spring的环境对象
    private Environment environment;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 通过BeanDefinitionRegistry注册中心获取指定的BeanDefinition(或者全部BeanDefinition,逐个循环处理)
        MutablePropertyValues propertyValues = registry.getBeanDefinition("propertiesXmlBean").getPropertyValues();
        // 循环所有属性
        for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {
            TypedStringValue typedStringValue = (TypedStringValue) propertyValue.getValue();
            if (typedStringValue != null) {
                // 获取xml配置中的值,值为${xxx.xxx},截取后为即为配置文件的key,通过环境对象获取相应的配置文件中的value
                String value = typedStringValue.getValue();
                Optional.ofNullable(value)
                        .ifPresent(v -> propertyValue.setConvertedValue(environment.getProperty(v.substring(2, v.length() - 1))));
            }
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // do nothing
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
  • 测试
java
private final ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
/* 测试xml配置中的property占位符赋值 */
@Test
public void testPropertiesByXml() {
    PropertyBean bean = context.getBean("propertyBean", PropertyBean.class);
    System.out.println(bean.getUsername() + " :: " + bean.getPassword());

    PlaceholderBean placeholderBean = context.getBean("placeholderBean", PlaceholderBean.class);
    System.out.println(placeholderBean.getName() + " :: " + placeholderBean.getPassword());
}

注:@PropertySource注解引入配置文件与xml配置中<context:property-placeholder>标签效果一样,也可以实现将注入属性值替换相应占位符的值,同时也会将properties或xml配置文件的值会注册到Environment对象中

但这次测试中发现问题是:如果@PropertySource注解引入配置文件只对使用@Value的占位符生效,对xml配置文件中的<property name="username" value="${moon.name}"/>的占位符是无效,注释BeanDefinitionRegistryPostProcessor接口实现修改部分,属性值直接就为占位符,此问题待日后详细研究源码后再分析原因

通过 ResourceLoaderAware 接口实现读取 properties 配置文件

  • 实现ResourceLoaderAware接口,通过setResourceLoader方法获取到资源加载对象ResourceLoader,通过该对象读取properties文件,手动设置到spring的占位符解析器PropertySourcesPlaceholderConfigurer
java
@Component
public class CustomResourceLoaderAware implements ResourceLoaderAware {

    private ResourceLoader resourceLoader;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    /* 通过@Bean注解,创建占位符解析器 */
    @Bean
    public PropertySourcesPlaceholderConfigurer getPropertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        // 通过ResourceLoader对象读取配置文件,并设置到PropertySourcesPlaceholderConfigurer占位符解析器的location属性
        propertySourcesPlaceholderConfigurer.setLocation(resourceLoader.getResource("application.properties"));
        return propertySourcesPlaceholderConfigurer;
    }

}

注意事项

注:如果都不配置以上的任何一种参数解析方案,xml则直接将占位符(el表达式)当成字符串赋值给相应的属性,结果如下:

${moon.name} :: ${moon.password}

PropertyPlaceholderBeanDefinitionParser 标签解析类

PropertyPlaceholderBeanDefinitionParser<context:property-placeholder>标签的解析类

查看spring-context包下的spring.handlers文件,找到相应的context自定义标签头的相应的解析类注册的处理类ContextNamespaceHandler

找到<property-placeholder>标签的解析类PropertyPlaceholderBeanDefinitionParser

getBeanClass方法中,返回相应的属性值占位符的解析类PropertySourcesPlaceholderConfigurer或者PropertyPlaceholderConfigurer旧版本,已过时

java
protected Class<?> getBeanClass(Element element) {
	// As of Spring 3.1, the default value of system-properties-mode has changed from
	// 'FALLBACK' to 'ENVIRONMENT'. This latter value indicates that resolution of
	// placeholders against system properties is a function of the Environment and
	// its current set of PropertySources.
	if (SYSTEM_PROPERTIES_MODE_DEFAULT.equals(element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE))) {
		// 属性值占位符解析器
		return PropertySourcesPlaceholderConfigurer.class;
	}

	// The user has explicitly specified a value for system-properties-mode: revert to
	// PropertyPlaceholderConfigurer to ensure backward compatibility with 3.0 and earlier.
	// This is deprecated; to be removed along with PropertyPlaceholderConfigurer itself.
	// 5.2版本以前的属性值占位符解析器(已过时)
	return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class;
}

PropertySourcesPlaceholderConfigurer 占位符解析器

从源码的继承关系可知,PropertySourcesPlaceholderConfigurer类不仅实现了BeanFactoryPostProcessor接口、还实现了EnvironmentAwareBeanNameAwareBeanFactoryAware等接口

  • 新版本参数占位符赋值处理都是调用此方法执行,此方法会将Environment对象与本地配置文件属性与值包装成PropertySource对象,然后加入到MutablePropertySources类的list集合中,然后处理占位符赋值的逻辑
java
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	if (this.propertySources == null) {
		this.propertySources = new MutablePropertySources();
		if (this.environment != null) {
			// 把environment对象封装成PropertySource对象后,加到MutablePropertySources中的list中
			this.propertySources.addLast(
				// 把environment对象封装成的PropertySource对象
				new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
					@Override
					@Nullable
					public String getProperty(String key) {
						// source就是PropertySource类的泛型T,即environment对象
						return this.source.getProperty(key);
					}
				}
			);
		}
		try {
			// 加载本地配置文件中的属性值,并包装成properties对象后,最终包装成PropertySource对象
			PropertySource<?> localPropertySource =
					new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
			// 加入到MutablePropertySources中的list中,根据localOverride标识决定排序
			if (this.localOverride) {
				this.propertySources.addFirst(localPropertySource);
			}
			else {
				this.propertySources.addLast(localPropertySource);
			}
		}
		catch (IOException ex) {
			throw new BeanInitializationException("Could not load properties", ex);
		}
	}
	// 处理占位符赋值的主要逻辑
	processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
	this.appliedPropertySources = this.propertySources;
}
  • 其中mergeProperties方法是读取本地配置文件(如.properties)的属性与值

  • doProcessProperties方法处理将属性的占位符${xxx}替换成真正的值
java
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
		final ConfigurablePropertyResolver propertyResolver) throws BeansException {

	// 设置占位符的前缀后缀
	propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);
	propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);
	// 设分割符“:”
	propertyResolver.setValueSeparator(this.valueSeparator);

	// @Value注解的依赖注入会调到此匿名对象,重要程度【4】
	StringValueResolver valueResolver = strVal -> {
		String resolved = (this.ignoreUnresolvablePlaceholders ?
				propertyResolver.resolvePlaceholders(strVal) :
				propertyResolver.resolveRequiredPlaceholders(strVal));
		if (this.trimValues) {
			resolved = resolved.trim();
		}
		return (resolved.equals(this.nullValue) ? null : resolved);
	};
	// 核心流程。把占位符${xxx}替换成真正的值
	doProcessProperties(beanFactoryToProcess, valueResolver);
}
java
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
		StringValueResolver valueResolver) {

	// 创建BeanDefinition的修改者
	BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

	// 获取所有的beanNames
	String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
	for (String curName : beanNames) {
		// Check that we're not parsing our own bean definition,
		// to avoid failing on unresolvable placeholders in properties file locations.
		if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
			// 获取BeanDefinition对象
			BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
			try {
				// 修改BeanDefinition中的MutablePropertyValues中的每一个属性值,把属性值有${xxx.xxx}修改成真正的参数值
				visitor.visitBeanDefinition(bd);
			}
			catch (Exception ex) {
				throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
			}
		}
	}

	// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
	beanFactoryToProcess.resolveAliases(valueResolver);
	// 把内嵌的Value解析器设置到BeanFactory中,为@Value的依赖注入做准备
	// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
	beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}

注:方法的最后一行代码beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);,会将刚刚外面的调用方法的传入的lambda表达式创建的匿名内部类保存到embeddedValueResolvers的容器中

  • 其中visitor.visitBeanDefinition(bd);方法是处理占位符替换成真正的属性值的核心方法

调用resolveStringValue方法解析

注:以上的this.valueResolver.resolveStringValue(strVal);方法调用,调用PropertySourcesPlaceholderConfigurer#processProperties方法中的lambda表达式匿名内部类

java
String resolved = (this.ignoreUnresolvablePlaceholders ?
        propertyResolver.resolvePlaceholders(strVal) :
        propertyResolver.resolveRequiredPlaceholders(strVal));
  • AbstractPropertyResolver#resolveRequiredPlaceholders方法
java
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
	if (this.strictHelper == null) {
		this.strictHelper = createPlaceholderHelper(false);
	}
	return doResolvePlaceholders(text, this.strictHelper);
}
java
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
	return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}
java
@Override
@Nullable
protected String getPropertyAsRawString(String key) {
	return getProperty(key, String.class, false);
}

@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
	// 其实就是从MutablePropertySources中的list中获取每一个PropertySource对象然后调用getProperty方法
	if (this.propertySources != null) {
		for (PropertySource<?> propertySource : this.propertySources) {
			if (logger.isTraceEnabled()) {
				logger.trace("Searching for key '" + key + "' in PropertySource '" +
						propertySource.getName() + "'");
			}
			// 调用getProperty方法,属性值的来源分别是Environment对象和本地配置文件
			Object value = propertySource.getProperty(key);
			if (value != null) {
				if (resolveNestedPlaceholders && value instanceof String) {
					value = resolveNestedPlaceholders((String) value);
				}
				logKeyFound(key, propertySource, value);
				// 参数转换
				return convertValueIfNecessary(value, targetValueType);
			}
		}
	}
	if (logger.isTraceEnabled()) {
		logger.trace("Could not find key '" + key + "' in any property source");
	}
	return null;
}
  • doResolvePlaceholders方法中,调用helper.replacePlaceholders(text, this::getPropertyAsRawString);,最终会

PropertySourcesPlaceholderConfigurer 与 PropertyPlaceholderConfigurer 的区别

Spring在5.2版本以后,使用PropertySourcesPlaceholderConfigurer类做为属性值占位符的解析器,而PropertyPlaceholderConfigurer是以前版本的占位符解析器。

java
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
    ....
}

@Deprecated
public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport {
    ....
}

它们的区别在于,PropertyPlaceholderConfigurer类解析属性值占位符时获取值的渠道,只通过读取配置文件(如:properties文件);

从源码可以看到,PropertySourcesPlaceholderConfigurer类实现EnvironmentAware接口,该类解析属性值占位符时获取值的渠道,不只通过读取配置文件(如:properties文件),还通过Environment对象去获取。

因为PropertySourcesPlaceholderConfigurer类重写了postProcessBeanFactory方法,而PropertyPlaceholderConfigurer类没有重写该方法,是直接调用抽象父类PlaceholderConfigurerSupportpostProcessBeanFactory方法

java
/* 5.2以前的版本的 PropertyPlaceholderConfigurer 占位符赋值的处理是调用抽象父类 PropertyResourceConfigurer 的方法 */
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	try {
		Properties mergedProps = mergeProperties();

		// Convert the merged properties, if necessary.
		convertProperties(mergedProps);

		// Let the subclass process the properties.
		processProperties(beanFactory, mergedProps);
	}
	catch (IOException ex) {
		throw new BeanInitializationException("Could not load properties", ex);
	}
}

占位符设置BeanClass属性示例

通过源码分析,其他的属性都可以设置为占位符,在下图的位置可以进行占位符的替换操作。如BeanClass属性,与处理类属性值一样,同样会调用resolveStringValue方法处理占位符

利用Spring这个功能,可以通过配置文件与占位符来创建Bean实例

配置文件

修改properties文件,设置占位符与待创建实例的类全限定名

properties
# 定义beanClass的占位符
moon.beanClass=${moon.placeHolderBean1},${moon.placeHolderBean2},${moon.placeHolderBean3}
# 定义占位符相应的beanClass的值
moon.placeHolderBean1=com.moon.spring.bean.Bird
moon.placeHolderBean2=com.moon.spring.bean.Cat
moon.placeHolderBean3=com.moon.spring.bean.Fish

创建配置类

在配置类中设置包扫描与手动创建PropertySourcesPlaceholderConfigurer占位符解析器

java
@Configuration
@ComponentScan("com.moon.spring")
public class SpringConfiguration {
    /* 通过@Bean注解,创建占位符解析器 */
    @Bean
    public PropertySourcesPlaceholderConfigurer getPropertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        // 读取本地配置文件,设置占位符解析器location属性
        ClassPathResource resource = new ClassPathResource("application.properties");
        propertySourcesPlaceholderConfigurer.setLocation(resource);
        return propertySourcesPlaceholderConfigurer;
    }
}

通过BeanDefinitionRegistry注册中心设置BeanClass占位符

创建BeanDefinitionRegistryPostProcessor接口的实现类,在postProcessBeanDefinitionRegistry方法注册beanClass属性为占位符的 BeanDefinition。

java
@Component
public class BeanClassDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        try {
            // 使用工具类读取properties文件
            Properties properties = PropertiesLoaderUtils.loadAllProperties("application.properties", ClassUtils.getDefaultClassLoader());
            // 读取所有占位符
            String beanClassProperty = properties.getProperty("moon.beanClass");
            for (String beanClass : beanClassProperty.split(",")) {
                // 创建BeanDefinition对象
                BeanDefinition beanDefinition = new GenericBeanDefinition();
                // 设置占位符的beanClass
                beanDefinition.setBeanClassName(beanClass);
                // 注册BeanDefinition
                String beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, registry);
                registry.registerBeanDefinition(beanName, beanDefinition);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // do nothing
    }
}

测试

java
private final ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);

@Test
public void testBeanClassByPlaceHolder() {
    Cat cat = context.getBean(Cat.class);
    System.out.println(cat);
    Bird bird = context.getBean(Bird.class);
    System.out.println(bird);
    Fish fish = context.getBean(Fish.class);
    System.out.println(fish);
}

Spring 配置文件解析总结

Spring 在属性值(或者一些其他 BeanDefinition 属性,如 BeanClass)是可以使用占位符(如${xx.xx}),此时需要配合 Spring 提供的 PropertySourcesPlaceholderConfigurer 类来对占位符解析成相应 Environment 对象或者本地配置文件中的值。如果不配置此类,则会将占位符字符串直接注入属性中。

通过 xml 配置或者 @Bean 注解将 PropertySourcesPlaceholderConfigurer 类注册到 spring 容器中,会占位符解析方法存入到 AbstractBeanFactory 类的 List<StringValueResolver> embeddedValueResolvers 容器中,在实例创建的过程依赖注入 populateBean 的方法,会使用占位符解析方法进行解析,从而获取到占位符相应的值。

配置项解析流程图

@Lazy 注解标识构造函数不会出现循环依赖的问题

在构造函数中循环依赖会报错的根本原因是:在相互依赖的构造函数中,会多次触发getBean操作,然而在调用有参构造函数时,不会提前将实例放到三级缓存中,然后在第二次触发getBean操作时,缓存不存在实例,所以就会创建实例。此时singletonsCurrentlyInCreation容器已存在当前创建的beanName,就会报出异常

从源码分析中可知,如果将@Lazy标识在有循环依赖的构造函数上,不直接调用参数为引入类型的beanBean操作,而返回一个代理对象,因为多次触发getBean操作,所以不会出现循环依赖报错的异常

CGlib 动态代理库

CGlib 简介

CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。CGLIB作为一个开源项目,其代码托管在github,地址为:https://github.com/cglib/cglib

CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。

CGlib基础使用示例

  • 引入cglib依赖
xml
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
  • 准备被代理类
java
public interface GoodsService {

    String queryGoods(String param);

    String addGoods(String param);

    String editGoods(String param);

    String deleteGoods(String param);

    String fixedValue(String param);

}

/**
 * 被代理类,CGlib与jdk动态不同,代理与被代理不需要实现同一接口
 */
public class GoodsServiceImpl implements GoodsService {

    @Override
    public String queryGoods(String param) {
        System.out.println("=== queryGoods ===");
        return "queryGoods";
    }

    @Override
    public String addGoods(String param) {
        System.out.println("=== addGoods ===");
        return "addGoods";
    }

    @Override
    public String editGoods(String param) {
        System.out.println("=== editGoods ===");
        return "editGoods";
    }

    @Override
    public String deleteGoods(String param) {
        System.out.println("=== deleteGoods ===");
        return "deleteGoods";
    }

    @Override
    public String fixedValue(String param) {
        System.out.println("=== fixedValue ===");
        return "fixedValue";
    }
}
  • 创建FixedValue接口实现,其loadObject方法,是用于完全替代被代理类调用的方法
java
public class FixedValueIntercepter implements FixedValue {

    @Override
    public Object loadObject() throws Exception {
        System.out.println("FixedValueIntercepter.loadObject()方法执行了....");
        return "loadObject value";
    }

}
  • 创建 CallbackFilter 接口实现类,重写accept方法,方法返回值相应Callback数组的下标时,就会调用相应数组中相应下标的Callback
java
public class CglibCallbackFilter implements CallbackFilter {
    private final List<String> methodList = Arrays.asList("addGoods", "editGoods", "queryGoods", "deleteGoods");

    @Override
    public int accept(Method method) {
        String methodName = method.getName();
        // 获取方法名相应的下标
        int i = methodList.indexOf(methodName);
        return i < 0 ? 4 : i;
    }
}
  • 创建获取代理的工厂类CglibBeanFactory
java
public class CglibBeanFactory {

    public static Object getInstance() {
        // 创建增强器
        Enhancer enhancer = new Enhancer();
        // 设置被代理类(注意:是子类,非接口),会生成字节码文件并加载到jvm中
        enhancer.setSuperclass(GoodsServiceImpl.class);
        /*
         * 创建CallbackFilter对象,实现接口accept方法,在方法中指定调用相应的callback方法
         * 此方法的返回值是int整数,对于Callbacks数组中的下标
         */
        CallbackFilter callbackFilter = new CglibCallbackFilter();
        enhancer.setCallbackFilter(callbackFilter);

        // 创建几个Callback
        Callback callback1 = new GoodsServiceInterceptor1();
        Callback callback2 = new GoodsServiceInterceptor2();
        Callback callback3 = new GoodsServiceInterceptor3();
        // 这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。
        Callback noop = NoOp.INSTANCE;
        // 此FixedValue接口实现,会直接替代被代理类调用的方法
        Callback fixdValueCallback = new FixedValueIntercepter();

        // 设置Callback回调数组(在CallbackFilter的accept方法返回值,相应此数组的下标,即会调用相应的Callback)
        Callback[] callbacks = {callback1, callback2, callback3, noop, fixdValueCallback};
        enhancer.setCallbacks(callbacks);
        // 创建代理
        return enhancer.create();
    }

    private static class GoodsServiceInterceptor1 implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            // 前置增强
            System.out.println(String.format("Interceptor1 执行 %s 前....", method.getName()));
            // 调用被代理的方法
            Object o = proxy.invokeSuper(obj, args);
            // 后置增强
            System.out.println(String.format("Interceptor1 执行 %s 后....", method.getName()));
            return o;
        }
    }

    private static class GoodsServiceInterceptor2 implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println(String.format("Interceptor2 执行 %s 前....", method.getName()));
            Object o = proxy.invokeSuper(obj, args);
            System.out.println(String.format("Interceptor2 执行 %s 后....", method.getName()));
            return o;
        }
    }

    private static class GoodsServiceInterceptor3 implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println(String.format("Interceptor3 执行 %s 前....", method.getName()));
            Object o = proxy.invokeSuper(obj, args);
            System.out.println(String.format("Interceptor3 执行 %s 后....", method.getName()));
            return o;
        }
    }
}
  • 测试结果
java
@Test
public void testCglibBasic() {
    // 获取代理
    GoodsService goodsService = (GoodsService) CglibBeanFactory.getInstance();
    // 调用相应的方法
    System.out.println(goodsService.queryGoods("MooN"));
    System.out.println(goodsService.addGoods("iPhone18"));
    System.out.println(goodsService.editGoods("战神游戏本"));
    System.out.println(goodsService.deleteGoods("机械键盘"));
    System.out.println(goodsService.fixedValue("kirA"));
}

自定义增强型依赖注入注解案例(整理中!)

案例需求

此案例的需求是:

  1. 使 @Autowired@Resource 注解可以一次性注入一个接口所有的实现类
  2. 希望能通过注解的方式,可以一次性调用接口中方法对应的所有实现,如果能实现跟dubbo里面的那个ExtensionLoader 这个里面的功能那就更好了,可以批量找实现类,也可以单个找实现类,可以优先匹配某个实现类。

根据源码分析,整理实现此需求的思路如下:

  • @Autowired注解的收集源码位置是在AbstractAutowireCapableBeanFactory.doCreateBean方法的applyMergedBeanDefinitionPostProcessors

  • Spring实现@Autowired注解的收集是通过一个MergedBeanDefinitionPostProcessor接口类型的AutowiredAnnotationBeanPostProcessor类来完成的
  • Spring的真正的依赖注入源码位置是在AbstractAutowireCapableBeanFactory.doCreateBean方法的populateBean
  • Spring实现@Autowired依赖注入是通过一个InstantiationAwareBeanPostProcessor接口类型的AutowiredAnnotationBeanPostProcessor类来完成的

  • 所以可以参考AutowiredAnnotationBeanPostProcessor类来实现此案例的功能

功能实现

I know where dry desert ends, green grass grows · MooN