SpringBoot之AOP
一、AOP簡介(摘抄)
aop 全稱 Aspect Oriented Programming ,面向切面,AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。其與設計模式完成的任務差不多,是提供另一種角度來思考程式的結構,來彌補面向物件程式設計的不足。
二、搭建aop,通過自定義註解實現日誌插入
1、依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2、自定義註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
3、面向切面實現類
@Aspect @Component public class SysLogAspect { @Autowired private SysLogService sysLogService; @Pointcut("@annotation(io.renren.common.annotation.SysLog)") public void logPointCut() { } @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { long beginTime = System.currentTimeMillis(); //執行方法 Object result = point.proceed(); //執行時長(毫秒) long time = System.currentTimeMillis() - beginTime; //儲存日誌 saveSysLog(point, time); return result; } private void saveSysLog(ProceedingJoinPoint joinPoint, long time) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); SysLogEntity sysLog = new SysLogEntity(); SysLog syslog = method.getAnnotation(SysLog.class); if(syslog != null){ //註解上的描述 sysLog.setOperation(syslog.value()); } //請求的方法名 String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); sysLog.setMethod(className + "." + methodName + "()"); //請求的引數 Object[] args = joinPoint.getArgs(); try{ String params = new Gson().toJson(args[0]); sysLog.setParams(params); }catch (Exception e){ } //獲取request HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); //設定IP地址 sysLog.setIp(IPUtils.getIpAddr(request)); //使用者名稱 String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername(); sysLog.setUsername(username); sysLog.setTime(time); sysLog.setCreateDate(new Date()); //儲存系統日誌 sysLogService.insert(sysLog); } }
三、Aop 常用術語
切面(Aspect):
一個關注點的模組化,這個關注點可能會橫切多個物件。事務管理是J2EE應用中一個關於橫切關注點的很好的例子。在Spring AOP中,切面可以使用基於模式或者基於@Aspect註解的方式來實現。
連線點(Joinpoint):
在程式執行過程中某個特定的點,比如某方法呼叫的時候或者處理異常的時候。在Spring AOP中,一個連線點總是表示一個方法的執行。
通知(Advice):
在切面的某個特定的連線點上執行的動作。其中包括了“around”、“before”和“after”等不同型別的通知(通知的型別將在後面部分進行討論)。許多AOP框架(包括Spring)都是以攔截器做通知模型,並維護一個以連線點為中心的攔截器鏈。
切入點(Pointcut):
匹配連線點的斷言。通知和一個切入點表示式關聯,並在滿足這個切入點的連線點上執行(例如,當執行某個特定名稱的方法時)。切入點表示式如何和連線點匹配是AOP的核心:Spring預設使用AspectJ切入點語法。
引入(Introduction):
用來給一個型別宣告額外的方法或屬性(也被稱為連線型別宣告(inter-type declaration))。Spring允許引入新的介面(以及一個對應的實現)到任何被代理的物件。例如,你可以使用引入來使一個bean實現IsModified介面,以便簡化快取機制。
目標物件(Target Object):
被一個或者多個切面所通知的物件。也被稱做被通知(advised)物件。既然Spring AOP是通過執行時代理實現的,這個物件永遠是一個被代理(proxied)物件。
AOP代理(AOP Proxy):
AOP框架建立的物件,用來實現切面契約(例如通知方法執行等等)。在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。
織入(Weaving):
把切面連線到其它的應用程式型別或者物件上,並建立一個被通知的物件。這些可以在編譯時(例如使用AspectJ編譯器),類載入時和執行時完成。Spring和其他純Java AOP框架一樣,在執行時完成織入。
四、常用註解
@Aspect
標註此類為註解實現類
@Order(1)
order越小越是最先執行,但更重要的是最先執行的最後結束。order預設值是2147483647
@Pointcut
/*
* 定義一個切入點 (匹配註解方法)
*/
@Pointcut("@annotation(com.hsshy.beam.annotation.SysLog)")
public void logPointCut() {
}
// 用@Pointcut來註解一個切入方法
@Pointcut("execution(* com.hsshy.beam.controller.*.**(..))")
public void excudeController() {
}
@Before
前置通知:在某連線點之前執行的通知,但這個通知不能阻止連線點之前的執行流程
@AfterReturning
後置通知:在某連線點正常完成後執行的通知,通常在一個匹配的方法返回的時候執行。
@AfterThrowing
異常通知:在方法丟擲異常退出時執行的通知。
@After
最終通知。當某連線點退出的時候執行的通知(不論是正常返回還是異常退出)。
@Around
環繞通知:包圍一個連線點的通知,如方法呼叫。這是最強大的一種通知型別。環繞通知可以在方法呼叫前後完成自定義的行為。它也會選擇是否繼續執行連線點或直接返回它自己的返回值或丟擲異常來結束執行。
環繞通知最麻煩,也最強大,其是一個對方法的環繞,具體方法會通過代理傳遞到切面中去,切面中可選擇執行方法與否,執行方法幾次等。
環繞通知使用一個代理ProceedingJoinPoint型別的物件來管理目標物件,所以此通知的第一個引數必須是ProceedingJoinPoint型別,在通知體內,呼叫ProceedingJoinPoint的proceed()方法會導致後臺的連線點方法執行。proceed 方法也可能會被呼叫並且傳入一個Object[]物件-該陣列中的值將被作為方法執行時的引數。