详解Spring注解版 获取所有需要管理的BeanDefinition

注册ConfigurationClassPostProcessor

跟踪AnnotationConfigApplicationContext的构造方法,进入到了下面这个方法

	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

在初始化IOC容器的reader属性时,会调用AnnotationConfigUtils.registerAnnotationConfigProcessors向容器注册所有注解相关的处理器,如下

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		...
		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
		
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			//注册beanDefinition
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
		...
		return beanDefs;
	}

如上代码,该方法向容器中注册了一个名为ConfigurationClassPostProcessor的后置处理器,是一个BeanFactoryPostProcessor,该处理器的beanNameorg.springframework.context.annotation.internalConfigurationAnnotationProcessor,主要用来获取所有的自定义beanDefinition,也是我们这次问题的关键所在。

执行BeanFactoryPostProcessor类型后置处理器

然后走到Spring中最重要的方法refreshConfigurationClassPostProcessor 起作用的地方在其中的invokeBeanFactoryPostProcessors(beanFactory) 方法,这一步骤会执行所有BeanFactoryPostProcessor 其中的方法,如下。

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
			
			...
			
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

		}
	}

因为ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor,所以在执行getBeanNamesForTypeConfigurationClassPostProcessor 会被初始化并放入容器中;getBeanNamesForType 方法会找到所有BeanDefinitionRegistryPostProcessor 类型的Bean并将它们初始化完全后放入容器中。
又因为ConfigurationClassPostProcessor实现了PriorityOrdered接口,所以它的postProcessBeanDefinitionRegistry 会被执行,该方法的功能主要体现在processConfigBeanDefinitions 中调用的parse方法,该方法在ConfigurationClassParser 类上,它实际执行方法是doProcessConfigurationClass,它会解析所有加了@Configuration的类;

调用链如下

ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
	调用了ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
而ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
	调用了	ConfigurationClassParser的parse方法(解析获得所有自定义bean信息)
ConfigurationClassParser的parse方法
	调用了 	ConfigurationClassParser的processConfigurationClass方法
ConfigurationClassParser的processConfigurationClass方法
	调用了ConfigurationClassParser的doProcessConfigurationClass方法

doProcessConfigurationClass代码如下:

	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}

		// Process any @PropertySource annotations
		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
		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
				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
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		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
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

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

		// Process superclass, if any
		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;
	}

上述代码篇幅过长,主要是解析指定标签获取到它们的定义信息。
按顺序主要包括下面这几个功能:

  • 处理@Configuration的匿名内部类;
  • 处理@PropertySource 注解;
  • 处理@ComponentScan 注解,会使用ComponentScanAnnotationParserparse方法扫描获得所有指定目录下的所有BeanDefinitionHolder ,然后在递归的去解析这些类;
  • 处理@Import 注解;
  • 处理@ImportResource注解;
  • 处理 @Bean 方法;
  • 处理Interface上的默认方法;
  • 处理SuperClass

也就是processConfigBeanDefinitions中调用的parse 方法会获取到所有需要管理的Bean定义信息,然后在parse之后得到加载,如下

ConfigurationClassParser parser = new ConfigurationClassParser(...);
parser.parse(candidates); //解析

Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); 

this.reader.loadBeanDefinitions(configClasses);

到此,就已经大致解释清楚了Spring是如何通过注解获取到所有自定义Bean的。

总结

获取所有自定义Bean的功能主要体现ConfigurationClassPostProcessor 这个BeanFactory后置处理器中,它会在被调用执行postProcessBeanDefinitionRegistry 方法时加载所有自定义Bean信息到容器中,而扫描的关键就在于ConfigurationClassParserdoProcessConfigurationClass方法,它通过指定的@Configuration类解析指定的注解。
在Spring Boot中也采用了相似的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值