引入
在使用SpringBoot开发时,最常用的注解有@Component、@Service、@Controller、@Configuration等。当类使用这些注解标记时,类会被Spring IOC容器管理,包括创建,填充属性和实例化。
但是Spring容器如何发现并将这些类放到容器进行管理呢?
今天这篇博客主要分析Spring如何处理@Configuration注解。
@Configuration定义
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Component
- public @interface Configuration {
- @AliasFor(annotation = Component.class)
- String value() default "";
-
- //Since: 5.2
- boolean proxyBeanMethods() default true;
- //Since: 6.0
- boolean enforceUniqueMethods() default true;
- }
复制代码 看Configuration注解的定义,它本质也是一个@Component注解。
所以,标记有@Configuration注解的类在Spring注册bean的第一阶段就会被注册到容器中,但是使用@Configuration注解的类内部的其他bean并没有被注册到容器中。
想知道@Configuration注解被如何处理,需要看invokeBeanFactoryPostProcessors 方法。
ConfigurationClassPostProcessor处理@Configuration注解
先大致说一下invokeBeanFactoryPostProcessors 方法的基本流程,因为这个方法会处理所有BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的子类:
- 先处理方法入参:beanFactoryPostProcessors(如果只是分析AnnotationConfigApplicationContext,这个参数是空的。只有在分析SpringBoot的启动过程时,这个参数才会有值)
- 再处理BeanDefinitionRegistryPostProcessor的子类
- 这里最重要的一件事情是调用ConfigurationClassPostProcessor的processConfigBeanDefinitions方法。
- 最后处理BeanFactoryPostProcessor的子类
invokeBeanFactoryPostProcessors 的部分代码:- public static void invokeBeanFactoryPostProcessors(
- ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
-
- Set<String> processedBeans = new HashSet<>();
- if (beanFactory instanceof BeanDefinitionRegistry) {
- //省略部分代码,处理入参:beanFactoryPostProcessors
- //开始处理BeanDefinitionRegistryPostProcessor接口的子类
- //保存所有符合的子类,即实现BeanDefinitionRegistryPostProcessor,同样实现PriorityOrdered
- List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
- 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);
- //调用currentRegistryProcessors中所有的BDRPP
- invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
- currentRegistryProcessors.clear();
- //省略部分代码,同样处理BeanDefinitionRegistryPostProcessor接口的子类
- }
- else {
- //省略部分代码
- }
- //省略部分代码 处理BeanFactoryPostProcessor接口的子类
- }
复制代码 以上是invokeBeanFactoryPostProcessors的部分代码,接下来看ConfigurationClassPostProcessor的processConfigBeanDefinitions方法,在这个方法里开始正式地处理@Configruation注解:- public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
- List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
- String[] candidateNames = registry.getBeanDefinitionNames();
- //遍历所有的候选者
- for (String beanName : candidateNames) {
- BeanDefinition beanDef = registry.getBeanDefinition(beanName);
- if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
- if (logger.isDebugEnabled()) {
- logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
- }
- }
- //校验候选者类上是否使用了@Configuration注解
- else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
- configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
- }
- }
- //如果configCandidates为空,则立即返回
- if (configCandidates.isEmpty()) {
- return;
- }
- 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) {
- BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
- AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
- if (generator != null) {
- this.componentScanBeanNameGenerator = generator;
- this.importBeanNameGenerator = generator;
- }
- }
- }
- 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 {
- StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
- //开始解析候选类
- parser.parse(candidates);
- parser.validate();
- Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
- configClasses.removeAll(alreadyParsed);
- // Read the model and create bean definitions based on its content
- if (this.reader == null) {
- this.reader = new ConfigurationClassBeanDefinitionReader(
- registry, this.sourceExtractor, this.resourceLoader, this.environment,
- this.importBeanNameGenerator, parser.getImportRegistry());
- }
- //注册解析后的类到容器中
- this.reader.loadBeanDefinitions(configClasses);
- alreadyParsed.addAll(configClasses);
- processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
- candidates.clear();
- if (registry.getBeanDefinitionCount() > candidateNames.length) {
- String[] newCandidateNames = registry.getBeanDefinitionNames();
- Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
- Set<String> alreadyParsedClasses = new HashSet<>();
- for (ConfigurationClass configurationClass : alreadyParsed) {
- alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
- }
- for (String candidateName : newCandidateNames) {
- if (!oldCandidateNames.contains(candidateName)) {
- BeanDefinition bd = registry.getBeanDefinition(candidateName);
- if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
- !alreadyParsedClasses.contains(bd.getBeanClassName())) {
- candidates.add(new BeanDefinitionHolder(bd, candidateName));
- }
- }
- }
- candidateNames = newCandidateNames;
- }
- }
- while (!candidates.isEmpty());
- // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
- if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
- sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
- }
- if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
- // Clear cache in externally provided MetadataReaderFactory; this is a no-op
- // for a shared cache since it'll be cleared by the ApplicationContext.
- ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
- }
- }
复制代码 这个方法的关键点:
- 找到所有要解析的类
- 创建一个解析者
- 开始解析类
- 记住,这里只是解析,也就是确认所有需要处理的类或者方法,这些类或者方法最终也会注册到容器中
- 注册解析后的类到容器中:this.reader.loadBeanDefinitions(configClasses);
解析
那么实际上如何解析呢?- protected final SourceClass doProcessConfigurationClass(
- ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
- throws IOException {
- //1. 判断当前类是否有内部类,如果有内部类是否使用了@Configuration注解,如果使用了该注解,那么需要先处理内部类的配置
- //存在这种可能,但是实际开发中很少使用
- if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
- processMemberClasses(configClass, sourceClass, filter);
- }
- // 处理@PropertySource注解
- for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
- sourceClass.getMetadata(), PropertySources.class,
- org.springframework.context.annotation.PropertySource.class)) {
- if (this.environment instanceof ConfigurableEnvironment) {
- processPropertySource(propertySource);
- }
- else {
- logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
- "]. Reason: Environment must implement ConfigurableEnvironment");
- }
- }
- // 处理@ComponentScan注解
- 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) {
- Set<BeanDefinitionHolder> scannedBeanDefinitions =
- this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
- 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());
- }
- }
- }
- }
- // 处理@Import注解
- processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
- // 处理@ImportResource注解
- 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);
- }
- }
- // 处理使用了@Bean的方法
- 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;
- }
复制代码 processImports方法主要处理两种情况:
- 实现ImportSelector接口的类
- 实现ImportBeanDefinitionRegistrar接口的类
但是需要注意,这个方法只是把这些类放到了集合中,但是还没有开始处理。
下面开始看如何处理使用@Bean的方法- @Configuration
- @Import(MyBeanFactoryPostProcessor.class)
- public class JavaConfig {
- @Bean
- public Country country() {
- return new Country();
- }
- }
复制代码 最后返回所有需要处理的方法。
注册
- public class MyBeanFactoryPostProcessor implements ImportBeanDefinitionRegistrar {
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
- ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry, importBeanNameGenerator);
- RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
- rootBeanDefinition.setBeanClass(Person.class);
- registry.registerBeanDefinition("person", rootBeanDefinition);
- }
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |