Spring component-scan源码分析(二) -- @Configuration注解处理

上篇文章Spring component-scan源码分析(一) – XML解析分析了Spring解析<context:component-scan …/>标签时,把扫描到的合适的类封装成BeanDefinition加入Sping容器中,本篇分析Spring如何解析带相关注解的类。

从AnnotationConfigUtils的registerAnnotationConfigProcessors静态方法入手

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			//设置成ContextAnnotationAutowireCandidateResolver类型的
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
		//注册ConfigurationClassPostProcessor类,解析@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));
		}
		//注册AutowiredAnnotationBeanPostProcessor类
		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));
		}

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		//是否支持JSR-250
		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));
		}

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		//是否支持JPA
		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));
		}
		//注册EventListenerMethodProcessor类
		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));
		}
		//注册DefaultEventListenerFactory类
		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;
	}

该方法想Spring容器注册了一些处理器,用于处理配置、注入等注解的处理

ConfigurationClassPostProcessor类

ConfigurationClassPostProcessor

可以看到,ConfigurationClassPostProcessor类实现了BeanDefinitionRegistryPostProcessor、PriorityOrdered这两个接口。

(1). Spring在把所有bean解析封装成BeanDefinition装进容器后,在bean实例化之前,会实例化实现BeanDefinitionRegistryPostProcessor接口的bean,调用其postProcessBeanDefinitionRegistry方法,最后再调用BeanDefinitionRegistryPostProcessor接口的父类接口BeanFactoryPostProcessor接口的postProcessBeanFactory方法。这样bean可以在这两个方法中对容器中的bean属性进行一些处理。
(2). 实现PriorityOrdered接口有最高优先级,会优先实例化调用这样的BeanDefinitionRegistryPostProcessor,它比Ordered接口优先级高,而实现Ordered接口又比没实现这两个接口的优先级高

1 postProcessBeanDefinitionRegistry方法

	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		...防止重复的处理
		//记录处理过的registry
		this.registriesPostProcessed.add(registryId);
		//开始寻找符合的配置类
		processConfigBeanDefinitions(registry);
	}

processConfigBeanDefinitions方法开始处理@Configuration配置类

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

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				//已经处理过了,处理过的bean会在其BeanDefinition中添加一个属性作为标志
				...省略log
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				//带有@Configuration注解或带有@Component、@ComponentScan、@Import、@ImportResource的注解或有带@Bean的方法的类加入候选集合
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		//没有候选的配置类,那不用处理了,收工
		if (configCandidates.isEmpty()) {
			return;
		}

		..省略@Order注解排序

		...省略名字生成器处理

		//environment没被赋值就新建一个StandardEnvironment
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}
		//用于解析带@Configuration参数的类
		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 {
			//【标记1】开始解析
			parser.parse(candidates);
			//验证解析得到的@Configuration类,由于CGLib的限制,类不能是final,并且@Bean方法要能被覆盖
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);
			//reader是负责注册beanDef进spring容器
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			//【标记2】开始向容器注册BeanDefinition
			this.reader.loadBeanDefinitions(configClasses);
			//加入已解析过的缓存中
			alreadyParsed.addAll(configClasses);
			//清空解析过的候选类
			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				//进入这里,说明解析过程中,容器中新增了一些BeanDefinition
				...
				//一系列操作,提取出新的没解析的类赋值给candidates,循环再次解析
			}
		}
		while (!candidates.isEmpty());

		//注册ImportRegistry,用于处理ImportAware接口
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		...省略清理metadataReaderFactory的缓存
	}

该方法代码很多,但逻辑还是清楚,主要从registry中筛选出@Configuration配置类进行解析,最后在把这些类封装成BeanDefinition加入Spring容器。

核心代码是parser.parse(candidates)和this.reader.loadBeanDefinitions(configClasses);

【标记1】开始解析

	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		this.deferredImportSelectors = new LinkedList<>();

		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				//会进入该if
				if (bd instanceof AnnotatedBeanDefinition) {
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				...
			}
			catch ...
		}
		//处理需要延迟引入的配置
		processDeferredImportSelectors();
	}

	protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
		//把类的元数据和beanName封装成ConfigurationClass
		processConfigurationClass(new ConfigurationClass(metadata, beanName));
	}

在上篇文章Spring component-scan源码分析(一) – XML解析可以知道扫描带有@Component注解的类会封装成ScannedGenericBeanDefinition放入Spring容器。
ScannedGenericBeanDefinition

可以看到ScannedGenericBeanDefinition是实现了AnnotatedBeanDefinition接口的

	protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		//处理@Conditional注解
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;//跳过(即不满足条件)的话,直接返回
		}
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {//已经解析过
			if (configClass.isImported()) {//是被引入的
				if (existingClass.isImported()) {//旧的类也是被引入的
					existingClass.mergeImportedBy(configClass);//更新合并引入它配置类
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				//否则就把旧的从解析缓存中移除,也从父类缓存中移除
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}
		//把configClass又封装成SourceClass类型
		SourceClass sourceClass = asSourceClass(configClass);
		//会循环解析直到没有符合的父类
		do {
			//解析@Configuration配置类
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);
		//解析完装入缓存
		this.configurationClasses.put(configClass, configClass);
	}

前半部分代码会看不懂,先看doProcessConfigurationClass方法再回来看就明白了

	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
		//是否有@Component注解
		if (sourceClass.getMetadata().isAnnotated(Component.class.getName())) {
			//处理成员内部类
			processMemberClasses(configClass, sourceClass);
		}

		// 处理@PropertySource注解
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			//StandardEnvironment实现了ConfigurableEnvironment接口
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				...省略log
			}
		}
		...省略处理@ComponentScans@ComponentScan注解,和处理XML配置处理差不多

		//处理@Import注解(用于引入其他配置类)
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		//处理@ImportResource注解(用于引入其他XML配置或.groovy文件配置)
		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) {
				//处理${xxx}的情况
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				//把资源加入当前解析类的缓存中
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		//拿到带@Bean注解的方法,而且顺序是和类中的源代码一致
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			//封装成BeanMethod,加入当前解析类缓存中
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		//处理实现接口中的带@Bean的默认方法(java8新增的default关键字)
		processInterfaces(configClass, sourceClass);

		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				//返回父类继续解析
				return sourceClass.getSuperClass();
			}
		}
		//解析完成
		return null;
	}

解析步骤:
1、如果有@Component注解,先解析成员内部类;
2、处理@PropertySource注解;
3、处理@ComponentScans、@ComponentScan注解,和处理XML配置<context:component-scan …/>差不多;
4、处理@Import注解(用于引入其他配置类),其中涉及ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar接口的处理;
5、处理@ImportResource注解(用于引入其他XML配置或.groovy文件配置);
6、处理带@Bean注解的方法;
7、处理实现接口中的带@Bean的默认方法(java8新增的default关键字);
8、如果有父类,且不是java原生类,且还没解析过,就继续解析父类

上面对带@Configuration注解的类解析了一遍,解析的结果信息都放在封装的ConfigurationClass里,接下来就是向Spring容器注册BeanDefinition了

【标记2】开始向容器注册BeanDefinition

	public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		//遍历解析好的ConfigurationClass
		for (ConfigurationClass configClass : configurationModel) {
			//真正注册逻辑在这
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

	private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			//进入这里说明要跳过该配置类
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);//从容器中移除该bean名字
			}
			//再从解析@Import得到的缓存中移除当前类
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		if (configClass.isImported()) {
			//把当前的@Configuration类解析封装成AnnotatedGenericBeanDefinition,加入spring容器
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			//解析加载带@Bean注解的方法,会封装成ConfigurationClassBeanDefinition或RootBeanDefinition(代理模式的情况下)放入Spring容器
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
		//加载@ImportResource注解配置文件的bean,这就涉及到XML解析了
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		//调用实现ImportBeanDefinitionRegistrar接口的对象的registerBeanDefinitions方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

注册一个带@Configuration注解的bean的流程:
1、 先注册自身类
2、 注册解析到的带@Bean注解的方法中的bean
3、 注册@ImportResource注解配置文件的bean
4、 调用实现ImportBeanDefinitionRegistrar接口的对象的registerBeanDefinitions方法,对Spring容器做更多的操作


上面对postProcessBeanDefinitionRegistry方法分析告一段落,接着分析跟随其后被Spring调用的postProcessBeanFactory方法

2 postProcessBeanFactory方法

   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   	int factoryId = System.identityHashCode(beanFactory);
   	...防止重复的处理
   	//判断是否解析过
   	if (!this.registriesPostProcessed.contains(factoryId)) {
   		//这个方法上面分析过
   		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
   	}
   	//对解析好的@Configuration类进行CGLib代理,代理类会实现EnhancedConfiguration接口
   	enhanceConfigurationClasses(beanFactory);
   	//做了两件事:
   	// (1)、对EnhancedConfiguration类型的bean调用其BeanFactoryAware接口的setBeanFactory方法
   	// (2)、处理实现ImportAware接口的类
   	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
   }

该方法主要是对没处理过的BeanDefinitionRegistry进行处理,然后就是对解析好的@Configuration类进行CGLib代理,最后就是添加一个后置处理器ImportAwareBeanPostProcessor。

总结

Spring通过遍历容器得到配置类,处理他们的相关注解,向容器中注册更多的bean,最后再用CGLib代理技术代理配置类以达到管理bean生命周期的目的。

PS:
想着控制篇幅,更多展开分析的代码就不贴了。

猜你喜欢

转载自blog.csdn.net/seasonLai/article/details/83039131