• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

3.spring生命周期详解

开发技术 开发技术 3小时前 3次浏览

目录
  • 前言:
  • Bean生命周期流程图:
  • Bean生命周期
    • 1.生成BeanDefinition
      • 1.1生成beanDefinition的方式:
      • 1.2通过扫描包路径获取beanDefinition
        • 1.2.1ClassPathBeanDefinitionScanner类
          • 1.2.1.1 ClassPathBeanDefinitionScanner的构造函数
          • 1.2.1.2 ClassPathBeanDefinitionScanner#scan
          • 1.2.1.3 ClassPathBeanDefinitionScanne#doScan
        • 1.2.2 ClassPathScanningCandidateComponentProvider类
          • 1.2.2.1ClassPathBeanDefinitionScanner#findCandidateComponents
          • 1.2.2.2ClassPathScanningCandidateComponentProvider#scanCandidateComponents
          • 生成beandefinition详细步骤如下:
          • 首先,通过ResourcePatternResolver获得指定包路径下的所有.class文件(Spring源码中将此文件包装成了Resource对象)
          • Spring方法注入 @Lookup注解使用
          • 1.2.2.3判断一个resource能否通过scaner扫描一个beandefinition: ClassPathScanningCandidateComponentProvider#isCandidateComponent
          • 1.2.2.4ClassPathScanningCandidateComponentProvider#registerDefaultFilters方法
          • 1.2.2.5AnnotationTypeFilter类继承关系
        • 1.2.2.6AbstractTypeHierarchyTraversingFilter类
        • 1.2.3AnnotationTypeFilter类
          • 1.2.3.1AnnotationTypeFilter构造方式
          • 1.2.3.2matchSelf()方法
        • 1.2.4ConditionEvaluator类
          • 1.2.4.1ConditionEvaluator.shouldSkip(AnnotatedTypeMetadata, ConfigurationPhase),
        • 回到1.2.1.3 ClassPathBeanDefinitionScanne#doScan
      • 1.3spring为beanDefintion设置beanName属性。
        • 1.3.1AnnotationBeanNameGenerator#generateBeanName
      • 1.4 为beanDefinition设置默认值
        • 1.4.1AbstractBeanDefinition#applyDefaults
      • 1.5 处理Lazy、DependsOn、Role、Description等注解信息,并设置到abd中
        • 1.5.1AnnotationConfigUtils#processCommonDefinitionAnnotations
      • 1.6 检验beanFactroy中是否已经注册了相同beanName的beanDefinition,spring要处理这种情况
      • 1.7 spring索引生成beanDefinition —Spring 5 启动性能优化之 @Indexed
        • Spring5的spring.components扩展点
          • 1.7.1Indexed 注解的定义:
          • 1.7.2META-INF/spring.components 如何生成?
          • 1.7.4哪些资源会被索引
          • 1.7.5spring索引如何生成
            • spring.properties
          • 1.7.6索引的使用
          • 1.7.7extractStereotype提取过滤类型
          • 1.7.8getCandidateTypes返回满足条件的bean类型
          • 1.7.9spring.components文件的格式以及加载格式
        • Spring5的spring.components扩展点案例
      • 1.8registerAnnotationConfigProcessors注册注解配置处理器
    • 2.合并beanDefinition
      • 继承的BeanDefinition
        • 在走到合并beanDefinition方法之前:
        • 走过合并方法后 :
        • 源码:是怎么样获得RootBeanDefinition
          • DefaultListableBeanFactory#preInstantiateSingletons()方法 // 实例化所有非懒加载的bean
          • AbstractBeanFactory#getMergedLocalBeanDefinition()方法
          • AbstractBeanFactory#getMergedBeanDefinition()方法
          • AbstractBeanFactory#transformedBeanName()方法
          • BeanFactoryUtils类的域
          • BeanFactoryUtils#transformedBeanName方法
          • 回到这个AbstractBeanFactory#transformedBeanName()方法
          • 回到DefaultListableBeanFactory#preInstantiateSingletons()方法 // 实例化所有非懒加载的bean
      • getMergedLocalBeanDefinition合并bean意义
      • 什么时候需要设置合并呢
        • 在AbstractBeanFactory的markBeanAsCreated,而且这里注释说了,让他重新合并一下。
        • 另外一个地方是invokeBeanFactoryPostProcessors的最后:
    • 3.FactoryBean实战例子
      • 1.关于spring的FactoryBean的问题:
      • 问题1:getBean的时候,为什么get的对象对象都是同一个对象呢?
      • 问题2:那么在执行LubanFactoryBean实例的getObject()的时候是在哪一行代码呢
      • 问题3:为什么往单例池放数据的时候是LubanFactoryBean,在getBean的时候却是User呢?
        • DefaultListableBeanFactory#preInstantiateSingletons()
        • AbstractBeanFactory#getBean()
        • AbstractBeanFactory#doGetBean()
        • AbstractBeanFactory#getObjectFromFactoryBean()
        • FactoryBeanRegistrySupport#getObjectFromFactoryBean()
          • FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
        • BeanFactoryUtils#isFactoryDereference()
      • 问题4:FactoryBean用在哪儿呢?
  • 参考
    • Spring 注解
    • Spring 5 启动性能优化之 @Indexed
    • GetBean源码全面解读

前言:

Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。

Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的

Bean生命周期流程图:

Bean生命周期

1.生成BeanDefinition

1.1生成beanDefinition的方式:

  1. 硬编码直接定义BeanDefinition,然后注册到bean工厂中
  2. 通过扫描包路径获取beanDefinition
  3. 通过@Bean注解获取beanDefinition (附上link)
  4. 解析spring.xml文件的<bean/>,生成beanDefinition

1.2通过扫描包路径获取beanDefinition

spring启动主要负责的工作是:

  1. 扫描包路径生成beanDefinition
  2. 创建非懒加载的单例bean

从下图(spring的启动过程图)中我们可以清楚的看到 –在解析AppConfig配置类的时候,会扫描配置类中配置的包路径。 后面会专门的介绍

spring的启动过程

3.spring生命周期详解

所以我们还是先着重介绍通过·扫描包路径获取BeanDefinition`的方式,即 bean的生命周期从扫描包路径开始。

Spring启动的时候会进行扫描,会使用ClassPathBeanDefinitionScanner类进行扫描

Spring扫描底层流程:

这里先讲一下Spring扫描的底层实现:https://www.processon.com/view/link/61370ee60e3e7412ecd95d43

3.spring生命周期详解

  1. 首先,通过ResourcePatternResolver获得指定包路径下的所有.class文件(Spring源码中将此文件包装成了Resource对象)
  • String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX resolveBasePackage(basePackage) + ‘/’ + this.resourcePattern;
    • 将package转化为ClassLoader类资源搜索路径packageSearchPath,例如:com.wl.spring.boot转化为classpath:com/wl/spring/boot/**/.class
  1. 遍历每个Resource对象

  2. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,MetadataReader的具体实现类为SimpleMetadataReader)

    • MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

    • 关于MetadataReaderFactory、MetadataReader 可以查看【源码】Spring —— ClassMetadata AnnotatedTypeMetadata 解读

  3. isCandidateComponent(metadataReader)判断一个resource 是不是能够生成 beandefinition 注册到beanFactory中 :

if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
 }  //这个后面会讲。。。。。
- **利用MetadataReader进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选**(**条件注解并不难理解:某个类上是否存在@Conditional注解,如果存在则调用注解中所指定的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)**
  1. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition

  2. 再基于metadataReader判断是不是对应的类是不是接口或抽象类

下面会仔细的扣流程,每个流程涉及到的代码都会大致的描述一下

1.2.1ClassPathBeanDefinitionScanner类

ClassPathBeanDefinitionScanner的主要作用有两个:

  1. 扫描类路径下的候选Component,构造BeanDefinition对象(实际为ScannedGenericBeanDefinition)
  2. 利用BeanDefinitionRegister注册BeanDefinition到bean工厂中;

类图

3.spring生命周期详解

通过ClassPathScanningCandidateComponentProvider(true)的构造器,就可以扫描出任何我们添加了@Component annotation的类,它是怎么做到的呢? 我们来看一下这个构造方法都做了什么:???

1.2.1.1 ClassPathBeanDefinitionScanner的构造函数

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
	

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
		this(registry, true); // 1.委托给内部的另一个构造方法

	}

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
		this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
	}

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment) {

		this(registry, useDefaultFilters, environment,
				(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
	}
	/**
	 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
	 * using the given {@link Environment} when evaluating bean definition profile metadata.
	 * @param registry the {@code BeanFactory} to load bean definitions into, in the form
	 * of a {@code BeanDefinitionRegistry}
	 * @param useDefaultFilters whether to include the default filters for the
	 * {@link org.springframework.stereotype.Component @Component},
	 * {@link org.springframework.stereotype.Repository @Repository},
	 * {@link org.springframework.stereotype.Service @Service}, and
	 * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
	 * @param environment the Spring {@link Environment} to use when evaluating bean
	 * definition profile metadata
	 * @param resourceLoader the {@link ResourceLoader} to use
	 * @since 4.3.6
	 */
	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		this.registry = registry; 
	// 添加includeFilters,Spring扫描的时候需要利用includeFilters,Spring扫描到某个类时如果能通过includeFilters的验证就证明这个类是一个Bean
		// 默认注册一个@Component注解对应的Filter
		if (useDefaultFilters) {   
			registerDefaultFilters();
		}
		setEnvironment(environment);
		setResourceLoader(resourceLoader);
	}
    // 省略
}   

我们仔细看一下注释

@param registry the {@code BeanFactory} to load bean definitions into, in the form of a {@code BeanDefinitionRegistry}

@param useDefaultFilters whether to include the default filters for the

  • {@link org.springframework.stereotype.Component @Component},
  • {@link org.springframework.stereotype.Repository @Repository},
  • {@link org.springframework.stereotype.Service @Service}, and
  • {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
if (useDefaultFilters) {   
	registerDefaultFilters();
}

useDefaultFilters默认为true,所以会执行registerDefaultFilters();

  1. 从方法的注释上可以看到这句话,registry 其实就是容器本身,负责将beanDefinition注册到BeanFactory中

  2. registerDefaultFilters();是父类ClassPathScanningCandidateComponentProvider的方法

  3. @Component,@Repository,@Service @Controller注解是如何被解析的

    这个问题我们去父类ClassPathScanningCandidateComponentProvider的registerDefaultFilters()中寻找答案

1.2.1.2 ClassPathBeanDefinitionScanner#scan
	/**
	 * Perform a scan within the specified base packages.
	 * @param basePackages the packages to check for annotated classes
	 * @return number of beans registered
	 */
	public int scan(String... basePackages) {
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

		doScan(basePackages);// (1) 执行扫描包路径生成bean定义的核心代码

		// Register annotation config processors, if necessary.
		// 注册几个BeanPostProcessor用来解析@Autowired、@Reource等几个注解
		if (this.includeAnnotationConfig) {
			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}

		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
	}
1.2.1.3 ClassPathBeanDefinitionScanne#doScan

ClassPathBeanDefinitionScanner#doScan是扫描BeanDefinition并注册的实现

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		// 这是Spring中的Assert,大家开发时也可以用
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			// 扫描包路径得到BeanDefinition,得到的BeanDefinition是空的,还没有解析类上所定义的注解信息
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//(1)
			for (BeanDefinition candidate : candidates) {
				// 得到Scope的信息,并设置
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				// 得到beanName
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

				if (candidate instanceof AbstractBeanDefinition) {
					// 根据beanDefinitionDefaults设置一些默认值
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				// 如果是注解定义的Bean, findCandidateComponents默认实现返回的BeanDefinition
				// 是一个ScannedGenericBeanDefinition,其实现了AnnotatedBeanDefinition接口
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 旧bean不是扫描出来的,当前扫描出来的新bean不会注册到bean工厂
				if (checkCandidate(beanName, candidate)) {
					// 生成BeanDefinitionHolder并注册到registry中
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder = // 设置代理策略
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					// 注册到Spring容器中
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

(1) 调用父类ClassPathScanningCandidateComponentProvider 的 findCandidateComponents 方法

1.2.2 ClassPathScanningCandidateComponentProvider类

域信息:

private String resourcePattern = DEFAULT_RESOURCE_PATTERN;

private final List<TypeFilter> includeFilters = new LinkedList<>();

private final List<TypeFilter> excludeFilters = new LinkedList<>();

@Nullable
private Environment environment;

@Nullable
private ConditionEvaluator conditionEvaluator;

@Nullable
private ResourcePatternResolver resourcePatternResolver;

@Nullable
private MetadataReaderFactory metadataReaderFactory;

@Nullable
private CandidateComponentsIndex componentsIndex;
1.2.2.1ClassPathBeanDefinitionScanner#findCandidateComponents
	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		// 扫描Component,最笨的方法就是使用类加载器将类加载到jvm中,然后for循环basePackage下的所有类,通过类反射的机制看是否有@Component注解 即用反射机制获取一个类的注解  spring虽然使用是asm技术获取.class 文件上的@component注解 但是这个方法也不是最优 。。
        // spring 5 之后多出了一个性能优化的技术 就是使用spring索引
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) { //使用spring索引
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		}
		else {
			return scanCandidateComponents(basePackage);
		}
	}
1.2.2.2ClassPathScanningCandidateComponentProvider#scanCandidateComponents

会先调用org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)扫描某个包路径,并得到BeanDefinition的Set集合。

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		// 扫描类,得到BeanDefinition
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 原文链接:https://blog.csdn.net/floor2011/article/details/106968194/
			//basePackage="com.lunban" 转换成packageSearchPath ="classpath*:com/luban/**/*.class";
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 加载搜素路径下的资源
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
						// MetadataReader包含了对应class的元信息以及注解元信息, MetadataReader
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						// 判断一个类是不是Component
						if (isCandidateComponent(metadataReader)) {
							// 通过扫描@Component得到的BeanDefinition为ScannedGenericBeanDefinition
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							// 再进一步验证是不是备选的Component
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

上述代码中,从resource获取到了MetadataReader,它相当于是class文件解析后的信息。

MetadataReader对象有三个功能:

  • 获取对应resource资源

  • 获取resource对应的class的元数据信息,包括名称、是否是注解、是否抽象等,具体可以查看类ClassMetadata的接口;

  • 获取resource对应的class上的注解信息,如当前类上有的注解,被注解标注的方法等;

这里生成的ScannedGenericBeanDefinition中有一属性beanClass,在这里存的是字符串,就是类全名,spring中使用ASM技术解析class文件,会得到class的所有信息,但不会加载类,所有在这里的beanClass保存了类名,beanClass的类型为Object,是因为,它可以存储不止字符串一种类型,也可以存储class类型,在用到这个类时才会加载,那么就会存class对象。spring源码篇(三)bean的生命周期

生成beandefinition详细步骤如下:
  1. 首先,通过ResourcePatternResolver获得指定包路径下的所有.class文件(Spring源码中将此文件包装成了Resource对象)
    • String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX resolveBasePackage(basePackage) + ‘/’ + this.resourcePattern;
    • 将package转化为ClassLoader类资源搜索路径packageSearchPath,例如:com.wl.spring.boot转化为classpath:com/wl/spring/boot/**/.class
  2. 遍历每个Resource对象

  3. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,MetadataReader的具体实现类为SimpleMetadataReader)

    • MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

    • 关于MetadataReaderFactory、MetadataReader 可以查看【源码】Spring —— ClassMetadata AnnotatedTypeMetadata 解读

  4. isCandidateComponent(metadataReader)判断一个resource 是不是能够生成 beandefinition 注册到beanFactory中 :

    if (tf.match(metadataReader, getMetadataReaderFactory())) {
    				return isConditionMatch(metadataReader);
     }  //这个后面会讲。。。。。
    
    • 利用MetadataReader进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选条件注解并不难理解:某个类上是否存在@Conditional注解,如果存在则调用注解中所指定的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)
  5. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition

  6. 再基于metadataReader判断是不是对应的类是不是接口或抽象类

    	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    		AnnotationMetadata metadata = beanDefinition.getMetadata();
    		// 不是接口或抽象类,如果是抽象类那么抽象类上得是Lookup注解
    		return (metadata.isIndependent() && (metadata.isConcrete() ||
    				(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
    	}
    
    • metadata.isIndependent()

    • AnnotationMetadata继承ClassMetadata,boolean isIndependent(); // 判断是否“独立”,TopLevelClass 或者 NestedClass 一般都是顶层类或者静态内部类

    • 详细解释 【源码】Spring —— ClassMetadata AnnotatedTypeMetadata 解读

      这个是什么意思呢? 传送条:

    【spring源码之Lookup注解的简单应用】

    Spring方法注入 @Lookup注解使用
  7. 如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition

    (得到的BeanDefinitions的很多属性只有默认值的,因为还没有解析类上所定义的注解信息,为BeanDefinitions设置属性值)加入结果集

关于@Conditional 注解的用法 : https://blog.csdn.net/xcy1193068639/article/details/81491071

1.2.2.3判断一个resource能否通过scaner扫描一个beandefinition: ClassPathScanningCandidateComponentProvider#isCandidateComponent
/**
	 * Determine whether the given class does not match any exclude filter
	 * and does match at least one include filter.
	 * @param metadataReader the **ASM ClassReader for the class**
	 * @return whether the class qualifies as a candidate component
	 */
	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		// 不匹配
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}

		// 匹配,只有通过了includeFilters的验证才算是一个备选的Component
		// includeFilters在前面生成ClassPathBeanDefinitionScanner的构造方法中用registerDefaultFilters()设置初始值,有@Component
		// AbstractTypeHierarchyTraversingFilter#match
		for (TypeFilter tf : this.includeFilters) { //(1)
			if (tf.match(metadataReader, getMetadataReaderFactory())) {  //(2)
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

代码段(1) 的解释:

我们回到1.2.1.1 查看ClassPathBeanDefinitionScanner的构造函数, 设置了一个默认的过滤器针对@component注解

1.2.2.4ClassPathScanningCandidateComponentProvider#registerDefaultFilters方法
protected void registerDefaultFilters() {
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); 
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
			logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) { 
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}
		try {
			this.includeFilters.add(new AnnotationTypeFilter(  
 					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
			logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) { 
			// JSR-330 API not available - simply skip.
		}
	}

首先这里的includeFilters大家熟悉吗,还有个excludeFilters,先看一下属性

private final List<TypeFilter> includeFilters = new LinkedList<>();
private final List<TypeFilter> excludeFilters = new LinkedList<>();

this.includeFilters.add(new AnnotationTypeFilter(Component.class));

这里我们看到includeFilters 集合中新增了一个AnnotationTypeFilter对象,AnnotationTypeFilter应该有一个带有匹配规则的方法。

(1)关于@ManagedBean@Named 注解,分别需要通过类加载器加载”javax.annotation.ManagedBean”、”javax.inject.Named”

类文件,而我们的工程没有相应的jar包,所以会走到捕获异常的地方。

否则(也就是说把这个方法走完),includeFilters里面只会有一个元素

3.spring生命周期详解

代码段(2) 的解释: tf.match(metadataReader, getMetadataReaderFactory())

执行AnnotationTypeFilter.match 会调用父类AbstractTypeHierarchyTraversingFilter的方法

1.2.2.5AnnotationTypeFilter类继承关系

3.spring生命周期详解

1.2.2.6AbstractTypeHierarchyTraversingFilter类

public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilter {

	protected final Log logger = LogFactory.getLog(getClass());

	private final boolean considerInherited;

	private final boolean considerInterfaces;


	protected AbstractTypeHierarchyTraversingFilter(boolean considerInherited, boolean considerInterfaces) {
		this.considerInherited = considerInherited;
		this.considerInterfaces = considerInterfaces;
	}


	@Override  // 主要关注的是该方法
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {

		// This method optimizes avoiding unnecessary creation of ClassReaders
		// as well as visiting over those readers.
		if (matchSelf(metadataReader)) { // (1)调用子类的matchSelf方法
			return true;
		}
		ClassMetadata metadata = metadataReader.getClassMetadata();
		if (matchClassName(metadata.getClassName())) {
			return true;
		}

		if (this.considerInherited) {
			String superClassName = metadata.getSuperClassName();
			if (superClassName != null) {
				// Optimization to avoid creating ClassReader for super class.
				Boolean superClassMatch = matchSuperClass(superClassName);
				if (superClassMatch != null) {
					if (superClassMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read super class to determine a match...
					try {
						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
									"] of type-filtered class [" + metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		if (this.considerInterfaces) {
			for (String ifc : metadata.getInterfaceNames()) {
				// Optimization to avoid creating ClassReader for super class
				Boolean interfaceMatch = matchInterface(ifc);
				if (interfaceMatch != null) {
					if (interfaceMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read interface to determine a match...
					try {
						if (match(ifc, metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
									metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		return false;
	}

	private boolean match(String className, MetadataReaderFactory metadataReaderFactory) throws IOException {
		return match(metadataReaderFactory.getMetadataReader(className), metadataReaderFactory);
	}

}

最终又会调用AnnotationTypeFilter类自己matchSelf 方法

1.2.3AnnotationTypeFilter类
1.2.3.1AnnotationTypeFilter构造方式
public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter {

/**
	 * Create a new {@code AnnotationTypeFilter} for the given annotation type.
	 * @param annotationType the annotation type to match
	 * @param considerMetaAnnotations whether to also match on meta-annotations
	 * @param considerInterfaces whether to also match interfaces
	 */
	public AnnotationTypeFilter(
			Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
        // 调用父类的构造方法
		super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces);
		this.annotationType = annotationType; 
		this.considerMetaAnnotations = considerMetaAnnotations;// 是否需要根据annotationType去匹配元注解
	}
    @Override
	protected boolean matchSelf(MetadataReader metadataReader) { //(1)
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		return metadata.hasAnnotation(this.annotationType.getName()) ||
				(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
	}

    // 省略
}
1.2.3.2matchSelf()方法
  • AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); 通过metadataReader获取

    注解的元数据信息

  • metadata.hasAnnotation(this.annotationType.getName())

    • 使用asm 技术 查询 目标是否被指定 名称直接注解 标注
  • (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())

    • 当this.considerMetaAnnotations = true 表示是否需要根据annotationType去匹配元注解 , metadata.hasMetaAnnotation(this.annotationType.getName()) 使用asm 技术 查询 目标是否被指定 名称 元注解 标注

我们都知道@Repository@Service@Controller里面都标注了@Component@Component@Repository@Service@Controller的元注解。很好理解,扫描的时候用includeFilters 去过滤时,会找到并生成带有这4个注解的resource对应的beanDefinition。

this.includeFilters.add(new AnnotationTypeFilter(Component.class));

总结: 新增一个过滤器, 该过滤器是为了过滤掉没有带有@Component 直接注解、或者过滤掉没有@Component 元注解的 resource

( ps : 因为此时类加载器还未把.class文件加载到jvm中,Spring源码中将.class文件包装成了Resource对象。

​ 我们通过metadataReader使用asm技术去.class文件中匹配注解信息 传送带:【源码】Spring —— ClassMetadata AnnotatedTypeMetadata 解读

现在我们还剩下最后一个判断的方法就能生成一个ScannedGenericBeanDefinition(生成,但还未注册到beanDefinitionMap中)

1.2.4ConditionEvaluator类
1.2.4.1ConditionEvaluator.shouldSkip(AnnotatedTypeMetadata, ConfigurationPhase),

会调用自定义Condition接口实现类的matches方法来判断是否符合条件;

public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
	//如果没有标记Conditional的,这直接返回false,表示不跳过
	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<Condition>();
	//通过getConditionClasses方法获取@Conditional指定的value值,即具体的自定义条件类的class文件
	for (String[] conditionClasses : getConditionClasses(metadata)) {
		for (String conditionClass : conditionClasses) {
			//实例化自定义Condition实现类
			Condition condition = getCondition(conditionClass, this.context.getClassLoader());
			conditions.add(condition);
		}
	}
 
	AnnotationAwareOrderComparator.sort(conditions);
 
	//遍历自定义条件类,挨个判断
	for (Condition condition : conditions) {
		ConfigurationPhase requiredPhase = null;
		if (condition instanceof ConfigurationCondition) {
			requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
		}
		if (requiredPhase == null || requiredPhase == phase) {
			//这里就调用自定义条件类
			if (!condition.matches(this.context, metadata)) { 
				return true;
			}
		}
	}
 
	return false;
}
	
	
//获取类上@Conditional注解的value定义的数组,并返回
@SuppressWarnings("unchecked")
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
	MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
	Object values = (attributes != null ? attributes.get("value") : null);
	return (List<String[]>) (values != null ? values : Collections.emptyList());
}

传送带:

Spring系列第20篇:@Conditional通过条件来控制bean的注册

Spring @Conditional注解 详细讲解及示例

回到1.2.1.3 ClassPathBeanDefinitionScanne#doScan

上面那么长的篇幅都是在基于ClassPathBeanDefinitionScanne#doScan代码段(1)的讲解

目前位置我们才走到下图画红框的位置

3.spring生命周期详解

扫描.class文件后,得到为BeanDefinitions。 但是beanDefintion 还未设置属性,spring会为beanDefintion 设置scope属性,如设置scope属性为single。

1.3spring为beanDefintion设置beanName属性。

我们回到ClassPathBeanDefinitionScanne#doScan 方法,代码段2 : 得到beanName

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		// 这是Spring中的Assert,大家开发时也可以用
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			// 扫描包路径得到BeanDefinition,得到的BeanDefinition是空的,还没有解析类上所定义的注解信息
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//(1)
			for (BeanDefinition candidate : candidates) {
				// 得到Scope的信息,并设置
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				// 得到beanName
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);// (2)

				if (candidate instanceof AbstractBeanDefinition) {
					// 根据beanDefinitionDefaults设置一些默认值
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				// 如果是注解定义的Bean, findCandidateComponents默认实现返回的BeanDefinition
				// 是一个ScannedGenericBeanDefinition,其实现了AnnotatedBeanDefinition接口
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 旧bean不是扫描出来的,当前扫描出来的新bean不会注册到bean工厂
				if (checkCandidate(beanName, candidate)) {
					// 生成BeanDefinitionHolder并注册到registry中
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder = // 设置代理策略
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					// 注册到Spring容器中
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

1.3.1AnnotationBeanNameGenerator#generateBeanName

在使用注解生成Bean的时候,如果没有指定Bean的名称,如@Componet("mytable"),则Spring会使用默认的名称生成策略,具体源码如下:

public class AnnotationBeanNameGenerator implements BeanNameGenerator {

	private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";


	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		if (definition instanceof AnnotatedBeanDefinition) {
			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
			if (StringUtils.hasText(beanName)) {
				// Explicit bean name found.
				return beanName;
			}
		}
		// Fallback: generate a unique default bean name.
		return buildDefaultBeanName(definition);
	}

	/**
	 * Derive a bean name from one of the annotations on the class.
	 * @param annotatedDef the annotation-aware bean definition
	 * @return the bean name, or <code>null</code> if none is found
	 */
	protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
		AnnotationMetadata amd = annotatedDef.getMetadata();
		Set<String> types = amd.getAnnotationTypes();
		String beanName = null;
		for (String type : types) {
			Map<String, Object> attributes = amd.getAnnotationAttributes(type);
			if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
				String value = (String) attributes.get("value");
				if (StringUtils.hasLength(value)) {
					if (beanName != null && !value.equals(beanName)) {
						throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
								"component names: '" + beanName + "' versus '" + value + "'");
					}
					beanName = value;
				}
			}
		}
		return beanName;
	}

	/**
	 * Check whether the given annotation is a stereotype that is allowed
	 * to suggest a component name through its annotation <code>value()</code>.
	 * @param annotationType the name of the annotation class to check
	 * @param metaAnnotationTypes the names of meta-annotations on the given annotation
	 * @param attributes the map of attributes for the given annotation
	 * @return whether the annotation qualifies as a stereotype with component name
	 */
   // isStereotypeWithNameValue检查该注解是否有指定bean名称的资格
	protected boolean isStereotypeWithNameValue(String annotationType,
			Set<String> metaAnnotationTypes, Map<String, Object> attributes) {

		boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
				(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
				annotationType.equals("javax.annotation.ManagedBean") ||
				annotationType.equals("javax.inject.Named");
		return (isStereotype && attributes != null && attributes.containsKey("value"));
	}

	/**
	 * Derive a default bean name from the given bean definition.
	 * <p>The default implementation simply builds a decapitalized version
	 * of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
	 * <p>Note that inner classes will thus have names of the form
	 * "outerClassName.innerClassName", which because of the period in the
	 * name may be an issue if you are autowiring by name.
	 * @param definition the bean definition to build a bean name for
	 * @return the default bean name (never <code>null</code>)
	 */
	protected String buildDefaultBeanName(BeanDefinition definition) {
		String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
		return Introspector.decapitalize(shortClassName);
	}

Spring在给Bean生成名字的时候,会调用generateBeanName方法,这个方法会先尝试获取注解括号中的名字,也就是用户自定义的名称,

isStereotypeWithNameValue检查该注解是否有指定bean名称的资格,如果有资格的话我们就可以使用用户自定的beanName了,

boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
				(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
				annotationType.equals("javax.annotation.ManagedBean") ||
				annotationType.equals("javax.inject.Named");

​		return (isStereotype && attributes != null && attributes.containsKey("value"));

如果 注解的attributes 属性不为空,包含value属性并且还存在下面四种情况之一 。

  1. 直接注解@component
  2. 元注解@component的
  3. 直接注解@ManagedBean
  4. 存在直接注解@Named

此时读取元数据中value属性的值作为beanName属性值,并设置到beanDefinition的beanName属性中

比如说@component(“hello”)此时beanDefinition的beanName就为hello

如果没有获取到beanName,则调用buildDefaultBeanName,用于生成默认的名称,这个方法会使用Introspector.decapitalize(shortClassName);

	// Fallback: generate a unique default bean name.
		// 如果注解中没有配置beanName,那么则生成一个默认的
		return buildDefaultBeanName(definition, registry);
/**
Utility method to take a string and convert it to normal Java variable name capitalization. This normally means converting the first character from upper case to lower case, but in the (unusual) special case when there is more than one character and both the first and second characters are upper case, we leave it alone.
Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays as "URL".
Parameters:
name - The string to be decapitalized.
Returns:
The decapitalized version of the string.
**/
public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]); // 如果类名字为AbTest 则 beanName = "abTest"
        return new String(chars);
    }

这边要注意了, 最重要的一句话翻译过来是说:如果name的开头两个及两个以上字符为大写,则不作处理并直接返回原来的名字,否则将名称的首字母小写后返回。

@Component
public class MXTable{
......
}

问题场景:

定义一个类如下:

通过ApplicationContext.getBean("mXTable")获取这个Bean对象,但是此时beanName = “MXTable”,导致调用的时候出现空指针异常。 传送门:Spring中生成Bean时默认生成名称策略的坑

1.4 为beanDefinition设置默认值

1.4.1AbstractBeanDefinition#applyDefaults

/**
	 * Apply the provided default values to this bean.
	 * @param defaults the default settings to apply
	 * @since 2.5
	 */
	public void applyDefaults(BeanDefinitionDefaults defaults) {
		Boolean lazyInit = defaults.getLazyInit();
		if (lazyInit != null) {
			setLazyInit(lazyInit);
		}
		setAutowireMode(defaults.getAutowireMode());
		setDependencyCheck(defaults.getDependencyCheck());
		setInitMethodName(defaults.getInitMethodName());
		setEnforceInitMethod(false);
		setDestroyMethodName(defaults.getDestroyMethodName());
		setEnforceDestroyMethod(false);
	}

1.5 处理Lazy、DependsOn、Role、Description等注解信息,并设置到abd中

1.5.1AnnotationConfigUtils#processCommonDefinitionAnnotations
	// 处理Lazy、DependsOn、Role、Description等注解信息,并设置到abd中
	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
		else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(), Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}

		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}

		AnnotationAttributes role = attributesFor(metadata, Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}

		AnnotationAttributes description = attributesFor(metadata, Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}

1.6 检验beanFactroy中是否已经注册了相同beanName的beanDefinition,spring要处理这种情况

3.spring生命周期详解

ClasspathBeanDefinitionScanner#checkCandidate

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
		// 如果registry中不存在当前beanName对应的beanDefinition,则直接返回true
		if (!this.registry.containsBeanDefinition(beanName)) {
			return true;
		}
		// 如果已经存在
		BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
		BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
		if (originatingDef != null) {
			existingDef = originatingDef;
		}
		//existingDefinition不是扫描出来的
		if (isCompatible(beanDefinition, existingDef)) {
			return false;
		}
		throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
				"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
				"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}

1.7 spring索引生成beanDefinition —Spring 5 启动性能优化之 @Indexed

两张图拼在一起看吧 ,哎

3.spring生命周期详解

3.spring生命周期详解

Spring5的spring.components扩展点

spring-framework 在版本 5.x 中新增了一个模块 spring-context-indexer,作用:

应用中使用<context:component-scan />或@ComponentScan扫描的package包含的类越来越多的时候,Spring启动时模式注解解析时间就会变得越长。@Indexed注解的引入正是为了解决这个问题,项目编译打包时,会在自动生成META-INF/spring.components文件,文件包含被@Indexed注释的类的模式解析结果

当Spring应用上下文进行组件扫描时,META-INF/spring.components会被org.springframework.context.index.CandidateComponentsIndexLoader读取并加载,转换为CandidateComponentsIndex对象。 此时组件扫描会读取CandidateComponentsIndex,而不进行实际扫描,从而提高组件扫描效率,减少应用启动时间。`

前面讲doScan的findCandidateComponents方法时,我们介绍了,自Spring5开始,查找BeanDefinition有两条路径:一条是传统的扫描包,前面已经讲了它的源码,另一条就是直接从”META-INF/spring.components”组件索引文件中加载符合条件的bean,即addCandidateComponentsFromIndex方法,在介绍该方法之前:请你保持探索下面几种问题的好奇心:我们知道 spring-context-indexer 可以生成 META-INF/spring.components 文件到类路径,

  • 那么文件中到底保存了哪些信息?
  • 文件中的的所有内容都会被用到吗?
  • Spring 又是如何读取文件的?

现在我们简单介绍一下该方法:

Spring5升级的其中一个重点就提升了注解驱动的启动性能,”META-INF/spring.components”这个文件类似于一个“组件索引”文件,我们将需要加载的组件(beean定义)预先的以键值对的样式配置到该文件中,当项目中存在”META-INF/spring.components”文件并且文件中配置了属性时,Spring不会进行包扫描,而是直接读取”META-INF/spring.components”中组件的定义并直接加载,从而达到提升性能的目的。

1.7.1Indexed 注解的定义:

可以看到,@Indexed 注解只能标注在类型上。@Indexed 标注的注解如果标注或元标注在类上,则这个类将成为候选的对象。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Indexed {
}

1.7.2META-INF/spring.components 如何生成?

@Indexed就是Spring5位了支持组件索引而新增的一个注解,因为实际上spring.components文件可以自动生成。

如果对org.springframework:spring-context-indexer处理机制感兴趣,则可参考org.springframework.context.index.CandidateComponentsIndexer的实现,其底层技术为“Java Annotation Processor”。

spring-context-indexer 定义了一个注解处理器(参见前面的文章 Java 注解处理器及其应用 ),因此只需要跟踪注解处理的逻辑即可了解其内部的实现,确定写入的文件内容。事实上 spring-context-indexer 模块中的类也确实没有几个,其项目结构如下图所示。

3.spring生命周期详解

  • CandidateComponentsIndexer 就是注解处理器,
    • CandidateComponentsIndexer 一轮一轮的处理元素,到最后一轮时将获取到的元数据写入到文件中。

CandidateComponentsIndexer负责对符合条件的注解生成索引文件(spring.components),整个源码也不是特别复杂,通过三个组件:

StereotypesProvider

MetadataCollector

MetadataStore来完成。

public class CandidateComponentsIndexer implements Processor {
	@Override
	public synchronized void init(ProcessingEnvironment env) {
		this.stereotypesProviders = getStereotypesProviders(env);
		this.typeHelper = new TypeHelper(env);
		this.metadataStore = new MetadataStore(env);
		this.metadataCollector = new MetadataCollector(env, this.metadataStore.readMetadata());
	}
 
	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		this.metadataCollector.processing(roundEnv);
		roundEnv.getRootElements().forEach(this::processElement);
		if (roundEnv.processingOver()) {
			writeMetaData();
		}
		return false;
	}
}
//定义了哪些注解需要被索引
interface StereotypesProvider {
	/**
	 * Return the stereotypes that are present on the given {@link Element}.
	 * @param element the element to handle
	 * @return the stereotypes or an empty set if none were found
	 */
	Set<String> getStereotypes(Element element);
}
//获取需要被索引的CandidateComponentsMetadata(元数据)
class MetadataCollector {
	public CandidateComponentsMetadata getMetadata() {
		CandidateComponentsMetadata metadata = new CandidateComponentsMetadata();
		for (ItemMetadata item : this.metadataItems) {
			metadata.add(item);
		}
		if (this.previousMetadata != null) {
			List<ItemMetadata> items = this.previousMetadata.getItems();
			for (ItemMetadata item : items) {
				if (shouldBeMerged(item)) {
					metadata.add(item);
				}
			}
		}
		return metadata;
	}    
}
//将上面的结果输出到spring.components中
class MetadataStore {
	static final String METADATA_PATH = "META-INF/spring.components";    
	public void writeMetadata(CandidateComponentsMetadata metadata) throws IOException {
		if (!metadata.getItems().isEmpty()) {
			try (OutputStream outputStream = createMetadataResource().openOutputStream()) {
				PropertiesMarshaller.write(metadata, outputStream);
			}
		}
	}    
}    

StereotypesProvider 是元数据的收集器

  • 用来收集元素中的模式信息,模式信息可能是注解等类型,也可能是其他的信息。

  • 收集到的每一项元数据保存到 ItemMetadata,

    3.spring生命周期详解

    包含类型和类型对应的模式列表。最终类型作为 key,模式列表以英文逗号分隔作为 value,以 properties 的形式保存到文件。

StereotypesProvider 定义如下。

interface StereotypesProvider {
/**
 * 返回给定元素的模式信息
 */
Set<String> getStereotypes(Element element);
}

StereotypesProvider 有三个实现,具体如下。

  • IndexedStereotypesProvider: 用来处理 @Indexed 注解,事实上也只有这个类才处理 @Indexed 注解。其获取到的模式信息如下:
    • @Indexed 注解直接标注的类型完全限定名,包括父类和接口。
    • 标注或元标注在类上的并且被 @Indexed 元标注的注解类型的完全限定名。
  • StandardStereotypesProvider:
    • 收集的模式信息为类上直接标注或通过 @Inherited 可以获取到的 Java 中包名以 javax 开头的注解的完全限定名。
  • PackageInfoStereotypesProvider:注解如果标注在 package-info.java 文件中的包名上,则收集的模式信息为 package-info 。

示例如下:

@Indexed
@Service
public interface Inter1 {

}

@Named
public interface Inter2 {

}

@Indexed
public class Parent {

}

@Component
@Indexed
public class Child extends Parent implements Inter1,Inter2 {

}

// package-info.java
@PackageAnnotation
package com.zzhkp;


编译后获取到的文件内容如下。

com.zzhkp=package-info
com.zzhkp.Child=org.springframework.stereotype.Component,com.zzhkp.Child,com.zzhkp.Parent,com.zzhkp.Inter1
com.zzhkp.Inter1=org.springframework.stereotype.Component,com.zzhkp.Inter1
com.zzhkp.Inter2=javax.inject.Named
com.zzhkp.Parent=com.zzhkp.Parent

1.7.4哪些资源会被索引?

目前,组件索引支持存在@Indexed元注解的注解,比如@Component注解上就标注了@Indexed注解,以及类路径以javax.开头的注解,比如@ManagedBean或者@Named注解,以及直接标注了@Indexed注解的类或者接口。

  1. org.springframework.stereotype包下的注解@Component@Controller@Service@Repository,除@Component外,@Controller@Service@Repository注解也同时标记有@Component注解,所以默认情况下,索引机制针对这四个注解。

  2. 自定义注解

    使用@Indexed作为元注解声明注解。

    使用@Component@Controller@Service@Repository中任一个作为元注解声明注解。

注:如果已经是spring bean(Component修饰的类,因为Component已经被标记为@Indexed)了就没必要再标记@Indexed,否则索引文件会再追加一个相同的,感觉这是个bug

1.7.5spring索引如何生成

我们都知道索引是优化的一大利器,spring的索引是怎样生成的呢?

调用ClassPathBeanDefinitionScanner构造方法生成扫描器的时候会调用父类ClassPathScanningCandidateComponentProvider的构造方法

public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
   if (useDefaultFilters) {
      registerDefaultFilters(); 
   }
   setEnvironment(environment);// 设置环境
    /*
     * 设置 ResourceLoader的时候,会尝试进行"META-INF/spring.components"文件的读取
     * 委托调用父类ClassPathScanningCandidateComponentProvider的方法
     */
   setResourceLoader(null);// 设置索引、资源加载器
}
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
   this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
   //新建了一个metadataReaderFactory 工厂获取MetadataReader,MetadataReader的功能我们之前
    //已经介绍过了
   this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); 
   //加载组件索引文件,将结果赋值给componentsIndex
    this.componentsIndex =  CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader()  );
}

CandidateComponentsIndexLoader类

可以看到读取文件最终是由CandidateComponentsIndexLoader.loadIndex完成,并将读取结果保存到 CandidateComponentsIndex 中。读取的逻辑也较为简单,判断类路径 spring.properties 文件内或系统参数 spring.index.ignore 是否设置为true,如果是则跳过读取,否则使用 ClassLoader 获取类路径下所有的 META-INF/spring.components 文件(参见文章 Java 中如何获取 classpath 下资源文件? ),并加载为 Properties,然后保存到 CandidateComponentsIndex 。

public final class CandidateComponentsIndexLoader {
    /**
 * CandidateComponentsIndexLoader的属性
 * 
 * 要查找组件索引文件的位置常量,可以存在于多个 JAR 文件中
 */
	public static final String COMPONENTS_RESOURCE_LOCATION = "META-INF/spring.components";
	private static final ConcurrentMap<ClassLoader, CandidateComponentsIndex> cache =
			new ConcurrentReferenceHashMap<>();
	/**
 * CandidateComponentsIndexLoader的方法
 * 


 * 从默认的文件路径"META-INF/spring.components"加载索引文件成为一个CandidateComponentsIndex实例并返回
 * 如果没有找到任何文件或者文件中没有定义组件,则返回null
 *
 * @param classLoader 给定的类加载器
 * @return 将要使用的CandidateComponentsIndex实例,如果没有找到索引文件则返回null
 */
    @Nullable
	public static CandidateComponentsIndex loadIndex(@Nullable ClassLoader classLoader) {
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = CandidateComponentsIndexLoader.class.getClassLoader();
		}
		return cache.computeIfAbsent(classLoaderToUse, CandidateComponentsIndexLoader::doLoadIndex);
	}
    
	@Nullable
	private static CandidateComponentsIndex doLoadIndex(ClassLoader classLoader) {
		if (shouldIgnoreIndex) {
			return null;
		}
		try {
           //加载全部组件索引文件
			Enumeration<URL> urls = classLoader.getResources(COMPONENTS_RESOURCE_LOCATION);//读取META-INF/spring.components文件
           //如果没有加载到组件索引文件,直接返回null
			if (!urls.hasMoreElements()) {
				return null;
			}
			List<Properties> result = new ArrayList<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				result.add(properties);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + result.size() + "] index(es)");
			}
			int totalCount = result.stream().mapToInt(Properties::size).sum();
          //如果没有从组件索引文件中加载到属性,同样返回null,否则返回CandidateComponentsIndex实例
			return (totalCount > 0 ? new CandidateComponentsIndex(result) : null);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Unable to load indexes from location [" +
					COMPONENTS_RESOURCE_LOCATION + "]", ex);
		}
	}
}  

  1. CandidateComponentsIndexLoader可以从多个jar中读取多个索引文件。

    1. CandidateComponentsIndexLoaderdoLoadIndex加载了META-INF/spring.components文件,并CandidateComponentsIndex实例,用于进行索引查找

    2. CandidateComponentsIndex放到 cache缓存池 (key:ClassLoader ,value:CandidateComponentsIndex

    3. CandidateComponentsIndexLoader.doLoadIndex(...)实现中出现了一个shouldIgnoreIndex变量,其值是Spring系统属性spring.index.ignore的值。通过这个Spring系统属性,可以关闭索引功能。

      通过spring.properties设置spring.index.ignore禁用索引功能。此时编译打包或直接启动项目,仍会生成META-INF/spring.components文件,但进行组件加载时,不会使用其作为缓存,而是进行类路径扫描加载组件。

      3.spring生命周期详解

      spring.properties
      # 禁用索引功能.
      spring.index.ignore=true
      
      

      通过编码方式设置spring.index.ignore来禁用索引功能。

      参照《Spring 通篇源码 之 扩展点 之 ApplicationContextInitializer原理与应用》,

      1、在web.xml中设置:
      <context-param>
          <param-name>contextInitializerClasses</param-name>
          <param-value>
              com.arhorchin.securitit.extend.initializer.CustomerApplicationContextInitializer
          </param-value>
      </context-param>
      
      2、用户自定制ApplicationContextInitializer.java,此时,也可以达到和①中一样的效果。
      
      
      /**
       * @author Securitit.
       * @note 自定义ApplicationContextInitializer.
       */
      public class CustomerApplicationContextInitializer implements ApplicationContextInitializer {
          
          /**
           * logger.
           */
          private Logger logger = LoggerFactory.getLogger(CustomerApplicationContextInitializer.class);
      
          @Override
          public void initialize(ConfigurableApplicationContext applicationContext) {
              logger.info("WebApplicationContext-id:" + applicationContext.getId());
              SpringProperties.setProperty("spring.index.ignore", "true");
          }
      
      }
      

new CandidateComponentsIndex(result) ; 时候会调用parseIndex方法

CandidateComponentsIndex#parseIndex

index.key = stereotype

index.value = Entry

/**
 * 加载进来的组件索引文件
 */
public class CandidateComponentsIndex {
     

    /**
     * Ant路径匹配器,用来支持basePackage的模式匹配
     */
    private static final AntPathMatcher pathMatcher = new AntPathMatcher(".");

    /**
     * 存放格式化之后的bean组件信息
     */
    private final MultiValueMap<String, Entry> index;


    /**
     * doLoadIndex方法调用的构造器
     *
     * @param content Properties的list集合,有几个文件就有几个Properties
     */
    CandidateComponentsIndex(List<Properties> content) {
     
        //调用parseIndex方法
        this.index = parseIndex(content);
    }

    private static MultiValueMap<String, Entry> parseIndex(List<Properties> content) {
     
        MultiValueMap<String, Entry> index = new LinkedMultiValueMap<>();
        //遍历Properties
        for (Properties entry : content) {
     
            entry.forEach((type, values) -> {
     
                //按照","拆分value为stereotypes数组
                String[] stereotypes = ((String) values).split(",");
                //遍历stereotypes数组
                for (String stereotype : stereotypes) {
     
                    //将stereotype作为key,一个新Entry作为value加入到index映射中,这里的Entry是CandidateComponentsIndex的一个内部类
                    //注意,由于是LinkedMultiValueMap类型的映射,它非常特别,对于相同的key,它的value不会被替换,而是采用一个LinkedList将value都保存起来
                    //比如,如果有两个键值对,key都为a,value分别为b、c,那么添加两个键值对之后,map中仍然只有一个键值对,key为a,但是value是一个LinkedList,内部有两个值,即b和c
                    index.add(stereotype, new Entry((String) type));
                }
            });
        }
        return index;
    }

    private static class Entry {
     
        /**
         * type就是spring.components文件中的key,即要注册的类的全限定名
         */
        private final String type;

        private final String packageName;

        /**
         * 构造器
         *
         * @param type
         */
        Entry(String type) {
     
            //为type赋值
            this.type = type;
            //获取包路径名,即出去类名之后的路径
            this.packageName = ClassUtils.getPackageName(type);
        }

        /**
         * 匹配basePackage
         *
         * @param basePackage basePackage包路径
         * @return true以匹配,false未匹配
         */
        public boolean match(String basePackage) {
     
            /*
             * 如果basePackage存在模式字符,比如? * ** ,那么使用pathMatcher来匹配
             */
            if (pathMatcher.isPattern(basePackage)) {
     
                return pathMatcher.match(basePackage, this.packageName);
            }
            /*
             * 否则,表示basePackage就是一个固定的字符串,那么直接看type是否是以basePackage为起始路径即可
             */
            else {
     
                return this.type.startsWith(basePackage);
            }
        }
    }

}
  1. 在configureScanner方法创建配置扫描器ClassPathBeanDefinitionScanner的时候,在ClassPathBeanDefinitionScanner 的构造器中,Spring就会尝试进行”META-INF/spring.components”文件的读取!
  2. 组件索引文件的读取同样是委托ClassPathScanningCandidateComponentProvider来完成的。如果存在组件索引文件并且文件中定义了属性,那么将会返回一个包含找到的所有组件的属性的CandidateComponentsIndex实例,否则返回null,并且将返回结果赋值给ClassPathScanningCandidateComponentProvider的componentsIndex属性!
1.7.6索引的使用

1) 若要开启@Indexed索引功能,首先需要引入spring-context-indexer

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
    <optional>true</optional>
</dependency>

2) 若配置无误,此时编译打包或直接启动项目,会生成META-INF/spring.components文件,并且会跳过类路径扫描阶段。

#
#Mon Nov 23 15:11:25 CST 2020
com.arhorchin.securitit.business.controller.HelloController=org.springframework.stereotype.Component
com.arhorchin.securitit.stereotype.component.SecComponent=org.springframework.stereotype.Component
com.arhorchin.securitit.stereotype.controller.SecController=org.springframework.stereotype.Component
com.arhorchin.securitit.stereotype.service.impl.SecServiceImpl=org.springframework.stereotype.Component
com.arhorchin.securitit.stereotype.repository.impl.SecRepositoryImpl=org.springframework.stereotype.Component

读取到的spring.components`文件内容都会被使用吗?事实并非如此。我们接着往下看:

spring使用索引的位置在哪里呢?我们仔细观察一下ClassPathScanningCandidateComponentProvider#findCandidateComponents方法

获取beanDefinitions的两种方式:

  1. scanCandidateComponents(basePackage)方法得到Set
  2. addCandidateComponentsFromIndex也能得到Set

ClassPathScanningCandidateComponentProviderfindCandidateComponents决定是使用META-INF/spring.components索引,还是进行类路径扫描。

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
           // Spring提供了一种支持更快速扫描的机制,使用spring索引
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		} 
		else {
			return scanCandidateComponents(basePackage);
		}
	}
	/**
	 * Determine if the index can be used by this instance.
	 * @return {@code true} if the index is available and the configuration of this
	 * instance is supported by it, {@code false} otherwise
	 * @since 5.0
	 */
	private boolean indexSupportsIncludeFilters() {
       //校验每一个includeFilter,只要有一个不符合要求就返回false
		for (TypeFilter includeFilter : this.includeFilters) {
			if (!indexSupportsIncludeFilter(includeFilter)) {
				return false;
			}
		}
		return true;
	}

/**
 * 确定指定是否是AnnotationTypeFilter或者AssignableTypeFilter的类型过滤器,以及是否支持组件索引
 *
 * @param filter 要检查的过滤器
 * @return 索引是否支持此包括过滤器
 */
private boolean indexSupportsIncludeFilter(TypeFilter filter) {
     
    //AnnotationTypeFilter类型的TypeFilter
    if (filter instanceof AnnotationTypeFilter) {
     
        Class<? extends Annotation> annotation = ((AnnotationTypeFilter) filter).getAnnotationType();
        //确定该注解类型是否包含@Indexed元注解 或者 该注解类型的名称是否以javax.开头,即ManagedBean或者Named注解
        //如果满足一个,则支持组件索引,返回true,否则返回false
        return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) ||
                annotation.getName().startsWith("javax."));
    }
    //AssignableTypeFilter类型的TypeFilter
    if (filter instanceof AssignableTypeFilter) {
        Class<?> target = ((AssignableTypeFilter) filter).getTargetType();
        //确定该类(接口)的类型上是否具有@Indexed元注解,如果具有,则支持组件索引,返回true,否则返回false
        return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target);
    }
    //其它类型的TypeFilter,直接返回false
    return false;
}

假设存在组件索引文件并且加载成功,那么componentsIndex属性就不会为null,随后就会走到indexSupportsIncludeFilters方法。

这个方法用于校验includeFilters中是否还存在除了AnnotationTypeFilter和AssignableTypeFilter类型的Filter之外的其他TypeFilter,

如果存在,则依然不会走addCandidateComponentsFromIndex的逻辑,因为组件索引仅仅支持AnnotationTypeFilter和AssignableTypeFilter的过滤选项,其他类型的过滤目前不支持,这也是这种模式的一个缺点!

目前,组件索引支持存在@Indexed元注解的注解,比如@Component注解上就标注了@Indexed注解,以及类路径以javax.开头的注解,比如@ManagedBean或者@Named注解,以及直接标注了@Indexed注解的类或者接口。

ClassPathScanningCandidateComponentProvider#addCandidateComponentsFromIndex的方法

	/**
 * ClassPathScanningCandidateComponentProvider的方法
 * 

 * 基于组件索引componentsIndex加载bean定义
 *
 * @param index       componentsIndex
 * @param basePackage 要扫描的包路径
 * @return 符合条件的BeanDefinition集合
 */
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
     
    //该集合用于保存注册的BeanDefinition
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
     
        Set<String> types = new HashSet<>();
        /*
         * 1 遍历includeFilters过滤器,获取满足条件的组件索引文件中的bean类型(全路径类名)
          registerDefaultFilters() 方法注册了支持注解 @Component、@ManagedBean、@Named 的注解类型过滤器。
         */
        for (TypeFilter filter : this.includeFilters) {
     
            //提取AnnotationTypeFilter和AssignableTypeFilter类型的过滤器指定的注解名和类(接口名)字符串。
            //比如是Component注解的Filter,那么返回org.springframework.stereotype.Component
            //如果是其它类型的TypeFilter,则返回null
            String stereotype = extractStereotype(filter);
            //如果stereotype为null,那么抛出异常,因为组件索引文件中只能指定注解或者类的全路径名,这也是一个局限
            if (stereotype == null) {
     
                throw new IllegalArgumentException("Failed to extract stereotype from " + filter);
            }
            //返回满足包含Filters过滤器以及basePackage包路径的所有类型
            types.addAll(index.getCandidateTypes(basePackage, stereotype));
        }
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();

        /*
         * 2 遍历所有bean类型(全路径类名),进行校验,以及创建BeanDefinition
         * 这一部分就类似于scanCandidateComponents方法的逻辑
         */
        for (String type : types) {
     
            //获取该类的MetadataReader,可以获取了类的元数据:ClassMetadata、AnnotationMetadata
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
            /*
             * 和scanCandidateComponents方法一样
             * 1 检查读取到的类是否可以作为候选组件,即是否符合TypeFilter类型过滤器的要求
             */
            if (isCandidateComponent(metadataReader)) {
     
                //如果符合,那么基于metadataReader先创建ScannedGenericBeanDefinition,
                ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                sbd.setSource(metadataReader.getResource());
                /*
                 * 2 继续检查给定bean定义是否可以作为候选组件,即是否符合bean定义
                 */
                if (isCandidateComponent(sbd)) {
     
                    if (debugEnabled) {
     
                        logger.debug("Using candidate component class from index: " + type);
                    }
                    //如果符合,那么添加该BeanDefinition
                    candidates.add(sbd);
                } else {
     
                    if (debugEnabled) {
     
                        logger.debug("Ignored because not a concrete top-level class: " + type);
                    }
                }
            } else {
     
                if (traceEnabled) {
     
                    logger.trace("Ignored because matching an exclude filter: " + type);
                }
            }
        }
    } catch (IOException ex) {
     
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    //返回candidates
    return candidates;
}

假设存在组件索引文件并且加载成功,那么就会走addCandidateComponentsFromIndex方法,基于componentsIndex加载复合条件的bean定义。
  addCandidateComponentsFromIndex中同样会使用到TypeFilter检验,以及会使用到我们设置的basePackage,但是这里并不是去扫描包,而是校验加载进来的bean组件的位置是否位于指定的basePackage中,相当于也是一种校验!其他的校验则和scanCandidateComponents方法的逻辑差不多,都有两个isCandidateComponent的校验!

1.7.7extractStereotype提取过滤类型

提取AnnotationTypeFilter和AssignableTypeFilter类型的过滤器指定的注解名和类(接口名)字符串。如果是其它类型的TypeFilter,则返回null,随后在外部方法中将抛出异常!

/**
 * ClassPathScanningCandidateComponentProvider的方法
 * 

 * 提取AnnotationTypeFilter和AssignableTypeFilter类型的过滤器指定的注解名和类(接口名)字符串
 * 如果是其它类型的TypeFilter,则返回null
 *
 * @param filter 要处理的过滤器
 * @return 匹配此筛选器的类型
 */
@Nullable
private String extractStereotype(TypeFilter filter) {
     
    //如果是AnnotationTypeFilter类型
    if (filter instanceof AnnotationTypeFilter) {
     
        //那么返回注解的名字
        return ((AnnotationTypeFilter) filter).getAnnotationType().getName();
    }
    //如果是AnnotationTypeFilter类型
    if (filter instanceof AssignableTypeFilter) {
     
        //那么返回类或者接口的名字
        return ((AssignableTypeFilter) filter).getTargetType().getName();
    }
    //其它类型,返回null
    return null;
}
1.7.8getCandidateTypes返回满足条件的bean类型

返回满足条件的bean类型(全路径类名)。即要求加载进来的组件索引匹配指定TypeFilter中的注解或者类(接口)的全路径名,并且组件索引中的bean路径位于basePackage指定的路径之中!

/**
 1. CandidateComponentsIndex的方法
 2. 

 3. 返回满足条件的bean类型(全路径类名)
 4.  5. @param basePackage 要检查的包路径
 6. @param stereotype  要使用的类型
 7. @return 满足条件的bean类型集合
 */
public Set<String> getCandidateTypes(String basePackage, String stereotype) {
     
    //获取使用指定注解或者类(接口)的全路径名的作为key的value集合
    List<Entry> candidates = this.index.get(stereotype);
    //如果candidates不为
    if (candidates != null) {
     
        //使用lambda的并行流处理,如果当前bean类型属于指定的包路径中,则表示满足条件,并且收集到set集合中
        return candidates.parallelStream()
                //匹配包路径
                .filter(t -> t.match(basePackage))
                //获取type,实际上就是文件的key,即bean组件的类的全路径类名
                .map(t -> t.type)
                .collect(Collectors.toSet());
    }
    //返回空集合
    return Collections.emptySet();
}
1.7.9spring.components文件的格式以及加载格式

spring.components文件的编写格式非常的简单,即key=value类型的键值对:

  1. key:要注册的类的全限定名;
  2. value:includeFilters中的任何一个AnnotationTypeFilter和AssignableTypeFilter类型的过滤器的过滤类型的全限定类名,比如Component的TypeFilter的全路径类名:org.springframework.stereotype.Component;当然可以写多个类型,使用,分隔即可。
  3. spring.components文件加载到CandidateComponentsIndex中之后,内部的键值对变成了一个LinkedMultiValueMap类型的映射,存入index属性中。
  4. 在解析的时候,value可以传递多个,使用,分隔,解析的时候将会拆分开,并且spring.components文件中的value在index映射中成为了key,而且由于是LinkedMultiValueMap类型的映射,它非常特别,对于相同的key,它的value不会被替换,而是采用一个LinkedList将value都保存起来。

Spring5的spring.components扩展点案例

我们在com.spring.source.index路径下新建四个类IndexClass、IndexClass2、IndexClass3、IndexClass4,它们分别使用@Component、@Service、@Named、@Component注解装饰。注意@Named是属于JSR330 的注解,想要使用它,我们必须引入另一个maven依赖:

<dependency>
    <groupId>javax.injectgroupId>
    <artifactId>javax.injectartifactId>
    <version>1version>
dependency>

测试类如下:

@Component
public class IndexClass {
      }
@Service
public class IndexClass2 {
      }
@Named
public class IndexClass3 {
      }
@Component
public class IndexClass4 {
      }

测试:

@Test
public void componentsIndex() {
     
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config-index.xml");
    System.out.println(ac.getBean("indexClass"));
    System.out.println(ac.getBean("indexClass2"));
    System.out.println(ac.getBean("indexClass3"));
    System.out.println(ac.getBean("indexClass4"));
}

结果当然是可以获取全部的bean:

com.spring.source.index.IndexClass@dbf57b3
com.spring.source.index.IndexClass2@384ad17b
com.spring.source.index.IndexClass3@61862a7f
com.spring.source.index.IndexClass4@441772e

现在我们在resources目录下(我使用的idea)新增一个META-INF/spring.components文件:

3.spring生命周期详解

加入如下配置:

spring.component

#key为需要手动添加的bean组件类的全路径名,value为includeFilters中的一个TypeFilter过滤条件,比如Component的TypeFilter的全路径类名
com.spring.source.index.IndexClass=org.springframework.stereotype.Component
com.spring.source.index.IndexClass2=org.springframework.stereotype.Component
com.spring.source.index.IndexClass3=javax.inject.Named,org.springframework.stereotype.Component

可以看到,我们仅仅添加了三个bean组件,当我们再一次运行测试代码时,发现抛出了异常:

com.spring.source.index.IndexClass@3c153a1
com.spring.source.index.IndexClass2@b62fe6d
com.spring.source.index.IndexClass3@13acb0d1

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'indexClass4' available

很明显,就是没有找到indexClass4,为什么呢?就是因为我们设置了META-INF/spring.components,但是只配置了三个bean定义,Spring在加载的时候就会从我们定义的组件索引文件中去加载bean定义,不会走扫描包的逻辑,导致indexClass4不能被加载和注册,我们自然无法获取对应的实例!
  需要注意的是,在此模式下,作为组件扫描目标的所有模块都必须使用此机制,如果只有部分模块存在 spring.components 文件,则其他模块的 bean 也不会走包扫描。为此,可以我们可以在Spring环境变量中设置spring.index.ignore属性为true,这样就不会扫描spring.components 文件,而是走包扫描!
  下面我们来deBug看看具体的情况!
  首先我们在CandidateComponentsIndex中打上断点,就能看到我们的配置文件被夹在进来之后的样式:
3.spring生命周期详解
  随后在ClassPathScanningCandidateComponentProvider中打上断点,就能明显看到它走的是addCandidateComponentsFromIndex的逻辑,根本没有扫描包:
3.spring生命周期详解
  最后进入addCandidateComponentsFromIndex方法,我们能看到,includeFilters包含两个Filter,因为我们引入了javax.inject,因此除了Component注解的Filter之外,还有一个JSR330的Named注解的Filter,它们是在registerDefaultFilters方法中注册的,前面已经讲过了!
3.spring生命周期详解

1.8registerAnnotationConfigProcessors注册注解配置处理器

在给定注册表中注册所有注解配置处理器的bean定义,用于后续步骤中对相关注解的处理,这个方法非常的重要。后面讲到的invokeBeanFactoryPostProcessors方法会回调所有的BeanFactoryPostProcessor,而创建bean实例的时候会回调所有的BeanPostProcessor。这里注册的这些bean定义在后面会先于普通bean定义被初始化,并在某个该它出手的阶段就会被调用相关方法,随后就会处理相关的注解!

  1. ConfigurationClassPostProcessor -> 用于处理@Configuration、@ComponentScan、@ComponentScans @Import 、@Bean注解-> 一个BeanDefinitionRegistryPostProcessor,非常重要。
  2. AutowiredAnnotationBeanPostProcessor -> 用于处理@Autowired、@Value、@Inject、@Lookup注解 -> 一个BeanPostProcessor,非常重要。
  3. CommonAnnotationBeanPostProcessor(要求支持JSR 250,默认支持) -> 用于处理@Resource、@PostConstruct、@PreDestroy、@WebServiceRef、@EJB等注解 -> 一个BeanPostProcessor,非常重要。
  4. PersistenceAnnotationBeanPostProcessor(要求支持JPA,默认不支持,需要引入JPA依赖) -> 用于处理JPA的相关注解,比如@PersistenceContext和@PersistenceUnit -> 一个BeanPostProcessor
  5. EventListenerMethodProcessor -> 用于处理@EventListener注解 -> 一个 SmartInitializingSingleton
  6. DefaultEventListenerFactory ->用于注册为解析@EventListener注解的方法而创建ApplicationListener的策略接口对应 -> 一个EventListenerFactory
  7. 注意,自Spring5.1开始,RequiredAnnotationBeanPostProcessor后处理器不被自动注册,因为Spring不赞成使用@Required注解,对于必须的依赖推荐使用构造器注入。

该方法zh注册的这些处理器,在后面bean实例化的时候将会被非常频繁的使用到,用于解析个注解对于bean进行装配和增强。

//------------AnnotationConfigUtils工具类的相关属性

/**
 * ConfigurationClassPostProcessor的bean name常量
 */
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
        "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
/**
 * AutowiredAnnotationBeanPostProcessor的bean name常量
 */
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
        "org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
/**
 * CommonAnnotationBeanPostProcessor的bean name常量
 */
public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
        "org.springframework.context.annotation.internalCommonAnnotationProcessor";


/**
 * PersistenceAnnotationBeanPostProcessor的bean name常量,用于JPA 注解支持
 */
public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
        "org.springframework.context.annotation.internalPersistenceAnnotationProcessor";

/**
 * PersistenceAnnotationBeanPostProcessor的bean class常量,用于JPA 注解支持
 */
private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
        "org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";


/**
 * EventListenerMethodProcessor的bean name常量
 */
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
        "org.springframework.context.event.internalEventListenerProcessor";

/**
 * DefaultEventListenerFactory的bean name常量
 */
public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
        "org.springframework.context.event.internalEventListenerFactory";

/**
 * AnnotationConfigUtils工具类的方法
 * 
 * 在给定注册表中注册所有注解配置处理器的bean定义,用于后续步骤中对相关注解的处理
 * 
 * ConfigurationClassPostProcessor -> 用于处理@Configuration注解 -> 一个BeanDefinitionRegistryPostProcessor
 * AutowiredAnnotationBeanPostProcessor -> 用于处理@Autowired、@Value、@Inject、@Lookup注解 -> 一个BeanPostProcessor
 * CommonAnnotationBeanPostProcessor(要求支持JSR 250,默认支持) -> 用于处理@Resource、@PostConstruct、@PreDestroy、@WebServiceRef、@EJB等注解 -> 一个BeanPostProcessor
 * PersistenceAnnotationBeanPostProcessor(要求支持JPA,默认不支持,需要引入JPA依赖) -> 用于处理JPA的相关注解,比如@PersistenceContext和@PersistenceUnit -> 一个BeanPostProcessor
 * EventListenerMethodProcessor ->  用于处理@EventListener注解 -> 一个 SmartInitializingSingleton
 * DefaultEventListenerFactory ->用于注册为解析@EventListener注解的方法而创建ApplicationListener的策略接口对应 -> 一个EventListenerFactory
 * 
 * 注意,自Spring5.1开始,RequiredAnnotationBeanPostProcessor后处理器不被自动注册,因为Spring不赞成使用@Required注解,对于必须的依赖推荐使用构造器注入
 *
 * @param registry 要操作的注册表
 * @param source   触发此注册的配置源
 * @return 此方法实际注册的所有注解后处理器的 Bean 定义
 */
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {
     
    //获取beanFactory,就是registry自身
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
     
        //设置比较器,可以看到设置的是AnnotationAwareOrderComparator比较器,可以支持PriorityOrdered接口、Ordered接口、@Ordered注解、@Priority注解的排序,比较优先级为PriorityOrdered>Ordered>@Ordered>@Priority
        //后面会学习的OrderComparator 比较器只支持PriorityOrdered、Ordered接口的排序,比较优先级为PriorityOrdered>Ordered
        //如果最终没找到设置的排序值,那么返回Integer.MAX_VALUE,即最低优先级。
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
     
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        //设置一个ContextAnnotationAutowireCandidateResolver,以决定是否应将 Bean 定义视为主动注入的候选项。
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
     
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    /*
     * 如果注册表的beanDefinitionMap缓存中没有"org.springframework.context.annotation.internalConfigurationAnnotationProcessor"为name的缓存
     * 那么创建并且注册一个BeanDefinitionRegistryPostProcessor后处理器的bean定义,用于处理@Configuration注解
     */
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
     
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    /*
     * 如果注册表的beanDefinitionMap缓存中没有"org.springframework.context.annotation.internalAutowiredAnnotationProcessor"为name的缓存
     * 那么创建并且注册一个AutowiredAnnotationBeanPostProcessor后处理器的bean定义,用于处理@Autowired、@Value、@Inject、@Lookup注解
     */
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
     
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    /*
     * 检查 JSR-250 支持,如果存在JSR-250的依赖,并且注册表的beanDefinitionMap缓存中没有"org.springframework.context.annotation.internalCommonAnnotationProcessor"为name的缓存
     * 那么创建并且注册一个CommonAnnotationBeanPostProcessor后处理器的bean定义,用于处理@Resource、@PostConstruct、@PreDestroy、@WebServiceRef、@EJB等注解
     */
    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
     
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    /*
     * 检查 JPA 支持,如果存在JPA的依赖,并且注册表的beanDefinitionMap缓存中没有"org.springframework.context.annotation.internalPersistenceAnnotationProcessor"为name的缓存
     * 那么创建并且注册一个PersistenceAnnotationBeanPostProcessor后处理器的bean定义,用于处理JPA的相关注解,比如@PersistenceContext和@PersistenceUnit
     */
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
     
        RootBeanDefinition def = new RootBeanDefinition();
        try {
     
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                    AnnotationConfigUtils.class.getClassLoader()));
        } catch (ClassNotFoundException ex) {
     
            throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    /*
     * 如果注册表的beanDefinitionMap缓存中没有"org.springframework.context.event.internalEventListenerProcessor"为name的缓存
     * 那么创建并且注册一个EventListenerMethodProcessor后处理器的bean定义,用于处理@EventListener注解
     */
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
     
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }
    /*
     * 如果注册表的beanDefinitionMap缓存中没有"org.springframework.context.event.internalEventListenerFactory"为name的缓存
     * 那么创建并且注册一个DefaultEventListenerFactory后处理器的bean定义,用于为使用@EventListener注解的方法而创建ApplicationListener的策略接口
     */
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
     
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

/**
 1. AnnotationConfigUtils工具类的方法
 2.  3. 注册相关注解后处理器的bean定义到注册表缓存中
 4.  5. @param registry   注册表
 6. @param definition 注解后处理器的bean定义
 7. @param beanName   beanName
 8. @return 当前bean定义的BeanDefinitionHolder
 */
private static BeanDefinitionHolder registerPostProcessor(
        BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
     
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //调用registerBeanDefinition方法注册BeanDefinition到注册表的缓存中,该方法此前已经讲过了
    registry.registerBeanDefinition(beanName, definition);
    //将definition和beanName封装成为一个BeanDefinitionHolder对象并返回
    return new BeanDefinitionHolder(definition, beanName);
}

2.合并beanDefinition

-----------refresh();----------------------
-----------	// 完成beanFactory的初始化(实例化非懒加载的单例bean)
			finishBeanFactoryInitialization(beanFactory);--------------------------
//实例化所有非懒加载的bean,也就是怎么来创建bean
----------beanFactory.preInstantiateSingletons();----------------------------

继承的BeanDefinition

通过扫描得到所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了,但是在Spring中支持父子BeanDefinition,和Java父子类类似,但是完全不是一回事。

在有了beanDefinition之后,会进行一次beanDefinition合并,其意义在于如果一个bean类继承了父类,而父类又设置了一些属性(或者是xml配置文件中的bean标签上设置了属性),那么子类会继承这些属性,

父子BeanDefinition实际用的比较少,使用是这样的,比如:

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>

这么定义的情况下,child是单例Bean。

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>

但是这么定义的情况下,child就是原型Bean了。

因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。child子BeanDefinition没有重写,那么getBean得到也是一个原型,也就是在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition。

//我们来验证获得的userService是不是原型
public class Test {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

		System.out.println(applicationContext.getBean("userService"));
		System.out.println(applicationContext.getBean("userService"));
		System.out.println(applicationContext.getBean("userService"));


	}
}


com.luban.service.UserService@5387f9e0
com.luban.service.UserService@6e5e91e4
com.luban.service.UserService@2cdf8d8a

在走到合并beanDefinition方法之前:

  • userService的scope还是空,而父类parentService是prototype。

3.spring生命周期详解

  • beanDefinitionMap中BeanDefinition是GenericBeanDefinition类型

    3.spring生命周期详解

  • beanDefinitionMap的时候类型是:GenericBeanDefinition,这个可以设置它们的ParentName

    ```java
    @Override
    	public void setParentName(@Nullable String parentName) {
    		this.parentName = parentName;
    	}
    
    	@Override
    	@Nullable
    	public String getParentName() {
    		return this.parentName;
    	}
    
    ```
    

走过合并方法后 :

  • 得到的userService的scope已经变了。

    3.spring生命周期详解

  • 在mergeBeanDefinitions就是RootBeanDefininiton类型,是GenericBeanDefinition合并得到的

3.spring生命周期详解

  • 在合并之后得到的(mergeBeanDefinitions)是RootBeanDefinition,setParentName是时候会报错,就不再又ParentBeanDefinition
@Override
	public String getParentName() {
		return null;
	}

	@Override
	public void setParentName(@Nullable String parentName) {
		if (parentName != null) {
			throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
		}
	}

源码:是怎么样获得RootBeanDefinition

DefaultListableBeanFactory#preInstantiateSingletons()方法 // 实例化所有非懒加载的bean
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}
		// 在spring启动时,就将bean的名字保存起来了
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
		// 循环bd,实例化非懒加载单例bean
		for (String beanName : beanNames) {
			// 对beanDefinition进行合并,基于合并后的BeanDefinition去创建bean
			// 合并是子类合并到父类,才有完整的定义信息
   //-----------------------------------------getMergedLocalBeanDefinition(beanName)-----------------------------
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 非抽象,单例,非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判断是不是一个SmartFactoryBean
				if (isFactoryBean(beanName)) {
					//  如果是一个FactoryBean,那么需要加上前缀
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						// eager:急切的意思,立马初始化
						// smartFactoryBean 有一个接口,isEagerInit,是否立即初始化
						// System.getSecurityManager() 是安全管理器,不用管
						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) {
							// 是立即初始化,就根据beanName去生成FactoryBean中所生成的Bean对象
							getBean(beanName);
						}
					}
				}
				else {
					// 根据beanName去创建bean
					getBean(beanName);
				}
			}
		}

		// 创建完所有的单例bean之后,判断某个单例bean是不是SmartInitializingSingleton,如果是执行afterSingletonsInstantiated()方法
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

AbstractBeanFactory#getMergedLocalBeanDefinition()方法

—————————————–getMergedLocalBeanDefinition(beanName)—————————–

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// 从已合并的容器中取
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null && !mbd.stale) {
			return mbd;
		}
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

AbstractBeanFactory#getMergedBeanDefinition()方法

—————–父bd和子bd进行合并———————————————————

protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {
		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;
			RootBeanDefinition previous = null;

			if (containingBd == null) { // 双重校验,可能mergedBeanDefinitions在上多之前,已经有别的线程 生成了相同的
                // beanName 对应的rootBeanDefinition
				mbd = this.mergedBeanDefinitions.get(beanName);
			}
			// 取不到合并的beanDefinition
			if (mbd == null || mbd.stale) {
				previous = mbd;
				// 如果bd的父bd为空,说明它是个rootBeanDefinition
				if (bd.getParentName() == null) {
					// RootBeanDefinition没有父BeanDefinition
					if (bd instanceof RootBeanDefinition) {
						// 如果bd已经是rootBeanDefinition,就克隆一份返回
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
						// 还不是rootBeanDefinition,就生成一个
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
					// bd存在父类
					BeanDefinition pbd;
					try {
						// 父bd的beanName
						String parentBeanName = transformedBeanName(bd.getParentName());
						if (!beanName.equals(parentBeanName)) {
							// 递归调用,因为父bean 还可能有父bean,所以再次调用合并得到父的beanDefinition
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
							// 一般不会走
							// 到父容器中找对应的bean,然后进行合并,合并也发生在父容器中
							BeanFactory parent = getParentBeanFactory();
							if (parent instanceof ConfigurableBeanFactory) {
								pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
							}
							else {
								// 抛异常 省略。。。
							}
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
//  -----------------父bd和子bd进行合并---------------------------------------------------------
					// pbd表示父BeanDefinition, bd表示本BeanDefinition
					mbd = new RootBeanDefinition(pbd);
					// 基于mbd,将bd属性设置进去,就是合并,这里可以说是覆盖
					mbd.overrideFrom(bd);
				}

				// 如果没有设置scope,就设置默认为singleton
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(SCOPE_SINGLETON);
				}

				// 如果某个<bean/>内包含了一个内部<bean/>,containingBd表示外部bean, mbd表示内部bean
				// 外部bean如果不是单例bean,内部bean是单例的,那么则把内部bean的scope设置为和外部bean的scope一样的
				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				// 将合并后的bd放入到mergedBeanDefinitions这个map中
				// 之后还是可能被清空的,因为bd可能被修改
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			if (previous != null) {
				copyRelevantMergedBeanDefinitionCaches(previous, mbd);
			}
			return mbd;
		}
	}

AbstractBeanFactory#transformedBeanName()方法
//---------------------------------transformedBeanName-----------------------------------
 //这个方法的作用就是 不管你传过来的name:lubanFactoryBean,lubanFactoryBean1(别名),&lubanFactoryBean,一律转化为lubanFactoryBean
	protected String transformedBeanName(String name) {  
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}
    
  
BeanFactoryUtils类的域

private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();

BeanFactoryUtils#transformedBeanName方法

// ------------------BeanFactoryUtils.transformedBeanName(name)------------------
 	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		// 如果beanName没有以&开头,则直接返回
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {   // lubanFactoryBean
			return name;
		}//(1)
		// 如果beanName以&开头,截取&后的beanName,并且把截取前后的name存在transformedBeanNameCache中
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		}); //(2)
	}   
--------------------Map.computeIfAbsent -----------------

// 方法定义
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
    ...
}

// java8之前。从map中根据key获取value操作可能会有下面的操作
Object value = map.get("key");
if (value == null) {
    value = new Object();
    map.put("key", value);
}

// java8之后。上面的操作可以简化为一行,若key对应的value为空,会将第二个参数的返回值存入并返回
Object value2 = map.computeIfAbsent("key", k -> new Object());

  • 假设name = “&lubanFactoryBean”, 那么不会走分支(1),

  • 执行分支(2)即执行下面代码段:

     return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
    			do {
    				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    			}
    			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
    			return beanName;
    		});  
    

看了 给出的示例——————–Map.computeIfAbsent —————– 方法

可以知道 分支(2) 的代码 要做的事情就是 :

如果beanName以&开头,截取&后的beanName,并且把截取前后的name存在transformedBeanNameCache中

此时transformedBeanNameCache 此时内容为:

  • name = “lubanFactoryBean”, value = “lubanFactoryBean”
  • name = “&lubanFactoryBean”,value = “lubanFactoryBean”

此时BeanFactoryUtils.transformedBeanName(name) 返回的是“lubanFactoryBean

简单来说就是 :BeanFactoryUtils#transformedBeanName方法 只返回 “lubanFactoryBean”

回到这个AbstractBeanFactory#transformedBeanName()方法
canonicalName(BeanFactoryUtils.transformedBeanName(name));
	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			resolvedName = this.aliasMap.get(canonicalName);  // 别名:beanName
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

查看此文章我们知道:Spring源码解析(五)-解析alias标签

this.aliasMap.put(alias, name);

aliasMap的key为 lubanFactoryBean1别名,value 为 lubanFactoryBean

此时canonicalName(BeanFactoryUtils.transformedBeanName(name)); 返回的是 lubanFactoryBean

AbstractBeanFactory#transformedBeanName方法 ,这个方法的作用就是 不管你传过来的name:lubanFactoryBean,lubanFactoryBean1(别名),&lubanFactoryBean,一律转化为lubanFactoryBean,因为我要用它来进行获取单例池中的对象(此例:LubanFactoryBean对象)

在这里我们知道不管怎样基于LubanFactoryBean的RootBeanDefinition的beanName只能是lubanFactoryBean,并不会把lubanFactoryBean1(别名),&lubanFactoryBean 作为该RootBeanDefinition 的beanName

3.spring生命周期详解

回到DefaultListableBeanFactory#preInstantiateSingletons()方法 // 实例化所有非懒加载的bean
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}
		// 在spring启动时,就将bean的名字保存起来了
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
		// 循环bd,实例化非懒加载单例bean
		for (String beanName : beanNames) {
			// 对beanDefinition进行合并,基于合并后的BeanDefinition去创建bean
			// 合并是子类合并到父类,才有完整的定义信息
   //-----------------------------------------getMergedLocalBeanDefinition(beanName)-----------------------------
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);  //---------------------------------------(1)
			// 非抽象,单例,非懒加载--
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 
				// 判断是不是一个SmartFactoryBean
				if (isFactoryBean(beanName)) {  // ------------------------------------(2)
					//  如果是一个FactoryBean,那么需要加上前缀
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); // 生成一个FactoryBean
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						// eager:急切的意思,立马初始化
						// smartFactoryBean 有一个接口,isEagerInit,是否立即初始化
						// System.getSecurityManager() 是安全管理器,不用管
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {  
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());//    -------------------------(3)
						}
						if (isEagerInit) {
							// 是立即初始化,就根据beanName去生成FactoryBean中所生成的Bean对象
							getBean(beanName);// ----------------------------------------------(4)
						}
					}
				}
				else {
					// 根据beanName去创建bean
					getBean(beanName);
				}
			}
		}

		// 创建完所有的单例bean之后,判断某个单例bean是不是SmartInitializingSingleton,如果是执行afterSingletonsInstantiated()方法
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}
  1. 首先会获取所有的beanDefinitionNames,然后创建一个副本,避免在使用的时候有改变。

  2. 然后遍历bean名字,如果非抽象,非懒加载的单例实例,如果是FactoryBean的话,就生成一个FactoryBean实例 ,并获取

  3. 如果获取到了这个实例,就判断是否需要立即加载FactoryBean中创建的实例,默认是不创建的,需要的时候创建。

  4. 这里要注意:

    • get(xx)获取FactoryBean实例本身,xx就是是& + beanName,FactoryBean实例本身会放置在singletonObjects中

    • 如果是获取FactoryBean创建的实例(调用FactoryBean实例的getObject()方法),xx就是beanName。而

      根据beanName去获取FactoryBean实例创建的实例(调用FactoryBean实例的getObject()方法生成的对象)

      getObject的user对象(假设FactoryBean实例执行getObject方法生成User对象)会放到容器中就是factoryBeanObjectCache 容器中

    • 如果不是FactoryBean类型的,xx就是beanName。

    如果FactoryBean实例实现了smartFactoryBean ,并且isEagerInit = true,表示立即初始化

    代码段(4)就是执行立即初始化,就根据beanName去获取FactoryBean实例创建的实例(调用FactoryBean实例的getObject()方法生成的对象)

所以FactoryBean相当于是懒加载除非factoryBean是实现了smartFactoryBean 。只有在调用getBean(factoryBeanName)的时候才会调用getObject方法去获取getObject()生成对象

因为beanName是来自于this.beanDefinitionNames,而this.beanDefinitionNames是扫描来的,返回去查看

1.3.1AnnotationBeanNameGenerator#generateBeanName,beanName只能是类LubanFactoryBean的第一个字符小写

lubanFactoryBean

3.spring生命周期详解

getMergedLocalBeanDefinition合并bean意义

其实这个很早就有了,前面没讲,现在讲比较合适。为什么要有这个,不是都有bean定义了么,我想这个可能是为了要统一处理,很多

地方都是获取合并后bean定义的来处理的,因为bean定义可能会被修改,处理的时候又想处理最新的,那就需要将可能修改的bean定义再一次合并成统一的

RootBeanDefinition。因为BeanDefinition有不同的实现类,但是肯定会有一个比较全面的子类,就是RootBeanDefinition,而且他还提供了深拷贝的构造

函数和克隆方法,可以传入其他BeanDefinition子类并创建一个新的RootBeanDefinition来进行属性的深拷贝。

3.spring生命周期详解

3.spring生命周期详解

我们来看这个方法的源码,先从合并的定义中获取,如果发现存在,且不需要合并了就直接返回,否则就进行合并。stale属性表示是否要进行合并,默认是需要的。

	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// Quick check on the concurrent map first, with minimal locking.
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null && !mbd.stale) {//存在且不需要合并的话就直接返回
			return mbd;
		}
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}


什么时候需要设置合并呢

那什么时候stale=true呢,也就是说是需要进行合并,我们来看看,首先是AbstractBeanFactoryclearMergedBeanDefinition

3.spring生命周期详解

那他在哪里被用到呢,

AbstractBeanFactorymarkBeanAsCreated,而且这里注释说了,让他重新合并一下。

所以这个时候要进行修改了BeanDefinition得需要最新的bean定义,所以要进行合并一次,获取到最新的RootBeanDefinition定义:

3.spring生命周期详解

另外一个地方是invokeBeanFactoryPostProcessors的最后:

3.spring生命周期详解

3.spring生命周期详解

3.spring生命周期详解

也就是说BeanFactoryPostProcessor处理器完之后,bean定义可能会有变化,所以我需要重新合并,以保证合并的是最新的

3.FactoryBean实战例子

1.关于spring的FactoryBean的问题:

@Component()
public class LubanFactoryBean implements FactoryBean {

	public Object getObject() throws Exception {
		return new User();
	}

	public Class<?> getObjectType() {
		return User.class;
	}

}


public class Test {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		System.out.println(applicationContext.getBean("lubanFactoryBean"));
		System.out.println(applicationContext.getBean("lubanFactoryBean"));
		System.out.println(applicationContext.getBean("lubanFactoryBean"));


	}
}


com.luban.entity.User@5aaa6d82
com.luban.entity.User@5aaa6d82
com.luban.entity.User@5aaa6d82

问题1:getBean的时候,为什么get的对象对象都是同一个对象呢?

default boolean isSingleton() {
  return true;
}


FactoryBean有一个default方法:isSingleton,默认是单例
那么我们就知道虽然getBean了三次,但是getObject()就只执行了一次

问题2:那么在执行LubanFactoryBean实例的getObject()的时候是在哪一行代码呢

应该是在第一次调用getBean(“lubanFactoryBean”)的时候执行的


AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

我们在启动spring的时候,就会去创建非懒加载的单例bean

我们的LubanFactoryBean上面有一个@Componet,Spring启动的时候就去扫描,并把它当作普通的bean,

new AnnotationConfigApplicationContext(AppConfig.class); 启动会执行refresh(); ———————————-之后会补充spring启动的博客

这段代码执行的时候会执行DefaultListableBeanFactory#preInstantiateSingletons()方法

也就是说3.spring生命周期详解

此时singleObject(单例池中)已经有了TestFactoryBean, singleObject中表现形式为 key=“testFactory”,value = TestFactoryBean的实例

3.spring生命周期详解

问题3:为什么往单例池放数据的时候是LubanFactoryBean,在getBean的时候却是User呢?

答案就是applicationContext.getBean(“lubanFactoryBean”)是从factoryBeanObjectCache r容器中拿对象

而不是从singleObject单例池中拿对象

仔细看看代码

还是回到DefaultListableBeanFactory#preInstantiateSingletons()方法 // 实例化所有非懒加载的bean

DefaultListableBeanFactory#preInstantiateSingletons()

@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}
 
		// 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...
		// 循环bd,实例化单例bean
		for (String beanName : beanNames) {  // userService
			// 对beanDefinition进行合并,基于合并后的BeanDefinition去创建bean
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
 
			// 非抽象,单例,非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
 
				// 判断是不是一个SmartFactoryBean
				if (isFactoryBean(beanName)) {
					//  如果是一个FactoryBean,那么则获取LubanFactoryBean对象
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);// ---------------------------------
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						// eager:急切的意思,立马初始化
						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) {
							// 根据beanName去生成FactoryBean中所生成的Bean对象
							getBean(beanName);
						}
					}
				}
				else {
					// 根据beanName去创建bean
					getBean(beanName);
				}
			}
		}
 
		// 创建完所有的单例bean之后,判断某个单例bean是不是SmartInitializingSingleton,如果是执行afterSingletonsInstantiated()方法
		// EventListenerMethodProcessor
 
		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}
 

AbstractBeanFactory#getBean()

创建bean会进入getBean()方法最终会进入doGetBean方法

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

AbstractBeanFactory#doGetBean()

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
 
		// 对beanName进行转换 name如果是"&lubanFactoryBean",那么beanName就是"lubanFactoryBean"
		final String beanName = transformedBeanName(name);
		Object bean;
 
		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);  // Map<>
		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 + "'");
				}
			}
			// 判断sharedInstance是不是FactoryBean,如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的对象
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
 
		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 原型bean正在创建中
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
 
			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// 当前BeanFactory中不存beanName对象的BeanDefinition,那么则从ParentBeanFactory中去获取
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
 
			// 创建Bean
 
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
 
			try {
				// 得到合并后的BeanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
 
				// Guarantee initialization of beans that the current bean depends on.
				// 加载DependsOn的bean
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						// 判断beanName是不是也被dep依赖了,如果是,就是相互依赖
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 存在在两个map中
						// 1. dependentBeanMap,key为dep, value是一个LinkedHashSet,表示dep被哪些bean依赖了
						// 2. dependenciesForBeanMap,key为beanName,value是一个LinkedHashSet,表示beanName依赖了哪些bean
						registerDependentBean(dep, beanName);
						try {
							// 先去生成所依赖的bean
							getBean(dep); //  getBean("xxx")
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
 
 
				// 根据Scope去创建bean
				// Create bean instance.
				if (mbd.isSingleton()) {
					// 获取单例bean,如果获取不到则创建一个bean,并且放入单例池中
					sharedInstance = getSingleton(beanName, () -> {
						try {
								return createBean(beanName, mbd, args); //-------------------------------------------------here
						}
						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;
						}
					});
					// sharedInstance可能是一个FactoryBean,所以需要单独再去factoryBeanObjectCache中去获取对应的对象
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
 
				else {
					String scopeName = mbd.getScope(); // request, session
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						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);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
 
		// Check if required type matches the type of the actual bean instance.
		// 根据beanName获取到的bean的类型是否和requiredType匹配,如果不配则进行类型转化
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

很明显我们走到的是这里 getSingleton(beanName)!=null = lunbanFactoryBean

// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);  // Map<>
	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 + "'");
			}
		}
		// 判断sharedInstance是不是FactoryBean,如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的对象
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

AbstractBeanFactory#getObjectFromFactoryBean()

方法 AbstractBeanFactory#getObjectForBeanInstance 在 getBean 方法中是个高频用法,在getBean中不论是用什么方式获得的bean,都会执行getObjectForBeanInstance方法。原因是,不论哪种方式获得的bean都是原始的bean状态,并不是我们真正想要的。

这段代码主要功能
1.辅助性检查;
2.进行了子类父类的合并,并把存储xml配置的GernericBeanDefinition转换为RootBeanDefinition;
3.真正核心是调用了getObjectFromFactoryBean这个方法。
代码如下

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.
   // 如果是name = &lubanFactoryBean,那么则直接返回单例池(SingletonObjects)中的对象

   if (BeanFactoryUtils.isFactoryDereference(name)) {
      if (beanInstance instanceof NullBean) {
         return beanInstance;
      }
       // 规定 &lubanFactoryBean 的beanInstance 必须属于FactoryBean
      if (!(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
      }
      // 设置mbd的isFactoryBean
      if (mbd != null) {
         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 .
   if (!(beanInstance instanceof FactoryBean)) { // 普通对象直接返回,name 没有&开头
      return beanInstance;
   }

   // 如果beanInstance是FactoryBean,并且name也不是以&,说明懒加载了 需要获取factoryBean实列getObject()获取的对象
   Object object = null;
   if (mbd != null) {
      mbd.isFactoryBean = true;
   }
   else {
      object = getCachedObjectForFactoryBean(beanName);
   }

   // 从factoryBeanObjectCache中没有拿到则进行创建  ========================前面说过的
   if (object == null) {
      // Return bean instance from factory.
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // Caches object obtained from FactoryBean if it is a singleton.
      // 合成bean
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      // 调用getObject方法得到对象并放入factoryBeanObjectCache中
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}

代码段: // 从factoryBeanObjectCache中没有拿到则进行创建 ========================前面说过的

if (object == null) {
      // Return bean instance from factory.
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // Caches object obtained from FactoryBean if it is a singleton.
      // 合成bean
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      // 调用getObject方法得到对象并放入factoryBeanObjectCache中
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }

这段代码可以看出,核心功能给了doGetObjectFromFactoryBean。
不管是不是单例模式,得到bean实例对象后,都进行了一个后处理postProcessObjectFromFactoryBean,这个以后再细说,现在看下真正的核心代码doGetObjectFromFactoryBean

FactoryBeanRegistrySupport#getObjectFromFactoryBean()

1.主要功能:

  • 首先是是lubanFactroyBean必须已经存在于单例池中 ,(不然我要怎么取出单例池中的lubanFactroyBean,执行getObject()方法得到对象)
  • 执行lubanFactroyBean的方法得到对象User对象

代码阅读:

1.还是存在双重校验模式

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		// 是不是单例的
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				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) {
							// 单例真正创建
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
								// 调用BeanPostProcessor执行初始化后的逻辑,主要就是进行AOP
								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)) {
							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;
		}
	}

FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
	private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final 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 {
				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.
		// 如果调用getObject()方法返回的是null,那么则返回一个NullBean
		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;
	}

3.spring生命周期详解

BeanFactoryUtils#isFactoryDereference()

public static boolean isFactoryDereference(@Nullable String name) {
	return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

3.spring生命周期详解

问题4:FactoryBean用在哪儿呢?

参考

Spring 注解

Spring 5 启动性能优化之 @Indexed

GetBean源码全面解读

Spring 5.x 源码之旅


程序员灯塔
转载请注明原文链接:3.spring生命周期详解
喜欢 (0)