1、SpringBoot starter机制

  在springboot中,使用的最多的就是starter。starter可以理解为一个可拔插式的插件,例如,你想使用jdbc插件,那么可以使用spring-boot-starter-jdbc;如果想使用mongodb,可以使用spring-boot-starter-data-mongodb。
     SpringBoot提供了各种场景的spring-boot-starter依赖模块,所有这些依赖模块都遵循着默认配置,并允许我们调整这些配置,即遵循“约定大于配置”的理念。,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot会自动通过classpath路径下的类发现需要的Bean,并注册进IOC容器。

2、为什么要自定义starter

  日常开发工作中,经常会有一些独立于业务之外的配置模块,我们经常将其放到一个特定的包下,然后如果另一个工程需要复用这块功能的时候,需要将代码硬拷贝到另一个工程,重新集成一遍。如果我们将这些可独立于业务代码之外的功配置模块封装成一个starter,复用的时候只需要将其在pom中引用依赖即可。

SpringBoot提供的starter以spring-boot-starter-xxx的方式命名的。自定义的starter使用xxx-spring-boot-starter命名,以区分SpringBoot生态提供的starter。

3、starter的实现方法

2. 引入必要的依赖

注意:这里的packaging为jar,starter需要使用到Spring boot的自动配置功能,所以需要引入自动配置相关的依赖

<groupId>com.mengday</groupId>
 <artifactId>helloworld-spring-boot-starter</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>jar</packaging><dependencies>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-autoconfigure</artifactId>
       <version>2.0.0.RELEASE</version>
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-configuration-processor</artifactId>
       <version>2.0.0.RELEASE</version>
       <optional>true</optional>
     </dependency>
 </dependencies>      
 XxxProperties

在使用Spring官方的Starter时通常可以在application.properties中来配置参数覆盖掉默认的值,例如在使用redis时一般就会有对应的RedisProperties

@ConfigurationProperties(prefix = "spring.redis")
 public class RedisProperties {
     private int database = 0;
     private String url;
     private String host = "localhost";
     private String password;
     private int port = 6379;
 }

  

我们来模仿来定义自己的Properties类

@ConfigurationProperties(prefix = "spring.demo")
 public class DemoProperties {
    private String sayWhat;
     private String toWho;
     // Getter & Setter
 }

核心服务类

每个starter都有自己的功能,例如在spring-boot-starter-jdbc中最重要的类时JdbcTemplate,每个starter中的核心业务类明白都不同,也没什么规律(像spring-boot-starter-data-xxx的命名是比较有规律的)

public class DemoService {
     public String sayWhat;
     public String toWho;
     public DemoService(String sayWhat, String toWho){
         this.sayWhat = sayWhat;
         this.toWho = toWho;
     }
     public String say(){
         return this.sayWhat + "!  " + toWho;
     }
 }

 自动配置类

一般每个starter都至少会有一个自动配置类,一般命名规则使用XxxAutoConfiguration, 例如RedisAutoConfiguration

@Configuration
 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
 @EnableConfigurationProperties(RedisProperties.class)
 public class RedisAutoConfiguration {    @Configuration
     @ConditionalOnClass(GenericObjectPool.class)
     protected static class RedisConnectionConfiguration {
         private final RedisProperties properties;
         
         @Bean
         @ConditionalOnMissingBean(RedisConnectionFactory.class)
         public JedisConnectionFactory redisConnectionFactory()
                 throws UnknownHostException {
             return applyProperties(createJedisConnectionFactory());
         }
     }        
     
     @Configuration
     protected static class RedisConfiguration {
         @Bean
         @ConditionalOnMissingBean(name = "redisTemplate")
         public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
                         throws UnknownHostException {
             RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
             template.setConnectionFactory(redisConnectionFactory);
             return template;
         }}


这里我们定义自己的自动配置

@Configuration
 //@EnableConfigurationProperties({Demo1Properties.class, DemoProperties.class})
 @EnableConfigurationProperties(DemoProperties.class)
 @ConditionalOnClass(DemoService.class)
 @ConditionalOnProperty(
         prefix = "spring.demo",
         name = "isopen",
         havingValue = "true"
 )
 public class DemoConfig {
     @Autowired
     private Demo1Properties demo1Properties;
     @Autowired
     private DemoProperties demoProperties;    @Bean
     @ConditionalOnMissingBean(DemoService.class)  // 当容器中没有指定Bean的情况下,自动配置PersonService类
     public DemoService demoService(){
         return new DemoService(demoProperties.getSayWhat(), demoProperties.getToWho());
     }
    /* @Bean
     @ConditionalOnMissingBean(DemoService.class)  // 当容器中没有指定Bean的情况下,自动配置PersonService类
     public DemoService  demo1Service(){
         return new DemoService(demo1Properties.getSayWhat(), demo1Properties.getToWho());
     }*/
 }

@ConditionalOnClass:当类路径classpath下有指定的类的情况下进行自动配置

@ConditionalOnMissingBean:当容器(Spring Context)中没有指定Bean的情况下进行自动配置

@ConditionalOnProperty(prefix = “example.service”, value = “enabled”, matchIfMissing = true),当配置文件中example.service.enabled=true时进行自动配置,如果没有设置此值就默认使用matchIfMissing对应的值

@ConditionalOnMissingBean,当Spring Context中不存在该Bean时。

@ConditionalOnBean:当容器(Spring Context)中有指定的Bean的条件下

@ConditionalOnMissingClass:当类路径下没有指定的类的条件下

@ConditionalOnExpression:基于SpEL表达式作为判断条件

@ConditionalOnJava:基于JVM版本作为判断条件

@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置

@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下

@ConditionalOnWebApplication:当前项目是Web项目的条件下

@ConditionalOnResource:类路径下是否有指定的资源

@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean
 

.src/main/resources/META-INF/spring.factories

注意:META-INF是自己手动创建的目录,spring.factories也是手动创建的文件,在该文件中配置自己的自动配置类

#-------starter自动装配---------
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.liu.config.DemoConfig

测试

 打包mvn clean install

<dependencies>
       <dependency><!--引入依赖-->
           <groupId>com.liu</groupId>
           <artifactId>propertiesOnloadCustom-spring-boot-starter</artifactId>
           <version>0.0.1-SNAPSHOT</version>
       </dependency>
       <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-tomcat</artifactId>
             <scope>provided</scope>
         </dependency>
   </dependencies>

配置application.properties

spring.demo.isopen=true
 spring.demo.say-what=hello
 spring.demo.to-who=world

测试类

@RestController
 public class TestController {    @Resource
     private DemoService demoService;
     
     @GetMapping("/say")
     public String sayWhat(){
         return demoService.say();
     }
 }@SpringBootApplication
 public class StartApp {
 //TransactionAutoConfiguration
     public static void main(String[] args) {
         
         SpringApplication.run(StartApp.class, args);
     }    
 }