若是你有這樣的需求:java
想要計算本身的spring項目中某些方法的執行用時,且每次執行時自動輸出git
那麼這個框架就很適合你了,目前,這個計時框架有如下優勢:github
其實這個也是我本身作的小框架,徹底開源,項目地址在github-mayoi7/timer,目前正在開發的分支是1.x
,最新版本是1.2.0-RELEASE
web
首先建立一個簡單的web項目spring
而後在pom.xml
中引入咱們項目須要的依賴:服務器
<properties>
<java.version>1.8</java.version>
<timer.version>1.2.0-RELEASE</timer.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 計時器的依賴 -->
<dependency>
<groupId>com.github.mayoi7</groupId>
<artifactId>timer</artifactId>
<version>${timer.version}</version>
</dependency>
</dependencies>
複製代碼
而後接下來新建配置文件application.yml
,不過咱們這裏能夠什麼都先不寫併發
接着新建一個Controller,咱們裏面就添加一個方法:app
import com.github.mayoi7.timer.anno.Timer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@RequestMapping("hi")
@Timer
public void hello() {
try {
Thread.sleep(826);
} catch (Exception ignore) {}
System.out.println("Hello World...");
}
}
複製代碼
這裏要注意必定要把咱們com.github.mayoi7
這個包下的類掃描進來,因此能夠採用如下的配置方式:框架
@SpringBootApplication
// 下面兩種配置任選一(com.example.demo是當前項目的源碼包根目錄)
// @ComponentScan(basePackages = "com.*")
@ComponentScan(basePackages = {"com.example.demo.*", "com.github.mayoi7.*"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
複製代碼
好了,而後就到了重頭戲,如何給這個方法計時呢?既然咱們引入了依賴,這裏直接一個註解就夠了:ide
import com.github.mayoi7.timer.anno.Timer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@RequestMapping("hi")
@Timer
public void hello() {
try {
Thread.sleep(826);
} catch (Exception ignore) {}
System.out.println("Hello World...");
}
}
複製代碼
咱們啓動服務器,訪問localhost:8080/hi
,會發現控制檯會打印出結果:
Hello World...
[(date=2019-06-08 22:22:31, name=825608c3, duration=830 ms, classInfo=com.example.demo.controller.DemoController, methodInfo=hello)]
複製代碼
咱們來用JMeter測試下併發下的表現,這裏同時開了1000個線程循環1000次(電腦比較渣,以前開了太多被卡死機了),這裏截取了一小段輸出[1]:
[(date=2019-06-08 22:36:08, name=0753f926, duration=826 ms, classInfo=com.example.demo.controller.DemoController, methodInfo=hello)]
[(date=2019-06-08 22:36:08, name=a0a242cd, duration=826 ms, classInfo=com.example.demo.controller.DemoController, methodInfo=hello)]
Hello World...
[(date=2019-06-08 22:36:08, name=96b67174, duration=827 ms, classInfo=com.example.demo.controller.DemoController, methodInfo=hello)]
Hello World...
Hello World...
[(date=2019-06-08 22:36:08, name=26676684, duration=827 ms, classInfo=com.example.demo.controller.DemoController, methodInfo=hello)]
[(date=2019-06-08 22:36:08, name=fc283e48, duration=827 ms, classInfo=com.example.demo.controller.DemoController, methodInfo=hello)]
複製代碼
能夠發現輸出的結果仍是準確的
目前可供輸出的有5個屬性,即剛纔輸出的那些:
這些屬性大部分均可以在有限基礎上自行修改,至於如何自定義咱們接下來會進行講解
配置項能夠分爲配置文件中的配置,和註解上的配置,咱們分開來說
配置文件中以timer
爲前綴的是咱們計時器的配置項,有兩大類,timer.format
和timer.mode
,咱們單獨來講
timer.format 該類配置是用於配置輸出格式,自由度較高,因此統一放在一塊兒,包含有:
timer.format.fileFormat
:日誌文件名,包含了文件後綴(若是不輸出到日誌則無效)timer.format.logPath
:日誌輸出的絕對路徑,即「/」爲當前磁盤根目錄(若是不輸出到日誌則無效)timer.format.dateFormat
:日期輸出格式,形如「yyyy-MM-dd HH:mm:ss」,和SimpleFormatter
一致timer.format.formatterPath
:自定義格式化器類的全路徑(待會講到了會說)timer.mode 該類配置是用於一些既定輸出模式的選擇,均爲枚舉類型,因此統一放在一塊兒,包含有:
timer.mode.timeMode
:時間輸出方式,目前僅有simple
一種格式timer.mode.unit
:時間單位,可選範圍爲TimeUnit
的全部枚舉類timer.mode.methodMode
:方法名輸出方式,有simple
和param
兩種方式,分別是僅輸出方法名,以及輸出方法名和參數timer.mode.classMode
:類名輸出方式,有full
和simple
兩種方式,分別是類全路徑輸出,以及僅輸出簡單類名如下是一份樣例配置文件(暫時沒有配置自定義格式化器):
timer:
format:
file-format: timer-demo.log
log-path: /
date-format: yyyy-MM-dd HH:mm:ss
mode:
time-mode: simple
unit: milliseconds
method-mode: param
class-mode: full
複製代碼
@Timer
註解中,目前有效的配置有如下幾個:
ResultPosition.CONSOLE
和ResultPosition.LOG
,默認輸出到控制檯樣例配置以下:
@Timer(name = "timer1", unit = TimeUnit.SECONDS, position = ResultPosition.LOG)
複製代碼
若是剛纔的這些配置不可以知足你的須要,這裏還提供了高自由度的自定義配置
默認的輸出格式很差看?不要緊,如今教你如何自定義輸出的格式
首先,咱們在建立一個timer包,而後在包下建一個類,就叫MyFormatter
,而後繼承AbstractFormatter
,注意千萬不要引錯包:
import com.github.mayoi7.timer.format.AbstractFormatter;
import com.github.mayoi7.timer.props.TimerOutputSource;
import com.github.mayoi7.timer.props.TimerProperties;
public class MyFormatter extends AbstractFormatter {
public MyFormatter(TimerProperties properties, TimerOutputSource source) {
super(properties, source);
}
}
複製代碼
這裏構造函數裏兩個對象我先說明一下,properties
是咱們所設置的各項配置,source
是咱們計時器的輸出結果,不過這些都不用咱們手動設置
而後咱們在這個類中定義一個MyRecevier
的內部類[2],用於獲取到輸出屬性,須要覆寫其中的output()
方法,並在咱們自定義的MyFormatter
格式化器類中重寫getInfoReceiver()
方法,返回咱們的MyReceiver
對象:
import com.github.mayoi7.timer.format.AbstractFormatter;
import com.github.mayoi7.timer.props.TimerOutputSource;
import com.github.mayoi7.timer.props.TimerProperties;
public class MyFormatter extends AbstractFormatter {
public MyFormatter(TimerProperties properties, TimerOutputSource source) {
super(properties, source);
}
private static class MyReceiver extends InfoReceiver {
@Override
public String output() {
return "\n[myFormatter]" + date + "-" + duration;
}
}
@Override
public InfoReceiver getInfoReceiver() {
return new MyReceiver();
}
}
複製代碼
在output()
方法中,可供使用的屬性有如下5個(從InfoReceiver
中得知):
class InfoReceiver {
/** 日期 */
protected String date;
/** 名稱 */
protected String name;
/** 執行時間 */
protected String duration;
/** 類信息 */
protected String classInfo;
/** 方法信息 */
protected String methodInfo;
// ...
}
複製代碼
最後,最重要的一步來了,把MyFormatter
類的路徑通知給計時器,有配置文件和註解配置兩種方式,我這裏就在註解中配置了:
@Timer(formatter = "com.example.demo.timer.MyFormatter")
複製代碼
而後運行測試,會發現輸出的結果改成咱們配置的格式了:
Hello World...
[myFormatter]2019-06-08 23:34:20-828 ms
複製代碼
固然,僅僅改個格式還不夠,若是你想獲取更多的關於被計時方法和其所在類的信息,咱們也提供了自定義的手段
好比,你想在類信息輸出的FULL
模式下獲取更多的內容,咱們就須要回到MyFormatter
類中,再次添加一個內部類[3]MyClassFormatter
,並繼承ClassFormatter
,選擇性覆寫其中的方法:
import com.github.mayoi7.timer.format.AbstractFormatter;
import com.github.mayoi7.timer.props.TimerOutputSource;
import com.github.mayoi7.timer.props.TimerProperties;
public class MyFormatter extends AbstractFormatter {
// ...
private static class MyClassFormatter extend ClassFormatter {
@Override
public String formatInFull(Class clazz) {
return clazz.getName() + "-" + clazz.getTypeName();
}
}
}
複製代碼
而後最重要的一點是,將這個新聲明的類在構造方法中賦予對應的屬性:
public class MyFormatter extends AbstractFormatter {
public MyFormatter(TimerProperties properties, TimerOutputSource source) {
// ...
classFormatter = new MyClassFormatter();
}
複製代碼
一樣地,咱們也爲方法信息提供了對應的MethodFormatter
類和methodFormatter
屬性,使用方法基本一致,再也不進行演示
到此,配置已經完成,若是咱們開啓了類信息輸出的FULL
模式,則剛纔的MyReceiver
中的classInfo
屬性就爲咱們修改後的屬性了,具體內容再也不測試了,感興趣的能夠自行實驗
@ComponentScan
註解,無論怎麼配置,必定要把com.github.mayoi7.*
下的全部類掃描到spring-aop
的,因此只能做用於spring的bean,不能在普通類下使用到此,整個框架的使用教程已經徹底結束,若是有任何的問題能夠發送郵件到acerola.orion@foxmail.com
最後,項目地址在github-mayoi7/timer,感興趣的能夠點個星星啦