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)資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!