引言
只要你用 Spring boot,必定會用到各類 spring-boot-starter。其實寫一個spring-boot-starter,僅需4步。java
下面咱們就寫一個starter,它將實現,在日誌中打印方法執行時間。git
第一步 建立maven項目
在使用spring-boot-starter,會發現,有的項目名稱是 XX-spring-boot-starter,有的是spring-boot-starter-XX,這個項目的名稱有什麼講究呢?github
從springboot官方文檔摘錄以下:web
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.spring
As a rule of thumb, you should name a combined module after the starter.apache
從這段話能夠看出spring-boot-starter命名的潛規則。springboot
spring-boot-starter-XX是springboot官方的starter微信
XX-spring-boot-starter是第三方擴展的starter架構
打印方法執行時間的功能,須要用到aop,我們的項目就叫作app
aspectlog-spring-boot-starter吧。
項目的pom文件以下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>aspectlog-spring-boot-starter</artifactId>
<version>1.0.2</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.15.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
關於spring-boot-configuration-processor的說明,引自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:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
簡單說就是 寫starter時,在pom中配置 spring-boot-autoconfigure-processor,
在編譯時會自動收集配置類的條件,寫到一個 META-INF/spring-autoconfigure-metadata.properties中。
不熟悉 Spring Boot 基礎的能夠看下這個倉庫:https://github.com/javastacks/spring-boot-best-practice
第二步寫自動配置邏輯
各類condition
類型 | 註解 | 說明 |
Class Conditions 類條件註解 |
@ConditionalOnClass | 當前classpath下 有指定類才加載 |
@ConditionalOnMissingClass | 當前classpath下無指定類才加載 |
|
Bean Conditions Bean條件註解 |
@ConditionalOnBean | 當期容器內有 指定bean才加載 |
@ConditionalOnMissingBean | 當期容器內無指定bean才加載 |
|
Property Conditions 環境變量條件 註解(含配置文件) |
@ConditionalOnProperty | prefix 前綴 name 名稱 havingValue 用於匹配配置項值 matchIfMissing 沒找指定配置項時 的默認值 |
Resource Conditions 資源條件註解 |
@ConditionalOnResource | 有指定資源才加載 |
Web Application Conditions web條件註解 |
@ConditionalOnWebApplication | 是web才加載 |
@ConditionalOnNotWebApplication | 不是web才加載 | |
SpEL Expression Conditions | @ConditionalOnExpression | 符合SpEL 表達式才加載 |
本次咱們就選用@ConditionalOnProperty。即配置文件中有aspectLog.enable=true,才加載咱們的配置類。
不熟悉 Spring Boot 基礎的能夠看下這個倉庫:https://github.com/javastacks/spring-boot-best-practice
下面開始寫自動配置類
2.1.定義AspectLog註解,該註解用於標註須要打印執行時間的方法。
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: 用於控制定時任務的開啓與關閉
* 對應切面
* creat_user: wenl
* creat_time: 2018/11/10 18:45
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectLog {
}
2.2定義配置文件對應類
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定義自動配置類
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 {
//執行方法名稱
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() {
//保證事務等切面先執行
return Integer.MAX_VALUE;
}
}
配置類簡要說明:
@ConditionalOnProperty(prefix = "aspectLog", name = "enable",havingValue = "true", matchIfMissing = true)
當配置文件有aspectLog.enable=true時開啓,若是配置文件沒有設置aspectLog.enable也開啓。基礎知識不熟悉的能夠關注公衆號Java技術棧回覆boot獲取一份完整教程。
第三步META-INF/spring.factories
META-INF/spring.factories是spring的工廠機制,在這個文件中定義的類,都會被自動加載。多個配置使用逗號分割,換行用\
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.shanyuan.autoconfiguration.aspectlog.AspectLogAutoConfiguration
第四步打包測試
這是咱們最終的目錄結構
在IDEA中,進行mvn intall
打包完成後,在其餘項目中的pom中引入進行測試
來源:my.oschina.net/floor/blog/4435699
本文分享自微信公衆號 - 架構師智庫(beijing-tmt)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。