SpringBoot自定义Starter

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

2 org.springframework.boot

3 spring-boot-autoconfigure-processor

4 true

5

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

2

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

4    4.0.0

5   

6        org.springframework.boot

7        spring-boot-starter-parent

8        2.1.5.RELEASE

9       

10   

11    com.example

12    hello-spring-boot-starter-autoconfigure

13    0.0.1-SNAPSHOT

14    hello-spring-boot-starter-autoconfigure

15    Demo project for Spring Boot

16

17   

18        1.8

19   

20

21   

22       

23            org.springframework.boot

24            spring-boot-starter

25       

26       

27            org.springframework.boot

28            spring-boot-autoconfigure

29       

30

31       

32            org.springframework.boot

33            spring-boot-configuration-processor

34            true

35       

36   

37

38  

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

2

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

4    4.0.0

5    com.example

6    hello-spring-boot-starter

7    0.0.1-SNAPSHOT

8    hello-spring-boot-starter

9

10   

11        1.8

12   

13

14   

15       

16            com.example

17            hello-spring-boot-starter-autoconfigure

18            0.0.1-SNAPSHOT

19       

20   

21

22  

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

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

2.3. demo

1

2

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

4    4.0.0

5   

6        org.springframework.boot

7        spring-boot-starter-parent

8        2.1.5.RELEASE

9       

10   

11    com.example

12    demo

13    0.0.1-SNAPSHOT

14    demo

15

16   

17        1.8

18        UTF-8

19   

20

21   

22       

23            org.springframework.boot

24            spring-boot-starter-web

25       

26

27       

28            com.example

29            hello-spring-boot-starter

30            0.0.1-SNAPSHOT

31       

32

33       

34            org.springframework.boot

35            spring-boot-starter-test

36            test

37       

38   

39

40   

41       

42           

43                org.springframework.boot

44                spring-boot-maven-plugin

45           

46       

47   

48

49

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

2

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

4    4.0.0

5   

6        org.springframework.boot

7        spring-boot-starter-parent

8        2.1.5.RELEASE

9       

10   

11    com.example

12    hello-spring-boot-starter-autoconfigure

13    0.0.1-SNAPSHOT

14    hello-spring-boot-starter-autoconfigure

15    Demo project for Spring Boot

16

17   

18        1.8

19   

20

21   

22       

23            org.springframework.boot

24            spring-boot-starter

25       

26       

27            org.springframework.boot

28            spring-boot-autoconfigure

29       

30       

31            org.springframework.boot

32            spring-boot-starter-web

33            true

34       

35       

36            org.projectlombok

37            lombok

38            true

39       

40       

41            com.alibaba

42            fastjson

43            1.2.58

44            true

45       

46       

47            org.springframework.boot

48            spring-boot-configuration-processor

49            true

50       

51   

52

53

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 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 } 

查看控制台

SpringBoot自定义Starter_第1张图片

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

4. 工程结构

SpringBoot自定义Starter_第2张图片

SpringBoot自定义Starter_第3张图片

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

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

你可能感兴趣的:(SpringBoot自定义Starter)