僅需四步,寫一個(gè) Spring Boot Starter

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
引言
只要你用 Spring boot,一定會(huì)用到各種 spring-boot-starter。其實(shí)寫一個(gè)spring-boot-starter,僅需4步。
下面我們就寫一個(gè)starter,它將實(shí)現(xiàn),在日志中打印方法執(zhí)行時(shí)間。
第一步 創(chuàng)建maven項(xiàng)目
在使用spring-boot-starter,會(huì)發(fā)現(xiàn),有的項(xiàng)目名稱是 XX-spring-boot-starter,有的是spring-boot-starter-XX,這個(gè)項(xiàng)目的名稱有什么講究呢?
從springboot官方文檔摘錄如下:
Do not start your module names with spring-boot, even if you use a different Maven groupId. We may offer official support for the thing you auto-configure in the future.
As a rule of thumb, you should name a combined module after the starter.
從這段話可以看出spring-boot-starter命名的潛規(guī)則。
spring-boot-starter-XX是springboot官方的starter
XX-spring-boot-starter是第三方擴(kuò)展的starter
打印方法執(zhí)行時(shí)間的功能,需要用到aop,咱們的項(xiàng)目就叫做
aspectlog-spring-boot-starter吧。
項(xiàng)目的pom文件如下:
"1.0"?encoding="UTF-8"?>
"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">
????4.0.0
????org.example
????aspectlog-spring-boot-starter
????1.0.2
????
????????org.springframework.boot
????????spring-boot-starter-parent
????????2.1.15.RELEASE
????
????
????
????????
????????????org.springframework.boot
????????????spring-boot-autoconfigure
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-aop
????????
????????
????????????org.springframework.boot
????????????spring-boot-configuration-processor
????????????true
????????
????
關(guān)于spring-boot-configuration-processor的說(shuō)明,引自springBoot官方文檔:
Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file ( META-INF/spring-autoconfigure-metadata.properties ). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time. It is recommended to add the following dependency in a module that contains auto-configurations:
??org.springframework.boot
??spring-boot-autoconfigure-processor
??true
簡(jiǎn)單說(shuō)就是 寫starter時(shí),在pom中配置 spring-boot-autoconfigure-processor,
在編譯時(shí)會(huì)自動(dòng)收集配置類的條件,寫到一個(gè) META-INF/spring-autoconfigure-metadata.properties中。
不熟悉 Spring Boot 基礎(chǔ)的可以看下這個(gè)倉(cāng)庫(kù):https://github.com/javastacks/spring-boot-best-practice
第二步寫自動(dòng)配置邏輯
各種condition
| 類型 | 注解 | 說(shuō)明 |
Class Conditions 類條件注解 | @ConditionalOnClass | 當(dāng)前classpath下 有指定類才加載 |
| @ConditionalOnMissingClass | 當(dāng)前classpath下無(wú)指定類才加載 | |
Bean Conditions Bean條件注解 | @ConditionalOnBean | 當(dāng)期容器內(nèi)有 指定bean才加載 |
| @ConditionalOnMissingBean | 當(dāng)期容器內(nèi)無(wú)指定bean才加載 | |
Property Conditions 環(huán)境變量條件 注解(含配置文件) | @ConditionalOnProperty | prefix??前綴 name?名稱 havingValue ?用于匹配配置項(xiàng)值 matchIfMissing?? 沒(méi)找指定配置項(xiàng)時(shí) 的默認(rèn)值 |
Resource?Conditions? 資源條件注解 | @ConditionalOnResource | 有指定資源才加載 |
Web Application Conditions web條件注解 | @ConditionalOnWebApplication | 是web才加載 |
| @ConditionalOnNotWebApplication | 不是web才加載 | |
| SpEL Expression Conditions | @ConditionalOnExpression | 符合SpEL 表達(dá)式才加載 |
本次我們就選用@ConditionalOnProperty。即配置文件中有aspectLog.enable=true,才加載我們的配置類。
不熟悉 Spring Boot 基礎(chǔ)的可以看下這個(gè)倉(cāng)庫(kù):https://github.com/javastacks/spring-boot-best-practice
下面開(kāi)始寫自動(dòng)配置類
2.1.定義AspectLog注解,該注解用于標(biāo)注需要打印執(zhí)行時(shí)間的方法。
package?com.shanyuan.autoconfiguration.aspectlog;
import?java.lang.annotation.ElementType;
import?java.lang.annotation.Retention;
import?java.lang.annotation.RetentionPolicy;
import?java.lang.annotation.Target;
/**
?*?class_name:?ScheduleManage
?*?describe:???用于控制定時(shí)任務(wù)的開(kāi)啟與關(guān)閉
?*?對(duì)應(yīng)切面
?*?creat_user:?wenl
?*?creat_time:??2018/11/10?18:45
?**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public?@interface???AspectLog?{
}
2.2定義配置文件對(duì)應(yīng)類
package?com.shanyuan.autoconfiguration.aspectlog;
import?org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("aspectLog")
public?class?AspectLogProperties?{
????private?boolean?enable;
????public?boolean?isEnable()?{
????????return?enable;
????}
????public?void?setEnable(boolean?enable)?{
????????this.enable?=?enable;
????}
}
2.3定義自動(dòng)配置類
package?com.shanyuan.autoconfiguration.aspectlog;
import?org.aspectj.lang.ProceedingJoinPoint;
import?org.aspectj.lang.annotation.Around;
import?org.aspectj.lang.annotation.Aspect;
import?org.slf4j.Logger;
import?org.slf4j.LoggerFactory;
import?org.springframework.boot.autoconfigure.condition.*;
import?org.springframework.context.annotation.Configuration;
import?org.springframework.context.annotation.EnableAspectJAutoProxy;
import?org.springframework.core.PriorityOrdered;
@Aspect
@EnableAspectJAutoProxy(exposeProxy?=?true,?proxyTargetClass?=?true)
@Configuration
@ConditionalOnProperty(prefix?=?"aspectLog",?name?=?"enable",
?????????????????????havingValue?=?"true",?matchIfMissing?=?true)
public?class?AspectLogAutoConfiguration?implements?PriorityOrdered?{
????protected?Logger?logger?=?LoggerFactory.getLogger(getClass());
@Around("@annotation(com.shanyuan.autoconfiguration.aspectlog.AspectLog)?")
????public?Object?isOpen(ProceedingJoinPoint?thisJoinPoint)?
????????????????????????????????????????throws?Throwable?{
????????//執(zhí)行方法名稱?
????????String?taskName?=?thisJoinPoint.getSignature()
????????????.toString().substring(
????????????????thisJoinPoint.getSignature()
????????????????????.toString().indexOf("?"),?
????????????????????thisJoinPoint.getSignature().toString().indexOf("("));
????????taskName?=?taskName.trim();
????????long?time?=?System.currentTimeMillis();
????????Object?result?=?thisJoinPoint.proceed();
????????logger.info("method:{}?run?:{}?ms",?taskName,?
????????????????????????????(System.currentTimeMillis()?-?time));
????????return?result;
????}
????@Override
????public?int?getOrder()?{
????????//保證事務(wù)等切面先執(zhí)行
????????return?Integer.MAX_VALUE;
????}
}
配置類簡(jiǎn)要說(shuō)明:
@ConditionalOnProperty(prefix?=?"aspectLog",?name?=?"enable",havingValue?=?"true",?matchIfMissing?=?true)
當(dāng)配置文件有aspectLog.enable=true時(shí)開(kāi)啟,如果配置文件沒(méi)有設(shè)置aspectLog.enable也開(kāi)啟。基礎(chǔ)知識(shí)不熟悉的可以關(guān)注公眾號(hào)Java技術(shù)棧回復(fù)boot獲取一份完整教程。
第三步META-INF/spring.factories
META-INF/spring.factories是spring的工廠機(jī)制,在這個(gè)文件中定義的類,都會(huì)被自動(dòng)加載。多個(gè)配置使用逗號(hào)分割,換行用\
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.shanyuan.autoconfiguration.aspectlog.AspectLogAutoConfiguration
第四步打包測(cè)試
這是我們最終的目錄結(jié)構(gòu)

在IDEA中,進(jìn)行mvn intall

打包完成后,在其他項(xiàng)目中的pom中引入進(jìn)行測(cè)試

來(lái)源:my.oschina.net/floor/blog/4435699






關(guān)注Java技術(shù)棧看更多干貨


