• springboot 自定义starter之AutoConfiguration【原】


    八、自定义starter

    AutoConfiguration:

    1、这个场景需要使用到的依赖是什么?

    没有特别依赖的配置

    2、如何编写自动配置

    @Configuration  //指定这个类是一个配置类
    @ConditionalOnXXX  //在指定条件成立的情况下自动配置类生效
    @AutoConfigureAfter({YYY.class,ZZZ.class})  //指定自动配置类的顺序,在哪个自动配置类之后才配置
    @Bean  //给容器中添加组件,写成@Component也可
    ​
    @ConfigurationPropertie // 结合相关xxxProperties类来绑定相关的配置
    @EnableConfigurationProperties //让xxxProperties生效直接加入到容器中,可以直接使用@Autowired自动包装该xxxProperties类
    //自动配置类要能加载
    //将需要启动就加载的自动配置类,配置在META-INF/spring.factories  (比如spring-boot-autoconfigure-1.5.14.RELEASE.jar包的类路径下的/META-INF/spring.factories文件)
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,

    模式:

    starter启动器只用来做依赖导入;可以是一个空jar文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或其它类库。所以建模块时建成普通manven即可。

    autoconfigurer自动配置模块必需要依赖spring-boot-starter, 所以建模块时最好建成springboot项目。

    starter和autoconfigurer分成两个项目, 是为了形成一个starter对应对多autoconfigurer的后期扩展,方便管理。以后别人引用时只需要引用starter,而不用关心autoconfigurer。

    建议命名规则

      命名规则 定义名 举例  
    官方starter spring-boot-starter-OfficalDefinition 名字在后面 spring-boot-starter-jdbc  
    自定义starter MyDefinition-spring-boot-starter 名字在前面 starter叫mybatis-spring-boot-starter  
             

    项目说明

    1、my-spring-boot-starter-autoconfigurer  自动配置模块

    2、my-spring-boot-starter 场景启动器starter模块 ,依赖my-spring-boot-starter-autoconfigurer 

    3、starter-demo 主项目 依赖my-spring-boot-starter

     

    starter-demo-2019-6-12 15-17-11.snag

    步骤

     

    1、自动配置模块 my-spring-boot-starter-autoconfigurer

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>my-spring-boot-starter-autoconfigurer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>my-spring-boot-starter-autoconfigurer</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <!--autoconfigurer只需要依赖原生的spring-boot-starter-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <!-- 配置文件自动映射 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
    
    </project>

    Ticket.java

    package com.example.simple.bean;
    
    import java.io.Serializable;
    
    public class Ticket implements Serializable {
        public Integer id;
        public String name;
        private String type;
    
        public Ticket() {
        }
    
        public Ticket(Integer id, String name, String type) {
            this.id = id;
            this.name = name;
            this.type = type;
        }
    //get set  toString ....
    }

    TicketProperties.java

    package com.example.simple.bean;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    //和application.properties或application.yml产生关联
    @ConfigurationProperties(prefix = "com.ticket")
    public class TicketProperties {
        Integer id;//可以用 application.properties中com.ticket.id=xxx 的配置自动赋值
        String name;//可以用 application.properties中com.ticket.name=xxx 的配置自动赋值
        String type;//可以用 application.properties中com.ticket.type=xxx 的配置自动赋值
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    }

    ITicketService.java

    接口

    package com.example.simple.service;
    
    import com.example.simple.bean.Ticket;
    import com.example.simple.bean.TicketProperties;
    
    public interface ITicketService {
        public Ticket getDefaultTicket(String type);
    
        public TicketProperties getTicketProperties();
    
        public void setTicketProperties(TicketProperties ticketProperties);
    }

    PianoTicketService.java

    package com.example.simple.service;
    
    import com.example.simple.bean.Ticket;
    import com.example.simple.bean.TicketProperties;
    
    /**
     * 为了在 TicketServiceAutoConfiguration 的@Bean注解的方法中使用以返回该对象到IOC容器中,
     * 最终可以让其它依赖后的项目的Controller,Service等组件使用@Autowired自动装配该Bean
     */
    public class PianoTicketService implements ITicketService {
        TicketProperties ticketProperties;
    
        @Override
        public Ticket getDefaultTicket(String type){//用于其它项目的Controller中
            Ticket ticket = new Ticket(9999,ticketProperties.getName(),ticketProperties.getType());
            return ticket;
        }
    
        @Override
        public TicketProperties getTicketProperties() { //get方法
            return ticketProperties;
        }
    
        @Override
        public void setTicketProperties(TicketProperties ticketProperties) {//set方法
            this.ticketProperties = ticketProperties;
        }
    
    }

    ViolinTicketService.java

    package com.example.simple.service;
    
    import com.example.simple.bean.Ticket;
    import com.example.simple.bean.TicketProperties;
    
    public class ViolinTicketService implements ITicketService {
        TicketProperties ticketProperties;
    
        @Override
        public Ticket getDefaultTicket(String type){//用于其它项目的Controller中
            Ticket ticket = new Ticket(9999,ticketProperties.getName(),ticketProperties.getType());
            return ticket;
        }
    
        @Override
        public TicketProperties getTicketProperties() {//get方法
            return ticketProperties;
        }
    
        @Override
        public void setTicketProperties(TicketProperties ticketProperties) {//set方法
            this.ticketProperties = ticketProperties;
        }
    
    }

    TicketServiceAutoConfiguration.java

    package com.example.simple.config;
    
    import com.example.simple.bean.TicketProperties;
    import com.example.simple.service.ITicketService;
    import com.example.simple.service.PianoTicketService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration//标注这是一个配置类,这个类的位置不需要在启动类MySpringBootApplication的子包下,因为由META-INF/spring.factories指定了加载位置
    @ConditionalOnWebApplication//添加一些条件(也可以不加)web项目时才有效
    @ConditionalOnClass({ITicketService.class})//ITicketService.class存在时本配置才有效
    //@ConditionalOnMissingClass({"com.example.simple.service.ITicketService"})//指定类不存在的时候配置才有效
    @EnableConfigurationProperties(TicketProperties.class)//让TicketProperties在当前配置中直接生效
    public class TicketServiceAutoConfiguration {//声明自动配置类
    
        @Autowired
        TicketProperties ticketProperties;//自动包装
    
        //声明自动装配的Bean,这样当于在项目启动时就内置加载了该Bean
        @Bean
        //这个配置就是SpringBoot可以优先使用自定义Bean的核心所在,如果没有我们的自定义Bean ITicketService.class 存在, 那么才会自动配置一个新的Bean
        @ConditionalOnMissingBean(ITicketService.class)
        public ITicketService ticketService() {
            System.out.println("my-spring-boot-starter-autoconfigurer的bean:ticketService装配到容器成功");
            ITicketService ticketService = new PianoTicketService();//声明对象
            ticketService.setTicketProperties(ticketProperties);//设置属性
            return ticketService;//返回对象
        }
    
        // 参考: https://blog.csdn.net/xcy1193068639/article/details/81517456
        //@ConditionOnBean在判断list的时候,如果list没有值,返回false,否则返回true
        //@ConditionOnMissingBean在判断list的时候,如果list没有值,返回true,否则返回false,其他逻辑都一样
    
    }

    spring.factories

    创建文件夹及文件 srcmain esourcesMETA-INFspring.factories  , 目录不可更改

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    com.example.simple.config.TicketAutoConfiguration

    如果有多个自动配置类

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    com.xxx.yyy.Zzz1AutoConfiguration,
    com.xxx.yyy.Zzz2AutoConfiguration,
    com.xxx.yyy.Zzz3AutoConfiguration

     

    2、启动器模块 my-spring-boot-starter

    可以包含多个autoconfigurer模块, 方便其它项目引用

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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.example</groupId>
        <artifactId>my-spring-boot-starter</artifactId>
        <version>1.0-SNAPSHOT</version><!--引入自动配置模块-->
        <dependencies>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>my-spring-boot-starter-autoconfigurer</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            
            <!--
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>my-spring-boot-starter-other-autoconfigurer</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            -->
            
        </dependencies>
    </project>

    3、 starter-demo

    starter-demo为依赖my-spring-boot-starter的项目 , 就像正常maven项目一样, 在pom.xml添加my-spring-boot-starter即可.

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>starter-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>starter-demo</name>
        <description>Demo project for Spring Boot</description><properties>
            <java.version>1.8</java.version>
        </properties><dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency><!--配置自定义的starter依赖-->
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>my-spring-boot-starter</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency></dependencies><build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build></project>

    TicketController.java

    http get访问入口 http://localhost:8080/ticket?type=piano

    package com.example.starterdemo.controller;
    
    import com.example.simple.bean.Ticket;
    import com.example.simple.service.ITicketService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TicketController {
    
        @Autowired
        ITicketService ticketService;
    
        //http://localhost:8080/ticket?type=piano
        @GetMapping(value = "/ticket")
        public Ticket getDefaultTicket(String type){
            Ticket ticket = ticketService.getDefaultTicket(type);
            return ticket;
        }
    }

    StarterDemoApplication.java

    启动应用的类 , 启用了public ITicketService ticketService() 方法, 会在容器中添加ITicketService bean , 让默认自动配置失效, 当注释该方法后, 又可以启动自动配置.

    package com.example.starterdemo;
    
    import com.example.simple.bean.TicketProperties;
    import com.example.simple.service.ITicketService;
    import com.example.simple.service.PianoTicketService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.context.annotation.Bean;
    
    @SpringBootApplication
    public class StarterDemoApplication {
    
        //声明自动装配的Bean,这样当于在项目启动时就内置加载了该Bean
        //本bean将会优先于my-spring-boot-starter-autoconfigurer自动装配模块的 TicketServiceAutoConfiguration 类中的ticketService bean的初始化,
        //而自动装配模块有@ConditionalOnMissingBean(ITicketService.class)条件,所以一旦配了该bean,将替换自动装配模块的bean
        //为了作出区别,本bean的初始化值不再从properties文件中获取,而是直接代码声明了.
        @Bean
        public ITicketService ticketService() {
            System.out.println("starter-demo的bean:ticketService装配到容器成功, my-spring-boot-starter-autoconfigurer的bean:ticketService不再装配");
    
            ITicketService ticketService = new PianoTicketService();//声明对象
            TicketProperties ticketProperties = new TicketProperties();
            ticketProperties.setId(8888);
            ticketProperties.setName("圣母颂");
            ticketProperties.setType("violin");
    
            ticketService.setTicketProperties(ticketProperties);//设置属性
            return ticketService;//返回对象
        }
    
        //http://localhost:8080/ticket?type=piano
        public static void main(String[] args) {
            SpringApplication.run(StarterDemoApplication.class, args);
        }
    }

    参考

    SpringBoot @ConditionalOnBean、@ConditionalOnMissingBean注解源码分析与示例==>https://blog.csdn.net/xcy1193068639/article/details/81517456

    我的项目git地址

    我的git代码地址: https://gitee.com/KingBoBo/Spring-Boot-Starter-Demo  starter分支

  • 相关阅读:
    [页面布局方式]
    padding and margin
    【浏览器中的页面】
    【浏览器的页面循环系统】
    Activity启动模式详解(二)--->singleTask
    finish、onDestory、System.exit的区别
    Androidndk开发打包时我们应该如何注意平台的兼容(x86,arm,arm-v7a)
    关于WifiManager的一些看法
    高效的找出两个List中的不同元素
    关于Activity的生命周期
  • 原文地址:https://www.cnblogs.com/whatlonelytear/p/9023350.html
Copyright © 2020-2023  润新知