Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快速构建出标准化的应用。Spring Boot的特点可以概述为如下几点:
- 内置了嵌入式的Tomcat、Jetty等Servlet容器,应用可以不用打包成War格式,而是可以直接以Jar格式运行。
- 提供了多个可选择的”starter”以简化Maven的依赖管理(也支持Gradle),让您可以按需加载需要的功能模块。
- 尽可能地进行自动配置,减少了用户需要动手写的各种冗余配置项,Spring Boot提倡无XML配置文件的理念,使用Spring Boot生成的应用完全不会生成任何配置代码与XML配置文件。
- 提供了一整套的对应用状态的监控与管理的功能模块(通过引入spring-boot-starter-actuator),包括应用的线程信息、内存信息、应用是否处于健康状态等,为了满足更多的资源监控需求,Spring Cloud中的很多模块还对其进行了扩展。
有关Spring Boot的使用方法就不做多介绍了,如有兴趣请自行阅读官方文档Spring Boot或其他文章。
如今微服务的概念愈来愈热,转型或尝试微服务的团队也在如日渐增,而对于技术选型,Spring Cloud是一个比较好的选择,它提供了一站式的分布式系统解决方案,包含了许多构建分布式系统与微服务需要用到的组件,例如服务治理、API网关、配置中心、消息总线以及容错管理等模块。可以说,Spring Cloud”全家桶”极其适合刚刚接触微服务的团队。似乎有点跑题了,不过说了这么多,我想要强调的是,Spring Cloud中的每个组件都是基于Spring Boot构建的,而理解了Spring Boot的自动配置的原理,显然也是有好处的。
Spring Boot的自动配置看起来神奇,其实原理非常简单,背后全依赖于@Conditional注解来实现的。
本文作者为SylvanasSun(sylvanas.sun@gmail.com),首发于SylvanasSun’s Blog。
原文链接:https://sylvanassun.github.io/2018/01/08/2018-01-08-spring_boot_auto_configure/
(转载请务必保留本段声明,并且保留超链接。)
什么是@Conditional?
@Conditional是由Spring 4提供的一个新特性,用于根据特定条件来控制Bean的创建行为。而在我们开发基于Spring的应用的时候,难免会需要根据条件来注册Bean。
例如,你想要根据不同的运行环境,来让Spring注册对应环境的数据源Bean,对于这种简单的情况,完全可以使用@Profile注解实现,就像下面代码所示:
@Configuration public class AppConfig { @Bean @Profile("DEV") public DataSource devDataSource() { ... } @Bean @Profile("PROD") public DataSource prodDataSource() { ... } }
剩下只需要设置对应的Profile属性即可,设置方法有如下三种:
- 通过
context.getEnvironment().setActiveProfiles("PROD")
来设置Profile属性。 - 通过设定jvm的
spring.profiles.active
参数来设置环境(Spring Boot中可以直接在application.properties
配置文件中设置该属性)。 - 通过在DispatcherServlet的初始参数中设置。
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>spring.profiles.active</param-name> <param-value>PROD</param-value> </init-param> </servlet>
但这种方法只局限于简单的情况,而且通过源码我们可以发现@Profile自身也使用了@Conditional注解。
package org.springframework.context.annotation; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional({ProfileCondition.class}) // 组合了Conditional注解 public @interface Profile { String[] value(); } package org.springframework.context.annotation; class ProfileCondition implements Condition { ProfileCondition() { } // 通过提取出@Profile注解中的value值来与profiles配置信息进行匹配 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { if(context.getEnvironment() != null) { MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); if(attrs != null) { Iterator var4 = ((List)attrs.get("value")).iterator(); Object value; do { if(!var4.hasNext()) { return false; } value = var4.next(); } while(!context.getEnvironment().acceptsProfiles((String[])((String[])value))); return true; } } return true; } }
在业务复杂的情况下,显然需要使用到@Conditional注解来提供更加灵活的条件判断,例如以下几个判断条件:
- 在类路径中是否存在这样的一个类。
- 在Spr