Spring Boot 自动配置理解与实践
一 自动配置理解
Spring Boot提倡通过注解(annotation)来进行Bean的配置。最终达到零配置,开箱即用的效果。我们可以简单的认为Spring Boot里面有两种创建Bean的方式:configure(即@Configuration注解的使用)和auto-configure(即@EnableAutoConfiguration注解的使用)。
-
configure(@Configuration):对应@Configuration注解的使用,Spring Boot在启动的时候会扫描添加了@Configuration注解的类(关于扫描路径就需要看@ComponentScan的用法了),把@Configuration注解类下面所有加了@Bean方法对应的Bean初始化并添加到IOC容器里面。
-
auto-configure(@EnableAutoConfiguration):自动配置的入口是@EnableAutoConfiguration注解,SpringBoot在启动的时候会读取所有jar包里面META-INF/spring.factories文件里面EnableAutoConfiguration指定的所有类,然后根据各自的条件注解来初始化这些类下面的所有加了@Bean的方法,并且把这些Bean添加到IOC容器里面去。
这两者对Bean的配置是有很大的区别的?
- 初始化的时机不同,configure里面指定的Bean初始化的方式总是在auto-configure里面指定Bean的初始化方式之前。
- configure里面Bean的初始化顺序和扫描的过程相关,并不能有效的进行指定,因为我们很难确定文件加载的顺序。
- auto-configure对应的功能可以通过@AutoConfigureAfter @AutoConfigureBefore 和 @AutoConfigureOrder来指定类的加载顺序,从而控制里面Bean的加载顺序。
- configure对应的Bean初始化会先初始化所有被扫到加了@Configuration文件的@PostConstruct注解然后再初始化这些文件里面的@Bean注解,但是@EnableAutoConfiguration对应的Bean初始化是根据文件来进行初始化的,所以会初始化完一个文件的@PostConstruct注解然后再初始化这个文件的@Bean注解,然后再接着处理另外的文件。
有可能你会有这样的疑问,auto-configure是怎么起作用的呢。自动配置的入口是@EnableAutoConfiguration注解,那为啥我们没有显示的添加@EnableAutoConfiguration注解呢,因为我们一般创建SpringBoot工程的时候都会在启动类上添加@SpringBootApplication注解,而@SpringBootApplication注解已经包含了@EnableAutoConfiguration注解。所有咱们没有显示的去添加@EnableAutoConfiguration注解。这样SpringBoot在启动的过程中发现有添加@EnableAutoConfiguration注解。就会去找所有我们项目依赖的jar包,然后会在jar包里面META-INF/spring.factories文件读取到org.springframework.boot.autoconfigure.EnableAutoConfigurationn指定的类。然后根据这些类所指定的条件创建这些类里面添加了@Bean方法对应的Bean,并且把这些Bean添加到IOC容器里面去。
clipboard.png上面讲了一大堆,那么auto-configure具体的作用是啥呢。auto-configure的目的就是让第三方jar里面的类可以很方便的添加到IOC容器里面去。让我们在项目中可以直接使用,最终达到开箱即用的状态。SpringBoot里面的spring-boot-starters就是通过自动配置的方式来实现的。在实际开发过程中我们也可以仿照starter的实现方式,来提供自定义的的starter(关于这一点,我们会在后文中以一个具体的例子来讲)。总之自动配置让让我们可以更好的维护复杂的项目。通过自动配置的方式第三方jar里面的Bean在我们的项目中拿来用就可以了。真正的开箱即用.
关于自动配置有一点要强调,自动配置使用的时候还可以通过@AutoConfigureAfter,@AutoConfigureBefore和@AutoConfigureOrder这类的注解来指定加载顺序。有一点也要特别注意,如果自动配置提供的类名称在@ComponentScan扫描的路径之中,SpringBoot会把这些类作为configuration先给处理了,这个时候@AutoConfigureAfter,@AutoConfigureBefore和@AutoConfigureOrder这类指定顺序的注解都会失效的。千万千万要记住。
二 自动配置实践
接下来,我们通过自定义的Spring Boot Starter.来了解下自定配置实践的使用。我们心里一定要明确自动配置的目的就是让第三方jar里面的类可以很方便的添加到IOC容器里面去。
一个完整的Spring Boot Starter一般包含三个模块:第三方库(Bean的具体实现)模块、auto-configuration模块、starter模块。他们三者之间的关系如下图所示。
spring-boot-starter.png如果你不需要区分这两个概念的话,也可以将自动配置代码模块与依赖管理模块合并成一个模块。
2.1 第三方库(Bean的具体实现)
第三方库(Bean的具体实现),自动配置的目的就是为了让第三方的类可以添加到IOC容器里面,让我们在SpringBoot工程里面使用。这个模块就是我们需要添加到IOC容器里面去的Bean的具体实现。例如redis-starter则,该模块对应的就是redis操作的一些封装比如redis连接、读取缓存等等一些操作。
我们实现一个email-starter。我们简单的创建一个email项目。最后会把他们打成一个jar包。里面就是发送邮件的具体逻辑实现。我们就在email项目添加一个类EmailService模拟邮件的发送。如下代码。后续我们会把EmailService添加到IOC容器里面去。
public class EmailService {
private String sendEmail;
private String sendPassword;
public EmailService(String sendEmail, String sendPassword) {
this.sendEmail = sendEmail;
this.sendPassword = sendPassword;
}
/**
* 模拟发送邮件
*
* @param toEmail 发送邮件的目的地址
* @param content 发送邮件的内容
*/
public void sendEmail(String toEmail, String content) {
// 这里我们就不做具体的逻辑了,我们就简单的打印
System.out.println("发送邮件成功");
System.out.println("从 " + sendEmail + "发送给" + toEmail);
System.out.println("邮件内容:" + content);
}
}
最终打包成email-1.0-SNAPSHOT.jar
2.2 auto-configuration模块
auto-configuration模块包含自动配置的代码,里面会根据各种条件注解把根据需求把第三方jar里面的类对象添加到IOC容器里面去。而且该模块会在resource目录下添加META-INF/spring.factories文件配置org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的自动配置类。
auto-configuration模块命名规范
- 后缀:-spring-boot-autoconfigure
- 模式:模块-spring-boot-autoconfigure
- 举例:email-spring-boot-autoconfigure
auto-configuration模块pom文件,有两个是标配的依赖spring-boot-autoconfigure和spring-boot-configuration-processor,一个是自动配置的核心依赖,另一个如果我们自动配置需要用到什么自定义属性的时候(application.yml配置文件里面自定义属性)IDE的智能提示,剩下的就是auto-configuration模里面需要用到的其他依赖,比如我们需要对我们上面的email模块做自动配置,所以添加我们上面的email模块,这里要特别注意这里依赖没有往下传递添加了<scope>compile</scope>控制住了。因为在使用的时候我们需要控制当EmailService类存在的时候才会添加到IOC容器里面去。
<!-- 自动配置核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 用于IDE配置文件自定义属性时候的智能提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 需要的第三方库,注意这里设置只在编译器有效 -->
<dependency>
<groupId>com.tuacy</groupId>
<artifactId>email</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
关于SpringBoot里面添加注解的使用,可以自己去google下哦。
自动配置类的实现EmailAutoConfigure。如果存在EmailService类,我们就把EmailService对象条件到IOC容器里面去。EmailProperties用于去配置文件里面读取自定义的属性。
@Configuration
@EnableConfigurationProperties(EmailProperties.class)
public class EmailAutoConfigure {
/**
* 一些属性配置
*/
private final EmailProperties emailProperties;
public EmailAutoConfigure(EmailProperties emailProperties) {
this.emailProperties = emailProperties;
}
/**
* 需要自动配置的Bean,这样该Bean就可以在添加了starter包的项目里面直接哪里啊用就可以了
*
* @return EmailService
*/
@Bean
@ConditionalOnClass(EmailService.class)
@ConditionalOnMissingBean
public EmailService emailService() {
return new EmailService(emailProperties.getSendEmail(), emailProperties.getSendPassword());
}
}
@ConfigurationProperties("email")
public class EmailProperties {
private String sendEmail;
private String sendPassword;
public String getSendEmail() {
return sendEmail;
}
public void setSendEmail(String sendEmail) {
this.sendEmail = sendEmail;
}
public String getSendPassword() {
return sendPassword;
}
public void setSendPassword(String sendPassword) {
this.sendPassword = sendPassword;
}
}
spring.factories文件添加我们自动配置类EmailAutoConfigure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tuacy.autoconfigure.email.configure.EmailAutoConfigure
最后打包成email-spring-boot-autoconfigure-1.0-SNAPSHOT.jar
2.3 starter模块
starter是一个空jar。它的目的是提供提供对auto-configure模块的依赖,和auto-configure模块需要的依赖。
starter模块命名规范
- 后缀:-spring-boot-starter
- 模式:模块-spring-boot-starter
- 举例:email-spring-boot-starter
starter模块,主要是pom文件。一个是添加autoconfigure依赖,一个是添加autoconfigure模块里面需要的依赖(SpringBoot里面添加注解的使用)。
<dependencies>
<dependency>
<groupId>com.tuacy</groupId>
<artifactId>email</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.tuacy</groupId>
<artifactId>email-spring-boot-autoconfigure</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
最后打包成email-spring-boot-starter-1.0-SNAPSHOT.jar。这样在SpringBoot项目里面就可以使用这个starter包了。从而使用我们的EmailService类了。
实例代码下载地址,https://github.com/tuacy/java-study 对应地址里面的,emai,email-spring-boot-autoconfigure,email-spring-boot-starter三个module里面对应的代码。
image.png