Spring注解版执行流程 ConfigurationClassPostProcessor

Spring注解版执行流程 ConfigurationClassPostProcessor

上一篇文章,我们讲到invokeBeanFactoryPostProcessors方法中执行后置处理器ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法。这篇文章我们一探究竟。这个方法中传入了一个bean定义信息注册对象,结合上下文代码可以看出实际上就是我们工厂对象。
ConfigurationClassPostProcessor类里面的东西非常复杂。不是一篇文章可以讲清楚的。这篇文章并不是我写的,我只是个搬运工。为什么要把别人的东西抄一份呢,是为了防止他的文章如果下架了,我的整个源码流程就不完整了。文章最后贴出他的文章地址。

	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		// 通过工厂对象获取hash值,保证工厂对象没有被加载过,防止重复加载
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);
		// 真正的去加载工厂对象.从名字可以看出,加载配置类的bean定义信息
		processConfigBeanDefinitions(registry);
	}

大致讲一下里面的逻辑,首先获取工厂对象中所有的beanDefinition对象名称。循环遍历,通过名称拿到beanDefinition对象。判断对象中的 Map<String, Object> attributes集合中是否有CONFIGURATION_CLASS_ATTRIBUTE对象,如果有表示该类已经处理成为configuration了,不需要再处理了。否则,判断是否需要处理。

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			// 如果 beanDefinition 中 configurationClass 属性不等于空,那么意味着已经处理过,输出日志信息
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			// 检查是否是一个配置类
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				//如果返回为真,添加到配置类集合中等待后续处理。
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}

进入到检查方法checkConfigurationClassCandidate()里看看。先是获取到beanDefinition中的注解信息metadata。
在这里插入图片描述
通过注解信息判断类上是否有Configuration注解。
如果存在@Configuration 注解并且该注解属性 proxyBeanMethods 配置为 true,默认值就是 true,该属性的含义就是为了注明该类下的 @Bean 方法是否被动态代理拦截实现单例,则标识为 full,将这个配置类标记为全配置类。
否则, isConfigurationCandidate(metadata)方法查看这个类上是否有Component、ComponentScan、Import、ImportResource四个注解其中之一,如果有标记为半配置类。全配置类后期会做一个增强,后面会讲到,现在有一个印象就行。
同时,你会发先标记的方式就是向 attributes集合中添加CONFIGURATION_CLASS_ATTRIBUTE键值对。
在这里插入图片描述
在这里插入图片描述
我们的注解容器中并没有写Configuration注解,而是ComponentScan注解,至于另一个注解和AOP有关,暂不讨论。所以我们的主配置类是一个半配置类“lite”。
在这里插入图片描述
当我们循环遍历完所有的配置类。对配置类进行排序。设置名字解析器、环境对象等参数。


	// Sort by previously determined @Order value, if applicable
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});	
		
	SingletonBeanRegistry sbr = null;
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			// beanName的生成器,因为后面会扫描出所有加入到spring容器中calss类,然后把这些class
			// 解析成BeanDefinition类,此时需要利用BeanNameGenerator为这些BeanDefinition生成beanName
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

创建一个ConfigurationClassParser对象,设置之前赋值的属性参数,等会将用这个类来对配置类进行解析。仔细看这里解析的时候是一个do/while循环,因为如果配置类为空,前面就提前出去了,在第一次配置类解析后可能会有新的配置类需要解析,所有这里需要循环操作。那么我们先看parse方法是如何解析配置类的。

	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	//等待解析的配置类		
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	//已经解析过的配置类
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		// 解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
    	// 注意:这一步只会将加了@Configuration注解以及通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap中
    	// 通过其他注解(例如@Import、@Bean)的方式,在parse()方法这一步并不会将其解析为BeanDefinition放入到BeanDefinitionMap中,而是先解析成ConfigurationClass类
   		// 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的
		parser.parse(candidates);
		...

获取到每一个配置类的BeanDefinition,我们这里的定义信息属于第一种,会走第一个循环,获取到定义信息的元注解信息进行解析。

	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		// 处理延迟importSelector
		this.deferredImportSelectorHandler.process();
	}
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
         // 判断是否需要跳过解析。
         // 基于 @Conditional 标签判断该对象是否要跳过,如果不满足 @Conditional 中 value 中的条件,就跳过该 Bean,不会注入容器
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
        // 第一次进入的时候,configurationClass size 为 0,existingClass 肯定为 null,在此处理 configuration 重复 import
		// 如果同一个配置类被处理两次,两次都属于被 import 则合并导入类返回,如果配置类不是被导入的,则移除旧的使用新的配置类
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
				 // 如果要处理的配置类 configClass 在已经分析处理的配置类记录中已存在,合并两者的importBy属性
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				//明确 bean 定义发现,可能取代了 import,允许移除老的已加载配置类
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// Recursively process the configuration class and its superclass hierarchy.
		// 处理配置类,由于配置类可能存在父类(若父类的全类名是以java开头的,则除外),所有需要将configClass变成sourceClass去解析,然后返回sourceClass的父类。
		// 如果此时父类为空,则不会进行while循环去解析,如果父类不为空,则会循环的去解析父类
		// SourceClass的意义:简单的包装类,目的是为了以统一的方式去处理带有注解的类,不管这些类是如何加载的
		// 如果无法理解,可以把它当做一个黑盒,不会影响看spring源码的主流程
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			// 核心处理逻辑
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
		 // 将解析的配置类存储起来,这样回到parse()方法时,能取到值
		this.configurationClasses.put(configClass, configClass);
	}

真正核心的处理逻辑也是非常长的一段代码,老样子注释写在代码块里。

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
		// 首先判断配置类上是否标注了Component注解
		// 递归处理内部类,因为内部类也是一个配置类,配置类上有 @configuration 注解,
		// 该注解继承 @Component,if 判断为 true,调用 processMemberClasses 方法,递归解析配置类中的内部类
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			// 1.递归处理内部类
			processMemberClasses(configClass, sourceClass, filter);
		}

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

		// Process any @ComponentScan annotations
		//处理 @ComponentScan 或 @ComponentScans 注解,并将扫描包下的所有 bean 转换成填充后的 ConfigurationClass
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				// 3.比如 basePackages = com.lsc, 那么在这一步会扫描出这个包及子包下的 class,然后将其解析成 BeanDefinition
				//BeanDefinition 可以理解为等价于 BeanDefinitionHolder,BeanDefinitionHolder只是比BeanDefinition多一个名字和别名属性
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				//通过上一步扫描包 com.vnjohn,有可能扫描出来的 bean 中可能也添加了 ComponentScan 或 ComponentScans 注解.
				//所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有 ComponentScan、ComponentScans
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 判断是否是一个配置类,并设置 full 或 lite 属性
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						// 通过递归方法进行解析
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// Process any @Import annotations
		// 4.处理 @Import 注解,导入额外的配置类,同时完成具体类的实例化工作,该类型处理也涉及到自动装配的工作
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// Process any @ImportResource annotations
		// 5.处理 @ImportResource 注解
		//处理 @ImportResource 注解,导入 spring 配置文件,通过此方式引入的 xml 文件来通过 IOC 容器注入 Bean 实例对象
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// Process individual @Bean methods
		// 6.处理 @Bean 注解
		// 检索配置类中加了 @Bean 注解的方法,将 @Bean 方法转化为 BeanMethod 对象,保存再集合中
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		// 7.processInterfaces
		processInterfaces(configClass, sourceClass);

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

1.递归处理内部类,processMemberClasses方法。

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

2.处理 @PropertySource 注解,processPropertySource(propertySource)
默认创建的环境对象实例是 StandardEnvironment,它实现了 ConfigurableEnvironment 接口,处理使用 @PropertySource 注解修饰的类。
获取 name、value、encoding 属性,将 value 属性转换为 String[] locations;
对 locations 数组进行遍历,先进行占位符解析工作,如:classpath:myconfig${name}.properties 再转换为 Resource 源对象,最后将其添加至 propertySources 集合中。

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

3.注解工具类解析当前配置类
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName())

  • 这里填充了很多属性,属性有什么用以后还要详细说
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	// 创建对应的扫描类
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
	// 获取 @ComponentScan 参数,并进行参数的设置工作
	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));
	// 获取 scopedProxy 属性
	ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
	if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
		scanner.setScopedProxyMode(scopedProxyMode);
	}
	else {
		Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
		scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
	}
	// 获取 resourcePattern 属性
	scanner.setResourcePattern(componentScan.getString("resourcePattern"));
	// 获取 includeFilters 属性
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addIncludeFilter(typeFilter);
		}
	}
	// 获取 excludeFilters 属性
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addExcludeFilter(typeFilter);
		}
	}
	// 获取 lazyInit 属性
	boolean lazyInit = componentScan.getBoolean("lazyInit");
	if (lazyInit) {
		scanner.getBeanDefinitionDefaults().setLazyInit(true);
	}

	Set<String> basePackages = new LinkedHashSet<>();
	// 获取 basePackages 属性
	String[] basePackagesArray = componentScan.getStringArray("basePackages");
	for (String pkg : basePackagesArray) {
		String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		Collections.addAll(basePackages, tokenized);
	}
	// 获取 basePackageClasses 属性,对全限定类进行包名截取
	for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
		basePackages.add(ClassUtils.getPackageName(clazz));
	}
	if (basePackages.isEmpty()) {
		basePackages.add(ClassUtils.getPackageName(declaringClass));
	}
	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
		@Override
		protected boolean matchClassName(String className) {
			return declaringClass.equals(className);
		}
	});
	// 开始执行扫描,最终的扫描器是 ClassPathBeanDefinitionScanner
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}

3.1componentScanParser真正执行扫描方法scanner.doScan(StringUtils.toStringArray(basePackages))

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

3.1.1先调用 findCandidateComponents(backPackage) 将符合条件的 BeanDefinition(实际是 ScannedGenericBeanDefinition) 找出来【条件1:excludeFilters 不包含,条件2:includeFilters 至少匹配一个,条件三:该类不能是接口或抽象类】
findCandidateComponents->scanCandidateComponents->isCandidateComponent

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

3.1.2处理 BeanDefinition 对象的属性信息,解析 @Scope 注解,设置 scopeName、proxyMode,通过 beanNameGenerator 生成 beanName

3.1.3设置自动装配属性,例如:该 bean 是否可以自动装配到其他 bean 中;

3.1.4AnnotationConfigUtils#processCommonDefinitionAnnotations:处理定义在目标类上的通用注解,包括「@Lazy、@Primary、@DependsOn、@Role、@Description」填充对应的属性进去

3.1.5checkCandidate(beanName, candidate):检查 beanName 是否已经被注册过,如果被注册过考虑其是否与当前类兼容,不兼容就抛出异常,兼容则跳过当前 BeanDefinition 操作;如果未注册过,进行如下操作:

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

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

4.processImports方法。
递归获取被 @Import 注解标注的类,被它标注的类无须加 @Component、@Configuration 等配置注解,否则该 Bean 会被添加两次,但 Spring 会进行合并的工作

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

4.1判断被 @Import 注解标注的类集合是否为空,不为空才进行后续的处理工作,循环遍历每一个配置类,判断它所匹配的类型

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

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

this.deferredImportSelectorHandler.process();

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

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

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

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

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

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

到这里配置类的解析工作就结束了。一个篇抄不下了,下一篇再抄。

文章是这个前辈写的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值