前言

spring Boot中引入了自动配置,让开发者利用起来更加的简便、快捷,本篇讲利用RabbitMQ的自动配置为例讲分析下Spring Boot中的自动配置原理。

在上一篇末尾讲述了Spring Boot 默认情况下会为ConnectionFactory、RabbitTemplate等bean,在前面的文章中也讲到嵌入的Tomcat默认配置为8080端口

这些都属于Spring Boot自动配置的范畴,当然其自动配置相当多。

EnableAutoConfiguration注解

在创建Application时我们使用了SpringBootApplication注解,在spring boot实战(第九篇)Application创建源码分析中曾有所分析,再来看下其定义:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @Configuration
  6. @EnableAutoConfiguration
  7. @ComponentScan
  8. public @interface SpringBootApplication {  
  9. Class<?>[] exclude() default {};
  10. }

该注解上存在元注解@EnableAutoConfiguration,这就是Spring Boot自动配置实现的核心入口;其定义为:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @Import({ EnableAutoConfigurationImportSelector.class,
  6. AutoConfigurationPackages.Registrar.class })
  7. public @interface EnableAutoConfiguration {
  8. /**
  9. * Exclude specific auto-configuration classes such that they will never be applied.
  10. * @return the classes to exclude
  11. */
  12. Class<?>[] exclude() default {};
  13. }

很显然能看出有一特殊的注解@Import,该注解在spring boot实战(第十篇)Spring boot Bean加载源码分析中有讲解到,加载bean时会解析Import注解,因此需要讲目光聚集在这段代码

  1. @Import({ EnableAutoConfigurationImportSelector.class,
  2. AutoConfigurationPackages.Registrar.class })

EnableAutoConfigurationImportSelector

来看EnableAutoConfigurationImportSelector类

  1. public String[] selectImports(AnnotationMetadata metadata) {
  2. try {
  3. AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
  4. .getAnnotationAttributes(EnableAutoConfiguration.class.getName(),
  5. true));
  6. Assert.notNull(attributes, "No auto-configuration attributes found. Is "
  7. + metadata.getClassName()
  8. + " annotated with @EnableAutoConfiguration?");
  9. // Find all possible auto configuration classes, filtering duplicates
  10. List<String> factories = new ArrayList<String>(new LinkedHashSet<String>(
  11. SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
  12. this.beanClassLoader)));
  13. // Remove those specifically disabled
  14. factories.removeAll(Arrays.asList(attributes.getStringArray("exclude")));
  15. // Sort
  16. factories = new AutoConfigurationSorter(this.resourceLoader)
  17. .getInPriorityOrder(factories);
  18. return factories.toArray(new String[factories.size()]);
  19. }
  20. catch (IOException ex) {
  21. throw new IllegalStateException(ex);
  22. }
  23. }

看如下代码,获取类路径下spring.factories下key为EnableAutoConfiguration全限定名对应值

  1. SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
  2. this.beanClassLoader))

其结果为:

  1. # Auto Configure
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  3. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  5. org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
  6. org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  8. org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
  9. org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
  10. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
  11. org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
  12. org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
  13. org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
  14. org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
  15. org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
  16. org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
  17. org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
  18. org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
  19. org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
  20. org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
  21. org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  22. org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
  23. org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
  24. org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
  25. org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
  26. org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
  27. org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
  28. org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
  29. org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\
  30. org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration,\
  31. org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration,\
  32. org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfiguration,\
  33. org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
  34. org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
  35. org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
  36. org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
  37. org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
  38. org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
  39. org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
  40. org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
  41. org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
  42. org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration,\
  43. org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
  44. org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
  45. org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
  46. org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
  47. org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
  48. org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
  49. org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
  50. org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
  51. org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
  52. org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
  53. org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
  54. org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\
  55. org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
  56. org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
  57. org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
  58. org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
  59. org.springframework.boot.autoconfigure.web.GzipFilterAutoConfiguration,\
  60. org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
  61. org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
  62. org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
  63. org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
  64. org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
  65. org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration

以上为Spring Boot中所有的自动配置相关类;在启动过程中会解析对应类配置信息,以RabbitMQ为例,则会去解析RabbitAutoConfiguration

RabbitAutoConfiguration

首先来看RabbitAutoConfiguration类上的注解:

 

  1. @Configuration
  2. @ConditionalOnClass({ RabbitTemplate.class, Channel.class })
  3. @EnableConfigurationProperties(RabbitProperties.class)
  4. @Import(RabbitAnnotationDrivenConfiguration.class)
  5. public class RabbitAutoConfiguration {
  • @Configuration: 应该不需要解释
  • @ConditionalOnClass:表示存在对应的Class文件时才会去解析RabbitAutoConfiguration,否则直接跳过不解析,这也是为什么在不导入RabbitMQ依赖Jar时工程能正常启动的原因

  • @EnableConfigurationProperties:表示对@ConfigurationProperties的内嵌支持,默认会将对应Class这是为bean,例如这里值为RabbitProperties.class,其定义为:

  1. @ConfigurationProperties(prefix = "spring.rabbitmq")
  2. public class RabbitProperties {
  3. /**
  4. * RabbitMQ host.
  5. */
  6. private String host = "localhost";
  7. /**
  8. * RabbitMQ port.
  9. */
  10. private int port = 5672;   .... //省略部分代码}

RabbitProperties提供对RabbitMQ的配置信息,其前缀为spring.rabbitmq,因此在上篇中配置的host、port等信息会配置到该类上,随后@EnableConfigurationProperties会将RabbitProperties注册为一个bean。

 
  • @Import为导入配置,RabbitAnnotationDrivenConfiguration具体实现如下:
  1. @Configuration
  2. @ConditionalOnClass(EnableRabbit.class)
  3. class RabbitAnnotationDrivenConfiguration {
  4. @Autowired(required = false)
  5. private PlatformTransactionManager transactionManager;
  6. @Bean
  7. @ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
  8. public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
  9. ConnectionFactory connectionFactory) {
  10. SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
  11. factory.setConnectionFactory(connectionFactory);
  12. if (this.transactionManager != null) {
  13. factory.setTransactionManager(this.transactionManager);
  14. }
  15. return factory;
  16. }
  17. @EnableRabbit
  18. @ConditionalOnMissingBean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
  19. protected static class EnableRabbitConfiguration {
  20. }
  21. }

这里又涉及到一个重要的注解:@ConditionalOnMissingBean,其功能为如果存在指定name的bean,则该注解标注的bean不创建,

  1. @ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")

表示的意思为:如果存在名称为rabbitListenerContainerFactory的bean,则该部分代码直接忽略,这是Spring Boot人性化体现之一,开发者申明的bean会放在第一位,实在是太懂礼貌了~~

 
本篇中涉及到的注解比较多,其具体实现原理在以后有时间再具体分析。
 
再回到RabbitAutoConfiguration类的具体实现
 
首先来看:
  1. @Configuration
  2. @ConditionalOnMissingBean(ConnectionFactory.class)
  3. protected static class RabbitConnectionFactoryCreator {
  4. @Bean
  5. public ConnectionFactory rabbitConnectionFactory(RabbitProperties config) {
  6. CachingConnectionFactory factory = new CachingConnectionFactory();
  7. String addresses = config.getAddresses();
  8. factory.setAddresses(addresses);
  9. if (config.getHost() != null) {
  10. factory.setHost(config.getHost());
  11. factory.setPort(config.getPort());
  12. }
  13. if (config.getUsername() != null) {
  14. factory.setUsername(config.getUsername());
  15. }
  16. if (config.getPassword() != null) {
  17. factory.setPassword(config.getPassword());
  18. }
  19. if (config.getVirtualHost() != null) {
  20. factory.setVirtualHost(config.getVirtualHost());
  21. }
  22. return factory;
  23. }
  24. }

创建了默认的ConnectionFactory,需要注意的时,这里的ConnectionFactory无回调的设置(解答了上篇中的疑问)

  1. @Bean
  2. @ConditionalOnMissingBean(RabbitTemplate.class)
  3. public RabbitTemplate rabbitTemplate() {
  4. return new RabbitTemplate(this.connectionFactory);
  5. }

创建了默认的RabbitTemplate;下面创建的RabbitMessagingTemplate实现对RabbitTemplate的包装。

 
在RabbitAutoConfiguration类中还剩AmqpAdmin的创建没有讲解,这部分就留到后面的文章再来讲述...

spring boot实战(第十三篇)自动配置原理分析的更多相关文章

  1. Spring boot - 梳理 - 根本上说,Spring Boot项目只不过是一个普通的Spring项目,只是使用了Spring Boot的起步依赖和自动配置

    根本上说,Spring Boot项目只不过是一个普通的Spring项目,只是使用了Spring Boot的起步依赖和自动配置

  2. Spring Boot实战系列(7)集成Consul配置中心

    本篇主要介绍了 Spring Boot 如何与 Consul 进行集成,Consul 只是服务注册的一种实现,还有其它的例如 Zookeeper.Etcd 等,服务注册发现在微服务架构中扮演这一个重要 ...

  3. Spring Boot数据访问之数据源自动配置

    Spring Boot提供自动配置的数据访问,首先体验下,Spring Boot使用2.5.5版本: 1)导入坐标: 2.5.25版本支持8.0.26mysql数据库驱动.spring-boot-st ...

  4. Spring Boot框架 - 数据访问 - JDBC&自动配置

    一.新建Spring Boot 工程 特殊勾选数据库相关两个依赖 Mysql Driver — 数据库驱动 Spring Data JDBC 二.配置文件application.properties ...

  5. (转)spring boot实战(第三篇)事件监听源码分析

    原文:http://blog.csdn.net/liaokailin/article/details/48194777 监听源码分析 首先是我们自定义的main方法: package com.lkl. ...

  6. (转)spring boot实战(第六篇)加载application资源文件源码分析

    原文:http://blog.csdn.net/liaokailin/article/details/48878447

  7. spring boot实战(第十二篇)整合RabbitMQ

    前言 最近几篇文章将围绕消息中间件RabbitMQ展开,对于RabbitMQ基本概念这里不阐述,主要讲解RabbitMQ的基本用法.Java客户端API介绍.spring Boot与RabbitMQ整 ...

  8. Spring Boot自动配置原理与实践(一)

    前言 Spring Boot众所周知是为了简化Spring的配置,省去XML的复杂化配置(虽然Spring官方推荐也使用Java配置)采用Java+Annotation方式配置.如下几个问题是我刚开始 ...

  9. Spring Boot的自动配置原理及启动流程源码分析

    概述 Spring Boot 应用目前应该是 Java 中用得最多的框架了吧.其中 Spring Boot 最具特点之一就是自动配置,基于Spring Boot 的自动配置,我们可以很快集成某个模块, ...

随机推荐

  1. UVA 540 stl

    Queues and Priority Queues are data structures which are known to most computer scientists. The Team ...

  2. Lucene 4.7 --创建索引

    Lucene的最新版本和以前的语法或者类名,类规定都相差甚远 0.准备工作: 1). Lucene官方API http://lucene.apache.org/core/4_7_0/index.htm ...

  3. javaScript基础练习题-下拉框制作(神奇的代码)

    http://www.oschina.net/code/snippet_12_46548#66319 http://www.codeproject.com/Tips/890021/Advanced-C ...

  4. c++ 函数调用在进入下一个循环的时候会再次初始化参数,将函数体直接写进去就正常

    #include"stdafx.h" #include"string" #include<iostream> #include<vector& ...

  5. easyui datagrid 获取 title

    function exportExecl(obj) { var cfs = $(obj).datagrid('getColumnFields'); //这是获取到所有的Fields //得到title ...

  6. 初学JDBC,调用存储过程

    在JDBC简单封装的基础上实现 public class UserDao{ public static void testGetUser(String userName) throws Excepti ...

  7. hdu 2045 不容易系列之(3)—— LELE的RPG难题

    解题思路: f(n)=1,2,.....n-2,n-1,n 前n-2个已经涂好,那么n-1有两种可能 1.n-1与n-2和1 的颜色都不同 1 粉,   n-2 红,   n-1 绿.  那么n的颜色 ...

  8. Ward BRDF实现心得

    最近做了Ward BRDF的实现,相对于之前的lambert,phong来说,Ward是一个真正意义上的各向异性BRDF,但同样的,Ward模型也是一个基于经验的模型,并不是物理上正确的.它由ward ...

  9. ALTER 语句修改数据表

    1.修改数据表名:alter table 表名 rename 新表名; 2.修改列名: alter table 表名 change 列名 新列名(可以与旧的一样) 类型 默认值; 3.修改类型: al ...

  10. js通过alert查看对象或数组内容

    var arr=new Array("Saab","Volvo","BMW"); for(i in arr ){ alert(i); //获 ...