spring boot自动配置实现

自打用了spring boot,都忘spring
mvc中之xml配置是个什么事物了,再为反过来不失。为啥spring boot这么好用呢,
约定大于配置的筹划初衷,
让我们才晓得吝惜好application.properties(或application.yml)文件就得了,我们于安排文件里能够安装数据源参数,可以安装服务端口,可以设置redis的地址等等。大家常会晤扣押有些含starter名字的jar包,如spring-boot-starter-data-redis,引入这个jar包,我们就是得略高效布置了。那么我们好支付了一个接口服务被别人调用,大家是休是能够管其封装成一个starter
jar包呢?让别人当application.properties定义,实现全自动配置为?答案是允许的,下面与自家一块儿写一个自行配置jar包。(本文的目的不是教学自动配置的法则,大家可自行网上查找原理)。

性配置

 

  • Spring的JdbcTemplate是勿是当Classpath里面?假假如,并且DataSource也是,就自行配置一个JdbcTemplate的Bean
  • Thymeleaf是匪是当Classpath里面?倘若是,则自动配置Thymeleaf的模版解析器、视图解析器、模板引擎
  1. ### 环境音信

    开发工具:idea

    maven版本号:3.5.4

  2. ### jar包封装

    创制一个springboot项目

    图片 1

    填写坐标信息

    图片 2

    springboot版本2.0.4

    图片 3

    别默认,成立好后,目录如下

    图片 4

    连片下创制大家的测试服务类Test瑟维斯(Service)(Service)

     1 package com.tanghuachun.teststarter;
     2 
     3 public class TestService {
     4 
     5     private String ip;
     6     private int port;
     7 
     8     public TestService(String ip, int port){
     9         this.ip = ip;
    10         this.port = port;
    11     }
    12     
    13     public void printConfInfo(){
    14         System.out.println("骚年,你配置的IP为:" + ip + ",端口为:" + port);
    15     }
    16 }
    

    咱着想,旁人利用大家那接口的下,将Ip和Port通过application.properties注入,接下大家创制属性配置实体类TestService(Service)Properties

     1 package com.tanghuachun.teststarter;
     2 
     3 import org.springframework.boot.context.properties.ConfigurationProperties;
     4 
     5 @ConfigurationProperties(prefix = "test-config")//取配置文件前缀为test-config配置
     6 public class TestServiceProperties {
     7     private String host;
     8     private int port;
     9 
    10     public String getHost() {
    11         return host;
    12     }
    13 
    14     public void setHost(String host) {
    15         this.host = host;
    16     }
    17 
    18     public int getPort() {
    19         return port;
    20     }
    21 
    22     public void setPort(int port) {
    23         this.port = port;
    24     }
    25 }
    

    咱发现以此类似写好后指示有左

     图片 5

    在pom文件加上倚重包,问题解决

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    

    新建一个机动配置类TestService(Service)AutoConfiguration

     1 package com.tanghuachun.teststarter;
     2 
     3 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
     4 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
     5 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
     6 import org.springframework.boot.context.properties.EnableConfigurationProperties;
     7 import org.springframework.context.annotation.Bean;
     8 import org.springframework.context.annotation.Configuration;
     9 
    10 @Configuration
    11 @ConditionalOnClass(TestService.class)// 存在TestService这个类才装配当前类
    12 @ConditionalOnProperty(name = "test-config.enabled", havingValue = "true", matchIfMissing = true)//配置文件存在这个test-config.enabled=true才启动,允许不存在该配置
    13 @EnableConfigurationProperties(TestServiceProperties.class)
    14 public class TestServiceAutoConfiguration {
    15     @Bean
    16     @ConditionalOnMissingBean   // 没有TestService这个类才进行装配
    17     public TestService testService(TestServiceProperties testServiceProperties) {
    18         return new TestService(testServiceProperties.getHost(), testServiceProperties.getPort());
    19     }
    20 }
    

    相关阐明含义在诠释中就认证,到这边,代码已经写好了,我们要坐注脚的不二法门于用户以,自定义一个注@EnableTestService

     1 package com.tanghuachun.teststarter;
     2 import org.springframework.context.annotation.Import;
     3 import java.lang.annotation.*;
     4 
     5 @Inherited
     6 @Documented
     7 @Target(ElementType.TYPE)
     8 @Retention(RetentionPolicy.RUNTIME)
     9 @Import(TestServiceAutoConfiguration.class)
    10 //相当于使用定义spring.factories完成Bean的自动装配
    11 public @interface EnableTestService {
    12 //@Import(TestServiceAutoConfiguration.class) 需要在调用者的Main 类加上该注解就能等效于spring.factories 文件配置
    13 }
    

    接下来注释掉pom文件中之maven插件,如下图

    图片 6

    接下来maven打包,就会扭转一个jar包,那多少个jar包大家就足以从来用了

    图片 7

     那里因为于当地环境测试,大家拿编译好的jar安装及地点maven仓库,点击左边边的install按钮(你为堪导入编译好之jar包一样的)

  3. ### jar包使用

    大家起始来测试大家封装好之jar,首先成立一个springboot项目(创造时一头默认,你的包名也可跟本身同,无所谓的)

    图片 8

    pom文件之凭配置如下

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.tanghuachun</groupId>
                <artifactId>test-starter</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    </dependencies>
    

    每当main入口类加上注明

    图片 9

    创建一个TestController类

     1 package com.tanghuachun.testmain;
     2 
     3 import com.tanghuachun.teststarter.TestService;
     4 import org.springframework.beans.factory.annotation.Autowired;
     5 import org.springframework.web.bind.annotation.GetMapping;
     6 import org.springframework.web.bind.annotation.RestController;
     7 
     8 @RestController
     9 public class TestController {
    10     @Autowired
    11     private TestService testService;
    12 
    13     @GetMapping(value = "/test")
    14     public String test(){
    15         testService.printConfInfo();
    16         return "OK";
    17     }
    18 }
    

    紧接下去当application.properties中配置参数

     图片 10

    启航该品种,在地点栏输入 http://localhost:8080/test
    回车,看控制台打印的音恰好是咱们需要的

    图片 11

    及这里大家就是完了了一个机关配置的包。

    骚年们可研商一下starter中表明@ConditionalOnProperty对运的熏陶。

    今底故事讲得了了。

 季、编写好之spring boot starter pom

图片 12

新建starter maven项目spring-boot-starter-hello

图片 13

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sam.spring_boot_starter_hello.HelloServiceAutoConfiguration

于SpringFactoriesLoader.loadFactoryNames()方法中,我们看到会询问META-INF/spring.factories那些布局文件

坐JdbcTemplateAutoConfiguration为条例,它里面来及时段代码:

  1. @Conditional小例子,来表明条件化配置的实现情势
  2. spring boot 的条件化配置详解
  3. spring boot 自动配置源码分析
  4. 友善出手实现spring boot starter pom

除非在不在JdbcOperations(假设查阅JdbcTemplate的源码,你会意识JdbcTemplate类实现了JdbcOperations接口)实例的下,才会合伊始化一个JdbcTemplate
的Bean。

一、@Conditional小例子

图片 14

本篇随便说起如下两只地方展开举办:

  1. )修改pom,引入上述的借助

    <dependency>
                <groupId>com.sam</groupId>
                <artifactId>spring-boot-starter-hello</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    
  2. )实现controller
    图片 15

    @RestController
    public class HelloController {
      //代码中没有配置这个helloService Bean,但是自动配置能够帮忙实例化,因此可以直接注入
        @Autowired
        HelloService helloService;
    
        @RequestMapping(value="/helloService")
        public String sayHello() {
            return helloService.sayHello();
        }
    }
    

    图片 16

  3. )页面访问/helloService接口图片 17

     

  4. )在application.properties里面配备hello.msg=sam,然后再度走访/helloService(Service)接口

判定遵照类

图片 18

图片 19

依据上述内容,我们不怕得翻阅活动配置相关的源码了。

(注:由于自家本地的spring
boot版本不是时的,这里的EnableAutoConfigurationImportSelector已经不提出下了,新本子可能都转移成了别样类似,可是非影响我们看代码)

  1. 今非昔比序列下之Bean的接近

    1. )接口

      public interface ListService {
      
          public String showListLine();
      }
      
    2. )windows下的Bean类
      图片 20

      public class WindowsListService implements ListService{
      
          @Override
          public String showListLine() {
              return "dir";
          }
      
      }
      

      图片 21

    3. )linux下的Bean的类
      图片 22

      public class LinuxListService implements ListService{
      
          @Override
          public String showListLine() {
              return "ls";
          }
      
      }
      

      图片 23

  2. 配置类
    图片 24

    @Configuration
    public class ConditionConfig {
    
        /**
         * 通过@Conditional 注解,符合windows条件就返回WindowsListService实例
         * 
         */
        @Bean
        @Conditional(WindowsCondition.class)
        public ListService windonwsListService() {
            return new WindowsListService();
        }
    
        /**
         * 通过@Conditional 注解,符合linux条件就返回LinuxListService实例
         * 
         */
        @Bean
        @Conditional(LinuxCondition.class)
        public ListService linuxListService() {
            return new LinuxListService();
        }
    }
    

    图片 25

  3. 测试类
    图片 26

    public class ConditionTest {
    
        public static void main(String[] args) {
    
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
            ListService listService = context.getBean(ListService.class);
            System.out
                    .println(context.getEnvironment().getProperty("os.name") + " 系统下的列表命令为: " + listService.showListLine());
        }
    }
    

    图片 27

  4. 运转测试类,由于自家的凡windows7 系统,因而结果是

    Windows 7 系统下的列表命令为: dir
    

    即便你的是linux系统,则结果就会是

    Linux 系统下的列表命令为: ls
    
  1. 看清标准定义

    1. )windows下的论断条件
      图片 28

      /**
       * 实现spring 的Condition接口,并且重写matches()方法,如果操作系统是windows就返回true
       *
       */
      public class WindowsCondition implements Condition{
      
          @Override
          public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
      
              return context.getEnvironment().getProperty("os.name").contains("Windows");
          }
      

SpringFactoriesLoader.loadFactoryNames方法会扫描具有META-INF/spring.factories文件的jar包,而我辈的spring-boot-autoconfigure.jar里面就出一个这样的文本,此文件被扬言了切实可行有哪些自动配置:

连着下我们看个源码的列子:

手续如下:

图片 29

图片 30

@Bean
    @Primary
    @ConditionalOnMissingBean(JdbcOperations.class)
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(this.dataSource);
    }

图片 31

图片 32

图片 33

咱清楚在windows下显得列表的一声令下是dir,而在linux系统下显得列表的命令是ls,基于条件配置,我们可以实现在不同之操作系统下回到不同之值。

修改pom文件

 

紧接下,我们便来形容一个简短的spring boot starter pom。

       图片 34

我们解,spring
boot自动配置效应能够按照不同意况来决定spring配置当据此哪个,不应该为此何人,举个例:

据悉Hello瑟维斯(Service)(Service)Properties提供的参数,并因而@ConditionalOnClass(HelloService.class)判定HelloService这一个仿佛以Classpath中是否存在,存在而还尚未对号入座的Bean,就别对应之hello瑟维斯(Service)Bean

/**
 * @ConfigurationProperties
 * 自动匹配application.properties文件中hello.msg的值,然后赋值给类属性msg,这里的msg默认值为“spring boot”
 *
 */
@ConfigurationProperties(prefix="hello")
public class HelloServiceProperties {

    private static final String MSG = "spring boot";

    private String msg = MSG;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }


}

 那些仿佛继承了AutoConfigurationImportSelector

登记配置,需要到META-INF/spring.factories文件中注册改成自动配置类:在src/main/source目录下新建改文件,然后举办安排。

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sam</groupId>
    <artifactId>spring-boot-starter-hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <!-- 这里需要引入spring boot的自动配置作为依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>1.5.1.RELEASE</version>
        </dependency>


    </dependencies>
</project>
@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello", matchIfMissing = true, value = "enabled")
public class HelloServiceAutoConfiguration {

    @Autowired
    HelloServiceProperties helloServiceProperties;

    @Bean
    @ConditionalOnMissingBean(HelloService.class)
    public HelloService helloService() {
        HelloService service = new HelloService();
        service.setMsg(helloServiceProperties.getMsg());
        return service;
    }
}

挺是是怎落实的吧?原因就在它们选拔了Spring的条件化配置,条件化配置允许配置是于用中,不过于满意某些特定条件前会忽略这一个部署。

条件化配置就是当这jar里面实现的,它使了之类的条件化讲明,这一个注解都是坐@ConditionalOn最先的,他们都是运了@Conditional的组合注脚:

对该工程进展mvn clean install,将jar推送及地面maven仓库,供后添利用。

图片 35

spring
boot项目标开行类用的诠释–@SpringBootApplication是一个结缘注明,其中@EnableAutoConfiguration是电动配置相关的。图片 36

我们地点提到的JdbcTemplateAutoConfiguration自动配置类似就于里面。

假定落实条件化配置大家而由此到@Conditional条件化声明。

图片 37

老三、spring boot 自动配置源码分析

机动配置类

以spring boot项目蒙会设有一个叫做吧spring-boot-autoconfigure的jar包

图片 38

/**
 * 后面的代码会依据此类是否存在,来决定是否生产对应的Bean
 *
 */
public class HelloService {

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String sayHello() {
        return "hello " + msg;
    }
}

要这些@EnableAutoConfiguration注解里面有只@Import表明导入了EnableAutoConfigurationImportSelector用来落实具体的力量

图片 39

亚、spring boot 的条件化配置

拔取starter ,使用我们是starter 需要新建一个要应用既存的一个spring
boot工程(这里自己用底凡既存的),然后

入父类,里面来个点子selectImports()调用了法getCandidateConfigurations(),进而调用了SpringFactoriesLoader.loadFactoryNames()方法

        }

    ![](https://common.cnblogs.com/images/copycode.gif)

2.  )linux下的判定条件
    ![](https://common.cnblogs.com/images/copycode.gif)

        /**
         * 实现spring 的Condition接口,并且重写matches()方法,如果操作系统是linux就返回true
         *
         */
        public class LinuxCondition implements Condition{

            @Override
            public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

                return context.getEnvironment().getProperty("os.name").contains("Linux");
            }


        }

    ![](https://common.cnblogs.com/images/copycode.gif)

图片 40

图片 41

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图