一 自动配置理解

        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容器里面去。

springboot service的实现 指定 beanname springboot设置bean默认值_Spring Boot Starter


      上面讲了一大堆,那么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模块。他们三者之间的关系如下图所示。

springboot service的实现 指定 beanname springboot设置bean默认值_Spring Boot Starter_02

如果你不需要区分这两个概念的话,也可以将自动配置代码模块与依赖管理模块合并成一个模块。

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模块,这里要特别注意这里依赖没有往下传递添加了compile控制住了。因为在使用的时候我们需要控制当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里面对应的代码。

springboot service的实现 指定 beanname springboot设置bean默认值_Spring Boot Starter_03