本篇文章將介紹如何使用Spring Boot的AOP來簡化處理自定義註解,並將經過實現一個簡單的方法執行時間統計工具爲樣例來說解這些內容。java
面向側面的程序設計(aspect-oriented programming,AOP,又譯做面向方面的程序設計、觀點導向編程、剖面導向程序設計)是計算機科學中的一個術語,指一種程序設計範型。該範型以一種稱爲側面(aspect,又譯做方面)的語言構造爲基礎,側面是一種新的模塊化機制,用來描述分散在對象、類或函數中的橫切關注點(crosscutting concern)。
側面的概念源於對面向對象的程序設計的改進,但並不僅限於此,它還能夠用來改進傳統的函數。與側面相關的編程概念還包括元對象協議、主題(subject)、混入(mixin)和委託。web
註釋:以上定義源自中文維基百科(若是訪問不了,能夠經過修改系統的hosts文件訪問,198.35.26.96 zh.wikipedia.org #中文維基百科
,只能幫到這了,若是仍是上不了,那就麻煩上網搜索下怎麼修改系統的hosts文件,不一樣系統下hosts文件位置不同,若是是Linux或者Mac系統,我就直接告訴你吧,通常文件路徑是/etc/hosts
),AOP這個詞的翻譯有點和國內主流叫法不一致,國內主流都把AOP譯作「面向切面編程」,你們不要拘泥於叫法,知道指的是同一個東西便可。
估計,你看了這個定義也是懵的,若是想深刻了解能夠去知乎看看大佬們是如何掰扯的什麼是面向切面編程AOP?。我這邊仍是就直接上例子了吧。spring
在pom.xml
中引入相應的依賴模塊編程
<!-- Spring Boot依賴包 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <dependencies> <!-- AOP依賴模塊 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- Web依賴模塊 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
一個簡單的處理Web請求的Controller。bash
package com.craneyuan.controller; import com.craneyuan.service.IHelloWorldService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloWorldController { @Autowired private IHelloWorldService helloWorldService; @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello(String name) { return helloWorldService.getHelloMessage(name); } }
一個簡單的HelloWorld服務實現類,接口的定義我就不展現代碼了。app
package com.craneyuan.service.impl; import com.craneyuan.annotation.AnalysisActuator; import com.craneyuan.service.IHelloWorldService; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class HelloWorldServiceImpl implements IHelloWorldService { public String getHelloMessage(String name) { return "Hello " + Optional.ofNullable(name).orElse("World!"); } }
這樣一個簡單的Web服務就弄好了,你能夠啓動項目用curl
命令調用試下,例如:curl -XGET -i "http://127.0.0.1:8080/hello?name=Java"
,若是一切順利的話,你將會獲得相似下面這樣的響應:curl
HTTP/1.1 200 Content-Type: text/plain;charset=UTF-8 Content-Length: 11 Date: Thu, 11 Jan 2018 09:45:38 GMT Hello Java123456
先定義一個用來統計方法執行時間的註解。模塊化
package com.craneyuan.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AnalysisActuator { String note() default ""; }123456789101112
而後定義一個切面,來處理剛剛定義的註解。函數
package com.craneyuan.aspect; import com.craneyuan.annotation.AnalysisActuator; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Component public class AnalysisActuatorAspect { final static Logger log = LoggerFactory.getLogger(AnalysisActuatorAspect.class); ThreadLocal<Long> beginTime = new ThreadLocal<>(); @Pointcut("@annotation(analysisActuator)") public void serviceStatistics(AnalysisActuator analysisActuator) { } @Before("serviceStatistics(analysisActuator)") public void doBefore(JoinPoint joinPoint, AnalysisActuator analysisActuator) { // 記錄請求到達時間 beginTime.set(System.currentTimeMillis()); log.info("cy666 note:{}", analysisActuator.note()); } @After("serviceStatistics(analysisActuator)") public void doAfter(AnalysisActuator analysisActuator) { log.info("cy666 statistic time:{}, note:{}", System.currentTimeMillis() - beginTime.get(), analysisActuator.note()); } }
最後,只要在須要統計執行時間的方法上加上@AnalysisActuator
註解就好了。spring-boot
package com.craneyuan.service.impl; import com.craneyuan.annotation.AnalysisActuator; import com.craneyuan.service.IHelloWorldService; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class HelloWorldServiceImpl implements IHelloWorldService { @AnalysisActuator(note = "獲取聊天信息方法") public String getHelloMessage(String name) { return "Hello " + Optional.ofNullable(name).orElse("World!"); } }
啓動項目,用curl
命令隨便調用一下,若是順利的話就能夠觀察到切面打印的日誌了。
... cy666 statistic time:4, note:獲取聊天信息方法