Spring Boot的自动化配置原理

转载自 Spring Boot的自动化配置原理 

随着Ruby、Groovy等动态语言的流行,相比较之下Java的开发显得格外笨重。繁多的配置、低下的开发效率、复杂的部署流程以及第三方技术集成难度大等问题一直被人们所诟病。随着Spring家族中的新星Spring Boot的诞生,这些问题都在逐渐被解决。


个人觉得Spring Boot中最重要的两个优势就是可以使用starter简化依赖配置和Spring的自动配置。

本文涉及到大量代码,静下心来仔细阅读。阅读之后,你会彻底了解SpringBoot的自动化配置以及starter的原理。

使用starter简化依赖配置

Spring提供了一系列starter来简化Maven配置。其核心原理也就是Maven和Gradle的依赖传递方案。当我们在我们的pom文件中增加对某个starter的依赖时,该starter的依赖也会自动的传递性被依赖进来。而且,很多starter也依赖了其他的starter。例如web starter就依赖了tomcat starter,并且大多数starter基本都依赖了spring-boot-starter。

Spring自动配置

Spring Boot会根据类路径中的jar包、类,为jar包里的类自动配置,这样可以极大的减少配置的数量。简单点说就是它会根据定义在classpath下的类,自动的给你生成一些Bean,并加载到Spring的Context中。自动配置充分的利用了spring 4.0的条件化配置特性,能够自动配置特定的Spring bean,用来启动某项特性。

条件化配置

假设你希望一个或多个bean只有在某种特殊的情况下才需要被创建,比如,一个应用同时服务于中美用户,要在中美部署,有的服务在美国集群中需要提供,在中国集群中就不需要提供。在Spring 4之前,要实现这种级别的条件化配置是比较复杂的,但是,Spring 4引入了一个新的@Conditional注解可以有效的解决这类问题。

@Bean
@Conditional(ChinaEnvironmentCondition.class)
public ServiceBean serviceBean(){
   return new ServiceBean();
}


当@Conditional(ChinaEnvironmentCondition.class)条件的值为true的时候,该ServiceBean才会被创建,否则该bean就会被忽略。


@Conditional指定了一个条件。他的条件的实现是一个Java类——ChinaEnvironmentCondition,要实现以上功能就要定义ChinaEnvironmentCondition类,并继承Condition接口并重写其中的matches方法。

class ChinaEnvironmentCondition implements Condition{
   public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

       Environment env = context.getEnvironment();
       return env.containProperty("ENV_CN");
   }
}

在上面的代码中,matches方法的内容比较简单,他通过给定的ConditionContext对象进而获取Environment对象,然后使用该对象检查环境中是否存在ENV_CN属性。如果存在该方法则直接返回true,反之返回false。


当该方法返回true的时候,就符合了@Conditional指定的条件,那么ServiceBean就会被创建。反之,如果环境中没有这个属性,那么这个ServiceBean就不会被创建。


除了可以自定义一些条件之外,Spring 4本身提供了很多已有的条件供直接使用,如:

@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnExpression
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnNotWebApplication
Spring Boot应用的启动入口

自动配置充分的利用了spring 4.0的条件化配置特性,那么,Spring Boot是如何实现自动配置的?Spring 4中的条件化配置又是怎么运用到Spring Boot中的呢?


这要从Spring Boot的启动类说起。Spring Boot应用通常有一个名为*Application的入口类,入口类中有一个main方法,这个方法其实就是一个标准的Java应用的入口方法。


一般在main方法中使用SpringApplication.run()来启动整个应用。值得注意的是,这个入口类要使用@SpringBootApplication注解声明。@SpringBootApplication是Spring Boot的核心注解,他是一个组合注解。


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
   excludeFilters = {@Filter(
   type = FilterType.CUSTOM,
   classes = {TypeExcludeFilter.class}
), @Filter(
   type = FilterType.CUSTOM,
   classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
   // 略
}


@SpringBootApplication是一个组合注解,它主要包含@SpringBootConfiguration、@EnableAutoConfiguration等几个注解。


也就是说可以直接在启动类中使用这些注解来代替@ SpringBootApplication注解。 关于Spring Boot中的Spring自动化配置主要是@EnableAutoConfiguration的功劳。该注解可以让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置。


至此,我们知道,Spring Boot的自动化配置主要是通过@EnableAutoConfiguration来实现的,因为我们在程序的启动入口使用了@SpringBootApplication注解,而该注解中组合了@EnableAutoConfiguration注解。所以,在启动类上使用@EnableAutoConfiguration注解,就会开启自动配置。


那么,本着刨根问底的原则,当然要知道@EnableAutoConfiguration又是如何实现自动化配置的,因为目前为止,我们还没有发现Spring 4中条件化配置的影子。

EnableAutoConfiguration

其实Spring框架本身也提供了几个名字为@Enable开头的Annotation定义。比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和这些注解其实是一脉相承的。

@EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。


@EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。


@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

下面是EnableAutoConfiguration注解的源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
   //略
}

观察@EnableAutoConfiguration可以发现,这里Import了@EnableAutoConfigurationImportSelector,这就是Spring Boot自动化配置的“始作俑者”。


至此,我们知道,至此,我们知道,由于我们在Spring Boot的启动类上使用了@SpringBootApplication注解,而该注解组合了@EnableAutoConfiguration注解,@EnableAutoConfiguration是自动化配置的“始作俑者”,而@EnableAutoConfiguration中Import了@EnableAutoConfigurationImportSelector注解,该注解的内部实现已经很接近我们要找的“真相”了。

EnableAutoConfigurationImportSelector

EnableAutoConfigurationImportSelector的源码在这里就不贴了,感兴趣的可以直接去看一下,其实实现也比较简单,主要就是使用Spring 4 提供的的SpringFactoriesLoader工具类。


通过SpringFactoriesLoader.loadFactoryNames()读取了ClassPath下面的META-INF/spring.factories文件。

这里要简单提一下spring.factories文件,它是一个典型的java properties文件,配置的格式为Key = Value形式。

EnableAutoConfigurationImportSelector通过读取spring.factories中的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值。


如spring-boot-autoconfigure-1.5.1.RELEASE.jar中的spring.factories文件包含以下内容:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
......
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

上面的EnableAutoConfiguration配置了多个类,这些都是Spring Boot中的自动配置相关类;在启动过程中会解析对应类配置信息。每个Configuation都定义了相关bean的实例化配置。都说明了哪些bean可以被自动配置,什么条件下可以自动配置,并把这些bean实例化出来。


如果我们新定义了一个starter的话,也要在该starter的jar包中提供spring.factories文件,并且为其配置org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置类。

Configuation

我们从spring-boot-autoconfigure-1.5.1.RELEASE.jar中的spring.factories文件随便找一个Configuration,看看他是如何自动加载bean的。


@Configuration
@AutoConfigureAfter({JmxAutoConfiguration.class})
@ConditionalOnProperty(
   prefix = "spring.application.admin",
   value = {"enabled"},
   havingValue = "true",
   matchIfMissing = false
)
public class SpringApplicationAdminJmxAutoConfiguration {
   @Bean
   @ConditionalOnMissingBean
   public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar() throws MalformedObjectNameException {
       String jmxName = this.environment.getProperty("spring.application.admin.jmx-name""org.springframework.boot:type=Admin,name=SpringApplication");
       if(this.mbeanExporter != null) {
           this.mbeanExporter.addExcludedBean(jmxName);
       }

       return new SpringApplicationAdminMXBeanRegistrar(jmxName);
   }
}

看到上面的代码,终于找到了我们要找的东西——Spring 4的条件化配置。


上面SpringApplicationAdminJmxAutoConfiguration 在决定对哪些bean进行自动化配置的时候,使用了两个条件注解:ConditionalOnProperty和ConditionalOnMissingBean。


只有满足这种条件的时候,对应的bean才会被创建。这样做的好处是什么?这样可以保证某些bean在没满足特定条件的情况下就可以不必初始化,避免在bean初始化过程中由于条件不足,导致应用启动失败。

总结

至此,我们可以总结一下Spring Boot的自动化配置的实现:

通过Spring 4的条件配置决定哪些bean可以被配置,将这些条件定义成具体的Configuation,然后将这些Configuation配置到spring.factories文件中,作为key: org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,这时候,容器在启动的时候,由于使用了EnableAutoConfiguration注解,该注解Import的EnableAutoConfigurationImportSelector会去扫描classpath下的所有spring.factories文件,然后进行bean的自动化配置。


所以,如果我们想要自定义一个starter的话,可以通过以上方式将自定义的starter中的bean自动化配置到Spring的上下文中,从而避免大量的配置。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329708.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

复盘Build 2016:不要错过微软给.NET开发者的这些福利

本文作者陈计节,ThoughtWorks 高级咨询师。多年的跨平台 .NET 开发者,全栈工程师,技术布道师。擅长互联网应用程序的设计、开发和运维等工作。 近年来,微软坚持为社区提供更多灵活性,并以更开放的思路重构其已有平台&a…

java异步线程内存可见性实验

【README】 本文演示了内存可见性的场景,以及解决方法; 相关定义如下(转自java并发编程实战,一本好书,强烈推荐): 内存可见性:一个线程修改了对象状态后, 其他线程可以…

springboot 单例_如何实现一个单例及优化

前言 社长,一个爱学习,爱分享的程序猿,始终相信,付出总会有回报的。 知识改变命运,学习成就未来。爱拼才会赢! 程序猿学社的GitHub,已整理成相关技术专刊,欢迎 Star:。 https:// github.com/ITfqyd/cxyxs 社长,4年api搬运工程师,之前做的都是一些框架的搬运工作,做的时间…

乐观锁的一种实现方式——CAS

转载自 乐观锁的一种实现方式——CAS在深入理解乐观锁与悲观锁一文中我们介绍过锁。本文在这篇文章的基础上,深入分析一下乐观锁的实现机制,介绍什么是CAS、CAS的应用以及CAS存在的问题等。线程安全 众所周知,Java是多线程的。但是&#xff0…

熬夜并不值得程序员炫耀

许多程序嘴上经常挂着每天加班到凌晨三点的论调,但事实上这没什么值得炫耀的,加班通常都是效率低的代名词。 放弃睡眠就像是高利贷借款。没错,看上去你是得到了额外的时间,但你想得太乐观了,你知道代价是什么吗&#x…

前端wxml取后台js变量值_这些鲜为人知的前端冷知识,你都GET了吗?

背景最近公司项目不多,比较清闲,划水摸鱼混迹于各大技术博客平台,瞬间又GET了好多前端技能,一些属于技巧,一些则是闻所未闻的冷知识,一时间还消化不过来,不由的发出一声感叹!前端可真…

(转-这篇文章非常棒) Thread的中断机制(interrupt)

转自: Thread的中断机制(interrupt)-这篇文章非常棒 Thread的中断机制(interrupt) - 寂静沙滩 - 博客园先看收集了别人的文章,全面的了解下java的中断:中断线程线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态…

深入理解乐观锁与悲观锁

转载自 [初级]深入理解乐观锁与悲观锁在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。 乐观并发控制(乐观锁)和悲观并发控制&a…

Z.ExtensionMethods 一个强大的开源扩展库

今天有意的在博客园里面搜索了一下 Z.ExtensionMethods 这个扩展类库,确发现只搜到跟这个真正相关的才两篇博文而已,我都点进去看了一下,也都只是提到而已,没有专门介绍,才引起我写这篇文档。 一. Z.E…

python isodd奇偶_Python这些位运算的妙用,绝对让你大开眼界

位运算的性能大家想必是清楚的,效率绝对高。相信爱好源码的同学,在学习阅读源码的过程中会发现不少源码使用了位运算。但是为啥在实际编程过程中应用少呢?想必最大的原因,是较为难懂。不过,在面试的过程中,…

java线程中断

【README】 本文po出了不同场景下线程中断的不同开发方式,包括阻塞,非阻塞,io阻塞线程等; 本文部分内容转自:这篇博文写的非常好 Thread的中断机制(interrupt) - 寂静沙滩 - 博客园先看收集了别人的文章&#xff0c…

WEB API系列(一):WEB API的适用场景、第一个实例

在我前一篇博客《WebAPI前置知识:HTTP与RestfulAPI》中已经给各位简单介绍了HTTP协议与RestFul API的关系,以及一些基本的HTTP协议知识,在这些知识的铺垫下,今天,我们一起来讨论一下WEB API的适用场景,然后写我们第一个…

rpa文件怎么提取内容_怎么编辑pdf文件内容?有什么软件可以编辑pdf文件吗?

怎么编辑pdf文件内容?我是2020年大学新生,选择学习的专业是财务管理。为了更快、更深入地了解更多专业知识,我上网查找、下载了很多相关资料。不过,从网上保存下来的资料文件大多是pdf格式的,想要编辑它还得先转word。…

Future取消线程执行

【README】 本文总结于 《java并发编程实战》 page121,非常棒的一本书; 【1】Future 1,介绍:future 用于管理任务的生命周期,处理异常,以及实现取消; 2,future.cancel() 取消方法…

Nancy之结合tinyfox给我们的应用提供简单的数据服务

说到提供数据服务给我们的一些应用,估计用的最多的也就是json和xml这两种数据格式 实现的方法也是多种多样,web api,mvc的jsonresult和contentresult...等等 本文是结合Nancy、TInyFox、Owin等来实现的 一、前提工作 新建一个空的web应用程序 添加相应的…

javaweb调用python算法_请教怎么用java远程调用python? 多谢

请问如何用java远程调用python? 谢谢!本帖最后由 blackkettle 于 2015-05-07 13:00:41 编辑比如有一台机器 A上安装了python, 另一台机器B要用java 调用A 上的python的某个函数,输入数据在B机器上,所有的计算在A机器完成,结果返回…

(转)如何查看java本地方法

在线查看本地代码, refer2 http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/tip/src/os/linux/vm/os_linux.cpp 我们知道在java中查看java源码时看到native方法在java层面上就到头的,如果还想继续往下看就需要看jdk是如何实现的,今天就分…

统一配置中心的设计方案

转载自 统一配置中心的设计方案对于配置文件,我们不陌生,它提供我们可以动态修改程序运行能力。引用别人的一句话就是:系统运行时(runtime)飞行姿态的动态调整。我可以把我们的工作称之为在快速飞行的飞机上修理零件。我们人类总是无法掌控和…

微软CEO纳德拉恢弘计划:让开发者始终忘不了微软

BI中文站 4月11日 报道 当微软前CEO史蒂夫•鲍尔默(Steve Ballmer)在2000年喊出“开发者,开发者,开发者”的口号时,他可能有点儿激动,但是他的观点是对的。 30年前当Windows 1.0推出的时候,这种…

python scratch unity_Unity3D研究院之2D游戏开发制作原理(二十一)

经过了4个月不懈的努力,我和图灵教育合作的这本3D游戏开发书预计下个月就要出版了。这里MOMO先打一下广告,图灵的出版社编辑成员都非常给力,尤其是编辑小花为这本书付出了很大的努力,还有杨海玲老师,不然我也无法完成这…