SpringBoot自定義Starter

1.?創(chuàng)建自己的Starter

一個完整的Spring Boot Starter可能包含以下組件:

autoconfigure模塊:包含自動配置的代碼

starter模塊:提供對autoconfigure模塊的依賴,以及一些其它的依賴

(PS:如果你不需要區(qū)分這兩個概念的話,也可以將自動配置代碼模塊與依賴管理模塊合并成一個模塊)

簡而言之,starter應(yīng)該提供使用該庫所需的一切

1.1.?命名

模塊名稱不能以spring-boot開頭

如果你的starter提供了配置keys,那么請確保它們有唯一的命名空間。而且,不要用Spring Boot用到的命名空間(比如:server,management,spring等等)

舉個例子,假設(shè)你為“acme”創(chuàng)建了一個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? ? ? * 家鄉(xiāng)

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? ? ? * 家鄉(xiāng)

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開發(fā)完了

接下來,我們在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,然后調(diào)用其提供的HelloService服務(wù)。感覺好像并沒有什么用,下面在此基礎(chǔ)上做個升級,再寫一個記錄日志的服務(wù)。?

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? ? ? ? ? ? //? 設(shè)置開始時間

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? ? ? ? ? ? //? 打印參數(shù)

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參數(shù):{}\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.?工程結(jié)構(gòu)

歡迎工作一到五年的Java工程師朋友們加入Java程序員開發(fā): 721575865

群內(nèi)提供免費的Java架構(gòu)學習資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構(gòu)資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容