美文网首页Java高级进阶Spring
SpringBoot自定义Starter

SpringBoot自定义Starter

作者: java菜 | 来源:发表于2019-05-27 12:31 被阅读3次

    1. 创建自己的Starter

    一个完整的Spring Boot Starter可能包含以下组件:

    autoconfigure模块:包含自动配置的代码

    starter模块:提供对autoconfigure模块的依赖,以及一些其它的依赖

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

    简而言之,starter应该提供使用该库所需的一切

    1.1. 命名

    模块名称不能以spring-boot开头

    如果你的starter提供了配置keys,那么请确保它们有唯一的命名空间。而且,不要用Spring Boot用到的命名空间(比如:servermanagementspring等等)

    举个例子,假设你为“acme”创建了一个starter,那么你的auto-configure模块可以命名为acme-spring-boot-autoconfigure,starter模块可以命名为acme-spring-boot-starter。如果你只有一个模块包含这两部分,那么你可以命名为acme-spring-boot-starter

    1.2.  autoconfigure模块

    建议在autoconfigure模块中包含下列依赖:

    1 <dependency>

    2 <groupId>org.springframework.boot</groupId>

    3 <artifactId>spring-boot-autoconfigure-processor</artifactId>

    4 <optional>true</optional>

    5 </dependency>

    1.3. starter模块

    事实上,starter是一个空jar。它唯一的目的是提供这个库所必须的依赖。

    你的starter必须直接或间接引用核心的Spring Boot starter(spring-boot-starter)

    2. Hello Starter 

    接下来,作为入门,写一个Spring Boot版的Hello World 

    2.1.  hello-spring-boot-starter-autoconfigure

    新建一个Maven项目命名为hello-spring-boot-starter-autoconfigure

    pom.xml

    1 <?xml version="1.0" encoding="UTF-8"?>

    2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    4    <modelVersion>4.0.0</modelVersion>

    5    <parent>

    6        <groupId>org.springframework.boot</groupId>

    7        <artifactId>spring-boot-starter-parent</artifactId>

    8        <version>2.1.5.RELEASE</version>

    9        <relativePath/> <!-- lookup parent from repository -->

    10    </parent>

    11    <groupId>com.example</groupId>

    12    <artifactId>hello-spring-boot-starter-autoconfigure</artifactId>

    13    <version>0.0.1-SNAPSHOT</version>

    14    <name>hello-spring-boot-starter-autoconfigure</name>

    15    <description>Demo project for Spring Boot</description>

    16

    17    <properties>

    18        <java.version>1.8</java.version>

    19    </properties>

    20

    21    <dependencies>

    22        <dependency>

    23            <groupId>org.springframework.boot</groupId>

    24            <artifactId>spring-boot-starter</artifactId>

    25        </dependency>

    26        <dependency>

    27            <groupId>org.springframework.boot</groupId>

    28            <artifactId>spring-boot-autoconfigure</artifactId>

    29        </dependency>

    30

    31        <dependency>

    32            <groupId>org.springframework.boot</groupId>

    33            <artifactId>spring-boot-configuration-processor</artifactId>

    34            <optional>true</optional>

    35        </dependency>

    36    </dependencies>

    37

    38 </project> 

    HelloProperties.java

    1 package com.example.hello;

    2

    3 import org.springframework.boot.context.properties.ConfigurationProperties;

    4

    5 /**

    6  * @author ChengJianSheng

    7  * @date 2019-05-26

    8  */

    9 @ConfigurationProperties("my.hello")

    10 public class HelloProperties {

    11

    12    /**

    13      * 姓名

    14      */

    15    private String name;

    16

    17    /**

    18      * 年龄

    19      */

    20    private Integer age;

    21

    22    /**

    23      * 家乡

    24      */

    25    private String hometown;

    26

    27    public String getName() {

    28        return name;

    29    }

    30

    31    public void setName(String name) {

    32        this.name = name;

    33    }

    34

    35    public Integer getAge() {

    36        return age;

    37    }

    38

    39    public void setAge(Integer age) {

    40        this.age = age;

    41    }

    42

    43    public String getHometown() {

    44        return hometown;

    45    }

    46

    47    public void setHometown(String hometown) {

    48        this.hometown = hometown;

    49    }

    50

    51    @Override

    52    public String toString() {

    53        return "HelloProperties{" +

    54                "name='" + name + '\'' +

    55                ", age=" + age +

    56                ", hometown='" + hometown + '\'' +

    57                '}';

    58    }

    59 }

    HelloService.java

    1 package com.example.hello;

    2

    3 /**

    4  * @author ChengJianSheng

    5  * @date 2019-05-26

    6  */

    7 public class HelloService {

    8

    9    /**

    10      * 姓名

    11      */

    12    private String name;

    13

    14    /**

    15      * 年龄

    16      */

    17    private Integer age;

    18

    19    /**

    20      * 家乡

    21      */

    22    private String hometown;

    23

    24    public HelloService(String name, Integer age, String hometown) {

    25        this.name = name;

    26        this.age = age;

    27        this.hometown = hometown;

    28    }

    29

    30    public String sayHello(String name) {

    31        return "Hello, " + name;

    32    }

    33

    34    public String helloWorld() {

    35        return String.format("[name=%s, age=%d, hometown=%s]", this.name, this.age, this.hometown);

    36    }

    37

    38 }

    HelloServiceAutoConfiguration.java

    1 package com.example.hello;

    2

    3 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

    4 import org.springframework.boot.context.properties.EnableConfigurationProperties;

    5 import org.springframework.context.annotation.Bean;

    6 import org.springframework.context.annotation.Configuration;

    7

    8 /**

    9  * @author ChengJianSheng

    10  * @date 2019-05-26

    11  */

    12 @Configuration

    13 @EnableConfigurationProperties(HelloProperties.class)

    14 public class HelloServiceAutoConfiguration {

    15

    16    private final HelloProperties helloProperties;

    17

    18    public HelloServiceAutoConfiguration(HelloProperties helloProperties) {

    19        this.helloProperties = helloProperties;

    20    }

    21

    22    @Bean

    23    @ConditionalOnMissingBean

    24    public HelloService helloService() {

    25        return new HelloService(this.helloProperties.getName(),

    26                this.helloProperties.getAge(),

    27                this.helloProperties.getHometown());

    28    }

    29 }

    META-INF/spring.factories

    1 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

    2  com.example.hello.HelloServiceAutoConfiguration 

    mvn clean install

    2.2.  hello-spring-boot-starter

    在hello-spring-boot-starter中引用该autoconfigure模块

    1 <?xml version="1.0" encoding="UTF-8"?>

    2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    4    <modelVersion>4.0.0</modelVersion>

    5    <groupId>com.example</groupId>

    6    <artifactId>hello-spring-boot-starter</artifactId>

    7    <version>0.0.1-SNAPSHOT</version>

    8    <name>hello-spring-boot-starter</name>

    9

    10    <properties>

    11        <java.version>1.8</java.version>

    12    </properties>

    13

    14    <dependencies>

    15        <dependency>

    16            <groupId>com.example</groupId>

    17            <artifactId>hello-spring-boot-starter-autoconfigure</artifactId>

    18            <version>0.0.1-SNAPSHOT</version>

    19        </dependency>

    20    </dependencies>

    21

    22 </project> 

    至此,我们的hello-spring-boot-starter开发完了

    接下来,我们在demo中引用它

    2.3. demo

    1 <?xml version="1.0" encoding="UTF-8"?>

    2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    4    <modelVersion>4.0.0</modelVersion>

    5    <parent>

    6        <groupId>org.springframework.boot</groupId>

    7        <artifactId>spring-boot-starter-parent</artifactId>

    8        <version>2.1.5.RELEASE</version>

    9        <relativePath/> <!-- lookup parent from repository -->

    10    </parent>

    11    <groupId>com.example</groupId>

    12    <artifactId>demo</artifactId>

    13    <version>0.0.1-SNAPSHOT</version>

    14    <name>demo</name>

    15

    16    <properties>

    17        <java.version>1.8</java.version>

    18        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    19    </properties>

    20

    21    <dependencies>

    22        <dependency>

    23            <groupId>org.springframework.boot</groupId>

    24            <artifactId>spring-boot-starter-web</artifactId>

    25        </dependency>

    26

    27        <dependency>

    28            <groupId>com.example</groupId>

    29            <artifactId>hello-spring-boot-starter</artifactId>

    30            <version>0.0.1-SNAPSHOT</version>

    31        </dependency>

    32

    33        <dependency>

    34            <groupId>org.springframework.boot</groupId>

    35            <artifactId>spring-boot-starter-test</artifactId>

    36            <scope>test</scope>

    37        </dependency>

    38    </dependencies>

    39

    40    <build>

    41        <plugins>

    42            <plugin>

    43                <groupId>org.springframework.boot</groupId>

    44                <artifactId>spring-boot-maven-plugin</artifactId>

    45            </plugin>

    46        </plugins>

    47    </build>

    48

    49 </project>

    application.properties

    1 my.hello.name=程同学

    2 my.hello.age=28

    3 my.hello.hometown=湖北省随州市

    DemoController.java

    1 package com.example.demo.controller;

    2

    3 import com.example.hello.HelloService;

    4 import org.springframework.web.bind.annotation.GetMapping;

    5 import org.springframework.web.bind.annotation.PathVariable;

    6 import org.springframework.web.bind.annotation.RequestMapping;

    7 import org.springframework.web.bind.annotation.RestController;

    8

    9 import javax.annotation.Resource;

    10

    11 /**

    12  * @author ChengJianSheng

    13  * @date 2019-05-26

    14  */

    15 @RestController

    16 @RequestMapping("/demo")

    17 public class DemoController {

    18

    19    @Resource

    20    private HelloService helloService;

    21

    22    @GetMapping("/hello/{name}")

    23    public String hello(@PathVariable("name") String name) {

    24        return helloService.sayHello(name);

    25    }

    26

    27    @GetMapping("/info")

    28    public String info() {

    29        return helloService.helloWorld();

    30    }

    31

    32 }

    3. 升级版的Hello World 

    上面的例子中演示了我们引入自定义的starter,然后调用其提供的HelloService服务。感觉好像并没有什么用,下面在此基础上做个升级,再写一个记录日志的服务。 

    3.1.  hello-spring-boot-starter-autoconfigure

    pom.xml

    1 <?xml version="1.0" encoding="UTF-8"?>

    2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    4    <modelVersion>4.0.0</modelVersion>

    5    <parent>

    6        <groupId>org.springframework.boot</groupId>

    7        <artifactId>spring-boot-starter-parent</artifactId>

    8        <version>2.1.5.RELEASE</version>

    9        <relativePath/> <!-- lookup parent from repository -->

    10    </parent>

    11    <groupId>com.example</groupId>

    12    <artifactId>hello-spring-boot-starter-autoconfigure</artifactId>

    13    <version>0.0.1-SNAPSHOT</version>

    14    <name>hello-spring-boot-starter-autoconfigure</name>

    15    <description>Demo project for Spring Boot</description>

    16

    17    <properties>

    18        <java.version>1.8</java.version>

    19    </properties>

    20

    21    <dependencies>

    22        <dependency>

    23            <groupId>org.springframework.boot</groupId>

    24            <artifactId>spring-boot-starter</artifactId>

    25        </dependency>

    26        <dependency>

    27            <groupId>org.springframework.boot</groupId>

    28            <artifactId>spring-boot-autoconfigure</artifactId>

    29        </dependency>

    30        <dependency>

    31            <groupId>org.springframework.boot</groupId>

    32            <artifactId>spring-boot-starter-web</artifactId>

    33            <optional>true</optional>

    34        </dependency>

    35        <dependency>

    36            <groupId>org.projectlombok</groupId>

    37            <artifactId>lombok</artifactId>

    38            <optional>true</optional>

    39        </dependency>

    40        <dependency>

    41            <groupId>com.alibaba</groupId>

    42            <artifactId>fastjson</artifactId>

    43            <version>1.2.58</version>

    44            <optional>true</optional>

    45        </dependency>

    46        <dependency>

    47            <groupId>org.springframework.boot</groupId>

    48            <artifactId>spring-boot-configuration-processor</artifactId>

    49            <optional>true</optional>

    50        </dependency>

    51    </dependencies>

    52

    53 </project>

    MyLog.java

    1 package com.example.log;

    2

    3 import java.lang.annotation.ElementType;

    4 import java.lang.annotation.Retention;

    5 import java.lang.annotation.RetentionPolicy;

    6 import java.lang.annotation.Target;

    7

    8 /**

    9  * @author ChengJianSheng

    10  * @date 2019-05-26

    11  */

    12 @Target(ElementType.METHOD)

    13 @Retention(RetentionPolicy.RUNTIME)

    14 public @interface MyLog {

    15

    16    /**

    17      * 方法描述

    18      */

    19    String desc() default "";

    20 }

    MyLogInterceptor.java

    1 package com.example.log;

    2

    3 import com.alibaba.fastjson.JSON;

    4 import lombok.extern.slf4j.Slf4j;

    5 import org.springframework.web.method.HandlerMethod;

    6 import org.springframework.web.servlet.ModelAndView;

    7 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

    8

    9 import javax.servlet.http.HttpServletRequest;

    10 import javax.servlet.http.HttpServletResponse;

    11 import java.lang.reflect.Method;

    12

    13 /**

    14  * @author ChengJianSheng

    15  * @date 2019-05-26

    16  */

    17 @Slf4j

    18 public class MyLogInterceptor extends HandlerInterceptorAdapter {

    19

    20    private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();

    21

    22    @Override

    23    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    24        HandlerMethod handlerMethod = (HandlerMethod) handler;

    25        Method method = handlerMethod.getMethod();

    26        MyLog myLog = method.getAnnotation(MyLog.class);

    27        if (null != myLog) {

    28            //  设置开始时间

    29            long startTime = System.currentTimeMillis();

    30            startTimeThreadLocal.set(startTime);

    31        }

    32        return true;

    33    }

    34

    35    @Override

    36    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    37        HandlerMethod handlerMethod = (HandlerMethod) handler;

    38        Method method = handlerMethod.getMethod();

    39        MyLog myLog = method.getAnnotation(MyLog.class);

    40        if (null != myLog) {

    41            //  获取开始时间

    42            long startTime = startTimeThreadLocal.get();

    43            long endTime = System.currentTimeMillis();

    44            long expendTime = endTime - startTime;

    45

    46            //  打印参数

    47            String requestUri = request.getRequestURI();

    48            String methodName = method.getDeclaringClass().getName() + "#" + method.getName();

    49            String methodDesc = myLog.desc();

    50            String parameters = JSON.toJSONString(request.getParameterMap());

    51

    52            log.info("\n描述:{}\n路径: {}\n方法: {}\n参数:{}\n耗时:{}", methodDesc, requestUri, methodName, parameters, expendTime);

    53        }

    54    }

    55 }

    MyLogAutoConfiguration.java

    1 package com.example.log;

    2

    3 import org.springframework.context.annotation.Configuration;

    4 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

    5 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    6

    7 /**

    8  * @author ChengJianSheng

    9  * @date 2019-05-26

    10  */

    11 @Configuration

    12 public class MyLogAutoConfiguration implements WebMvcConfigurer {

    13

    14    @Override

    15    public void addInterceptors(InterceptorRegistry registry) {

    16        registry.addInterceptor(new MyLogInterceptor());

    17    }

    18 }

    META-INF/spring.factories

    1 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

    2  com.example.hello.HelloServiceAutoConfiguration,\

    3  com.example.log.MyLogAutoConfiguration

    3.2. demo

    ProductController.java

    1 package com.example.demo.controller;

    2

    3 import com.example.demo.domain.ProductVO;

    4 import com.example.log.MyLog;

    5 import org.springframework.web.bind.annotation.*;

    6

    7 /**

    8  * @author ChengJianSheng

    9  * @date 2019-05-26

    10  */

    11 @RestController

    12 @RequestMapping("/product")

    13 public class ProductController {

    14

    15    @MyLog(desc = "查询商品")

    16    @GetMapping("/list")

    17    public String list() {

    18        System.out.println("查询商品");

    19        return "ok";

    20    }

    21

    22    @MyLog(desc = "添加商品")

    23    @PostMapping("/save")

    24    public String save(@RequestBody ProductVO productVO) {

    25        System.out.println("添加商品");

    26        return "ok";

    27    }

    28

    29    @MyLog(desc = "删除商品")

    30    @GetMapping("/delete")

    31    public String delete(@RequestParam("productId") Long productId) {

    32        System.out.println("删除商品");

    33        return "ok";

    34    }

    35

    36    @MyLog(desc = "获取商品详情")

    37    @GetMapping("/detail/{productId}")

    38    public String detail(@PathVariable("productId") Long productId) {

    39        System.out.println("商品详情");

    40        return "ok";

    41    }

    42

    43 } 

    查看控制台

    (PS:这里就打印日志这个功能没有使用AOP,因为这意味着在自动配置的代码中就要定义切面、切点这些东西,而且在项目启动的时候还要扫描切面,感觉比较麻烦)

    4. 工程结构

    欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865

    群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

    相关文章

      网友评论

        本文标题:SpringBoot自定义Starter

        本文链接:https://www.haomeiwen.com/subject/gwwctctx.html