1.简单的示例:

1 @Configuration2 @EnableConfigurationProperties({DemoProperties.class})3 public classDemoConfiguration {4
5 @Bean6     publicBook getBook(){7        return newBook();8 }9 }

Configuration

1 @Autowired Book book;2
3 @Test4     public voidtestBook(){5 System.out.println(book.toString());6     }

单元测试

结果打印出book对象,证明Book已经被注入到Spring 容器中了。

2.@Configuration配置的bean是如何注入到Spring容器中的呢?

首先先来简单介绍下通过BeanDefinitionRegistry注入bean

1 @Autowired2     public voidregistBeanDefinition(BeanFactory factory){3         if(factory instanceofBeanDefinitionRegistry) {4             BeanDefinitionRegistry registry =(BeanDefinitionRegistry)factory;5             BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Book.class).getBeanDefinition();6             registry.registerBeanDefinition("mybook", beanDefinition);7 }8     }

View Code

1     @Autowired @Qualifier("mybook") Book book2;2 @Test3     public voidtestBook2(){4 System.out.println(book2);5     }

单元测试

结果同样打印出book对象,这里,笔者将beanFactory强转为BenDefinitionRegistry,因为笔者的Demo中使用的是默认BeanFactory,----DefaultListableBeanFactory,他实现了BeanDefinitionRegistry接口。

3.入口,下图为ApplicaitonContext refresh方法的简化,只保留了BeandefinitionRegistry注册bean部分功能。

然,似乎并没什么用?此处会调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法。要解决的一个问题是,BeanDefinitionRegistryPostProcessor类型的bean是如何注入的。以SpringBoot初始化为例。

注意到,ApplicationContext的构造方法:

1 publicAnnotationConfigEmbeddedWebApplicationContext() {2         this.reader = new AnnotatedBeanDefinitionReader(this);3         this.scanner = new ClassPathBeanDefinitionScanner(this);4     }

ApplicationContext构造

1 publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {2         this(registry, getOrCreateEnvironment(registry));3     }

View Code

1     publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");3         Assert.notNull(environment, "Environment must not be null");4         this.registry =registry;5         this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);6         AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);7     }

View Code

1     public static Set<BeanDefinitionHolder>registerAnnotationConfigProcessors(2 BeanDefinitionRegistry registry, Object source) {3
4         DefaultListableBeanFactory beanFactory =unwrapDefaultListableBeanFactory(registry);5         if (beanFactory != null) {6             if (!(beanFactory.getDependencyComparator() instanceofAnnotationAwareOrderComparator)) {7 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);8 }9             if (!(beanFactory.getAutowireCandidateResolver() instanceofContextAnnotationAutowireCandidateResolver)) {10                 beanFactory.setAutowireCandidateResolver(newContextAnnotationAutowireCandidateResolver());11 }12 }13
14         Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);15                 //注解@Configuration处理
16         if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {17             RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);18 def.setSource(source);19 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));20 }21
22         .......//省略部分代码
23
24         returnbeanDefs;25     }

View Code

注意到对@Configuration的处理为ConfigurationClassPostProcessor。

注意到ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,显然关键方法为postProcessBeanDefinitionRegistry。ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry会调用ConfirgurationClassParser的parse方法。会依次解析注解,我们一步一步查看对各个注解的解析。

(1)@PropertySources和@PropertySource  

1 @Target(ElementType.TYPE)2 @Retention(RetentionPolicy.RUNTIME)3 @Documented4 public @interfacePropertySources {5
6 PropertySource[] value();7
8 }

PropertySources定义

最终都是处理@PropertySource,@PropertySources仅仅只是包含多个@PropertySource,@PropertySource注解的主要功能是引入配置文件,将配置的属性键值对与环境变量中的配置合并。其中最关键的类为MutablePropertySources

1 public class MutablePropertySources implementsPropertySources {2
3     private finalLog logger;4
5     private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();6 ......7 }

View Code

显然MutablePropertySources中包含有一个PropertySource列表。MutablePropertySources仅仅是封装了迭代器功能。可以理解成PropertySources是PropertySource的集合,增加了常用的集合操作。

(2)@ComponentScan

定义自动扫描的包。简化的序列图如下:

其最关键的方法为doScan方法,会注册BeanDefinition到容器中。

1     protected Set<BeanDefinitionHolder>doScan(String... basePackages) {2         Assert.notEmpty(basePackages, "At least one base package must be specified");3         Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();4         for(String basePackage : basePackages) {5             Set<BeanDefinition> candidates =findCandidateComponents(basePackage);6             for(BeanDefinition candidate : candidates) {7                 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);8 candidate.setScope(scopeMetadata.getScopeName());9                 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);10                 if (candidate instanceofAbstractBeanDefinition) {11 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);12 }13                 if (candidate instanceofAnnotatedBeanDefinition) {14 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);15 }16                 if(checkCandidate(beanName, candidate)) {17                     BeanDefinitionHolder definitionHolder = newBeanDefinitionHolder(candidate, beanName);18                     definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);19 beanDefinitions.add(definitionHolder);20                     registerBeanDefinition(definitionHolder, this.registry);21 }22 }23 }24         returnbeanDefinitions;25     }

doScan方法

registerBeanDefinition(definitionHolder, this.registry);能说明一切。

(3)@Import

@Import注解可以配置需要引入的class(假设配置为A,可以是数组),有三种方式。其流程图如下:

如果A为ImportSelector的子类,调用selectImports()方法,返回class类名数组,循环解析每一个import的类,如果A为BeanDefinitionRegistrar则直接调用registerBeanDefinition直接注入bean到容器中。如果A为普通的类(非前面提到的两种类型),则将A当做@Configuration配置的类,重新解析Configuration.

(4)@ImportSource

主要功能为引入资源文件。

(5)@Bean,比较简单,童FactoryMethod一样

1         //Process individual @Bean methods
2         Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());3         for(MethodMetadata methodMetadata : beanMethods) {4             configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));5 }6
7         //Process default methods on interfaces
8         for(SourceClass ifc : sourceClass.getInterfaces()) {9             beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());10             for(MethodMetadata methodMetadata : beanMethods) {11                 if (!methodMetadata.isAbstract()) {12                     //A default method or other concrete method on a Java 8+ interface...
13                     configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));14 }15 }16         }

@Bean解析

最后真实加载beanDefinition是loadBeanDefinitionsForConfigurationClass方法:

1     private voidloadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,2 TrackedConditionEvaluator trackedConditionEvaluator) {3
4         if(trackedConditionEvaluator.shouldSkip(configClass)) {5             String beanName =configClass.getBeanName();6             if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {7                 this.registry.removeBeanDefinition(beanName);8 }9             this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());10             return;11 }12
13         if(configClass.isImported()) {14 registerBeanDefinitionForImportedConfigurationClass(configClass);15 }16         for(BeanMethod beanMethod : configClass.getBeanMethods()) {17 loadBeanDefinitionsForBeanMethod(beanMethod);18 }19 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());20 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());21     }

View Code

转载于:https://www.cnblogs.com/dragonfei/p/5925114.html

Spring之@Configuration配置解析相关推荐

  1. Spring的@Configuration配置类-Full和Lite模式

    前言 各位小伙伴大家好,我是A哥.这是一篇"插队"进来的文章,源于我公众号下面的这句评论: 官方管这两种模式分别叫:Full @Configuration和lite @Bean m ...

  2. 【Spring实战】----Spring事务管理配置解析

    上篇说了aop的配置,并且说了Spring事务管理是基于aop的,那么Spring声明式事务的配置就有两种方式:XML配置及注解配置 不多说,直接看配置文件 一.配置文件 applicationCon ...

  3. spring.profiles.active配置解析、

    1.在配置springcloud 时候.不了解spring.profiles.active 有什么作用.看看文档去了只有. > 查看官方文档: 2.1 Environment Repositor ...

  4. Spring Boot:(六)默认日志logback配置解析

    Spring Boot:(六)默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日 ...

  5. spring boot 源码解析15-spring mvc零配置

    前言 spring boot 是基于spring 4 的基础上的一个框架,spring 4 有一个新特效–>基于java config 实现零配置.而在企业的实际工作中,spring 都是和sp ...

  6. 【Spring Boot实战】源码解析Spring Boot自动配置原理

    一.简介 Spring致力于让Java开发更简单,SpringBoot致力于让使用Spring进行Java开发更简单,SpringCloud致力于基于SpringBoot构建微服务生态圈,让微服务开发 ...

  7. 【Spring框架家族】Spring Cloud Eureka 之常用配置解析(转载)

    1. 配置项解析 1.1 通用配置 # 应用名称,将会显示在Eureka界面的应用名称列 spring.application.name=config-service# 应用端口,Eureka服务端默 ...

  8. 使用@Configuration注解来代替Spring的bean配置

    下面是一个典型的Spring配置文件(application-config.xml): 1 2 3 4 5 6 7 8 <beans>          <bean id=" ...

  9. spring多个视图解析器_在Spring中配置多个View解析器

    spring多个视图解析器 1.简介 在Spring中,提供了View Resolver来使用模型中可用的数据来解析视图,而无需与JSP,Velocity或Thymeleaf等View技术紧密绑定. ...

最新文章

  1. Qt 在Label上面绘制罗盘
  2. Machine Learning week 7 quiz: Unsupervised Learning
  3. 释疑の函数POPUP_TO_CONFIRM
  4. linux分区转换gpt命令,Linux中磁盘如何转换GPT格式
  5. 为什么多个线程不可能同时抢到一把锁_HFL Redis_12_redis分布式锁的3种实现方式...
  6. Ubuntu 12.04.1 mysql从5.5升级到5.6
  7. 微信小程序和百度的语音识别接口详解
  8. Knowledge Graph - NLP
  9. 软件开发模式之敏捷开发模型,应用之DevOps
  10. C语言输出图形:宝塔形(三角形)字母。第一行A,第二行BB,第三行CCC……
  11. 第一讲 数系发展史纲
  12. 理解Python中的RingBuffer环形缓冲区
  13. python全栈开发第一天(HTML认识,HTML常用标签)
  14. 【python gensim使用】word2vec词向量处理英文语料
  15. 4/6 深搜、广搜专题+二分答案+单调队列
  16. python输出多行数据合并_pandas之多行按类合并为一行
  17. windows server中opencv运行过程中MF.dll/MFReadWrite.dll/MFPlat.DLL文件丢失问题解决
  18. 同一局域网、不同局域网共享和连接打印机设置
  19. iterm配置alias
  20. 得到-薛兆丰的北大经济学课-0-目录

热门文章

  1. Linux如何切换图形界面和命令行界面
  2. springboot开启gzip压缩(springboot 1.3以上适用)
  3. Linux下安装golang
  4. java去掉的行_Java实现去掉每行的行号
  5. 27.将 VMware 服务器上的虚拟机备份到 Azure(上)
  6. Hyperledger Fabric服务器配置及修改Docker容器卷宗存储根目录/位置
  7. rocketmq学习杂记
  8. ASP.NET性能监控和优化入门
  9. bzoj15523506 robotic sort
  10. 轻量级java web实践-6(框架源码-4)