1 SpringBoot框架的自动配置
在前面章节中,我们主要分析了 Spring 框架的 IOC 容器的设计和 SpringBoot 框架在 Spring 框架的基础上,实现了可以以独立 Java 进程来启动 SpringBoot 应用,从而无需再将应用部署到 Tomcat 容器。这是 SpringBoot 框架的其中一个重大改进。除此之外,SpringBoot 提供的另外一个重大改进是自动配置。
1.1 自动配置特性
简单来说,自动配置是指 SpringBoot 应用在启动时会自动创建相关的 bean 对象,使得我们在项目中直接注入使用即可,而不需要再进行额外配置。具体为 SpringBoot 的自动配置特性解决了第三方功能组件的配置问题,实现了对第三方功能组件的即插即用,简化了应用配置,极大提高了我们的开发效率。
以下我们以在项目中添加 Redis 为例,对比一下使用了 SpringBoot 框架和不使用 SpringBoot 框架的差别,同时演示 SpringBoot 自动配置特性的使用方法。
1.1.1 Spring 应用的配置:需要显式配置 Redis 的相关功能 bean 对象
(1)在 pom.xml 文件中添加 redis 的 jar 包,即 spring-data-redis。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
(2)在应用属性配置文件 application.properties 中添加 redis 的配置
# redis 配置
redis.host=localhost
redis.port=6379
(3)在 Java 配置类中获取 redis 配置并创建对应的功能 bean 对象 redisTemplate
@Configuration
public class RedisConfig {
@Autowired
private Environment environment;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
// 配置
String host = environment.getProperty("redis.host");
int port = environment.getProperty("redis.port", Integer.class);
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxWaitMillis(1000);
config.setMaxIdle(200);
config.setMaxTotal(1000);
config.setTestOnBorrow(true);
// redisConnectionFactory
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setPort(port);
jedisConnectionFactory.setPoolConfig(config);
jedisConnectionFactory.afterPropertiesSet();
// redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
知识拓展:此处 Spring 应用的配置文件 application.properties(也可以是其他名字)与 SpringBoot 应用的配置文件的名字虽然一样,但是在 SpringBoot 应用是可以自动加载这个文件,而在 Spring 应用中则还需要使用 @PropertySource 注解来引入,否则无法生效。
除此之外,在 SpringBoot 应用中,如果需要在 application.properties 中自定义 key 和 value,并且需要在应用内使用,则需要跟 Spring 项目一样,通过 Environment 对象来获取。
(4)在应用内使用
@Service
public class TestService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public String getRedisStrValue(String key) {
return (String)redisTemplate.opsForValue().get(key);
}
}
1.1.2 SpringBoot 应用的配置:自动配置 Redis 的相关功能 bean 对象
(1)在 pom.xml 文件中添加 redis 的 starter 包,即 spring-boot-starter-data-redis。关于 SpringBoot 的 starter 包的更多知识会在后面小节详细分析,敬请期待~
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
(2)在应用配置文件 application.properties 添加 redis 的配置,即添加以 spring.redis. 为前戳的配置:
# redis 配置
spring.redis.host=localhost
spring.redis.port=6379
(3)在应用内使用
@Service
public class TestService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public String getRedisStrValue(String key) {
return (String)redisTemplate.opsForValue().get(key);
}
}
tips:以上 SpringBoot 应用配置的步骤(1)和(2)是 SpringBoot 基于 starter 包机制添加第三方功能组件的标准步骤。经过以上两步配置之后, SpringBoot 框架默认会自动为应用配置对应的功能组件 bean 对象,如 redisTemplate 等,然后在应用代码直接使用 @Autowired 注入即可。
如果是在 Spring 应用中,则还需要在 xml 配置文件中配置 redisTemplate 这个 bean 对象,或者在使用 @Configuration 注解的配置类,使用 @Bean 注解名为 redidsTemplate 的方法。
所以从以上步骤可以看出,SpringBoot 应用与 SpringBoot 应用相比,默认是不需要配置 Redis 的功能 bean 对象 redisTemplate 这个步骤的,这是因为 SpringBoot 在内部基于自动配置机制自动完成了配置。
这个例子只是展示了在应用中使用 Redis 这个功能组件,而项目中一般需要配置很多其他的功能组件,此时通过自动配置功能可以减少很多配置和编程工作,极大提高了开发效率。
1.2 自动配置的启用:@EnableAutoConfiguration
1.2.1. 用法
SpringBoot 的自动配置特性默认是开启的,不过也可以关掉,而这个控制开关就是 @EnableAutoConfiguration 注解。@EnableAutoConfiguration 是 @SpringBootApplication 注解的三大注解之一,如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// 省略其他代码
}
如果需要关掉自动配置特性,在 SpingBoot 应用的启动类中可以使用 @SpringBootConfiguration 和 @ComponentScan 来代替 @SpringBootApplication,此时不再使用 @EnableAutoConfiguration 注解。如下可以对 1.1 节点的 Spring 应用的启动类进行修改:
//@SpringBootApplication
@SpringBootConfiguration
@ComponentScan
public class SpringBootAutoconfigureDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAutoconfigureDemoApplication.class, args);
}
}
tips:正常情况下都不应该关掉 SpringBoot 的自动配置特性,不过如果项目中确实不需要 SpringBoot 自动配置的某个功能组件,一种方法是自定义一个该功能组件,另外一种方法是基于 @Conditional 系列的注解来设定自动配置的条件。关于此特性的更多知识会在下一小节详细分析。
所以用法很简单只需要配置 @EnableAutoConfiguration 注解即可,但是 SpringBoot 内部是怎么实现的呢?我们接下来继续分析。
1.2.2 实现原理
@EnableAutoConfiguration 注解的定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
// 引入了AutoConfigurationImportSelector,由该类负责引导功能组件的配置类的加载。
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
核心需要关注的是通过 @Import 注解引入了 AutoConfigurationImportSelector 这个类。AutoConfigurationImportSelector 的作用是读取 SpringBoot 框架源码的 spring-boot-autoconfigure 包的 META-INF 目录下的 spring.factories 文件。该文件的内容定义如下:
获取 org.springframework.boot.autoconfigure.EnableAutoConfiguration 作为 key 的类列表,其中这些类就是各个功能组件的配置类,即使用了 @Configuration 注解的配置类,并且在类内部使用 @Bean 注解方法来定义 bean 对象。
SpringBoot 通过处理这些配置类来决定是否需要自动创建对应的 bean 对象和注入到 Spring 的 IOC 容器中,从而实现自动配置。自动配置的处理逻辑是基于 Spring 4.0 推出的条件化注解 @Conditional 来实现的,关于 @Conditional 注解的使用和该处理逻辑的工作过程,我们会在下一节详细分析,敬请期待~
2 总结
在本小节中,我们介绍了 SpringBoot 自动配置的特性和使用方法,以及通过对比传统的 Spring 应用与 SpringBoot 应用在配置 Redis 这个第三方功能组件时的步骤,展示了 SpringBoot 框架在开发效率方面的优势。SpringBoot 的自动配置特性也是顺应了现今应用快速更新迭代的趋势,所以 SpringBoot 框架一经推出就被各大公司所使用。
在实现层面,SpringBoot 的自动配置是通过 @EnableAutoConfiguration 注解来控制的,即在项目启动类中添加这个注解才能启用自动配置特性。由于 SpringBoot 应用的启动类默认会使用 @SpringBootApplicaiton 注解,而 @SpringBootApplication 已经包含了 @EnableAutoConfiguration 注解,所以自动配置特性默认是开启的。
代码仓库
1.1.1 节:https://github.com/yzxie/spring-web-demo
1.1.2 节:https://github.com/yzxie/java-framework-demo/tree/master/spring-boot-autoconfigure-demo