開發中有時會遇到一些需求,需要記錄一些方法的執行時間、地點、及操作内容。我們需要在使用者操作時擷取使用者的日志資訊,然後做持久化。如果在本次方法中處理的話,就會有很多重複代碼,也容易發生遺漏,使用注解式aop,就能很優雅的實作這個功能。
aop步驟:
1.建立一個切面類
2.在類中定義增強方法,通過注解确定增強類型
3.在注解中配置切入點
切方法
"execution(* com.xst.service..*.*(..))"
第一個 * 表示任意傳回值
com.xst.service 定義包 業務層 表示在com.xst.service包下
第二個 * 表示任意類
第三個 * 表示任意方法
(..)表示任意形參
連起來就是 切入點為在com.xst.service包下 任意類 任意方法 任意形參 任意傳回值 的方法
/**
* @Aspect 聲明目前類為切面類
* 會自動編織類中的切點和增強
* @Configuration 聲明目前類為配置類
*/
@Aspect
@Configuration
public class LogAop {
/**
* 建立增強方法
* @After() 後置增強
* @Before()前置增強
* @Around()環繞增強
* @AfterThrowing 異常
* 切入點表達式("execution(* com.xst.service..*.*(..))"
*/
@After("execution(* com.xst.service..*.*(..))")
public void testAfter() {
System.out.println("後置增強AOEUIDHTN");
}
}
4.環繞增強
上面方法是在符合切入點的方法執行之後執行,前置和後置增強都很好了解,那麼我們來看一下ta們和環繞增強之間的差別
差別:
1.需要形參 ProceedingJoinPoint joinPoint
2.需要對目标方法執行放行操作 手動調用
3.需要将業務層方法執行結果傳回
@Around("execution(* com.xst.service..*.*(..))")
public Object testAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("執行環繞增強前pyfgcrl");
/**
* 放行
*執行目标方法
* proceed 執行業務層方法
*/
Object proceed = joinPoint.proceed();
System.out.println("執行環繞增強後qjkxbmwvz");
return proceed;
}
自定義注解步驟
1.建立自定義注解類
2.定義元注解
3.定義自定義注解的屬性
/**
* 元注解 加在自定義注解上的注解
*
* @Target("ElementType.METHOD")定義目前注解可以加在什麼地方 METHOD 方法上
* TYPE 類上
* FIELD 屬性上
* @Retention(RetentionPolicy.RUNTIME) 定義注解生效時間
* SOURCE 注解隻保留在源檔案,當代碼編譯成class檔案 注解會被jvm删除
* CLASS 注解被保留到class檔案,但jvm加載class檔案時候被删除,這是預設的生命
* RUNTIME 一直生效
* .java檔案 ---> .class檔案 ---> 記憶體中的位元組碼
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
/**
* 操作内容 content();
* 操作類型 type();
*/
String content();
String type();
}
4.業務方法添加自定義注解
@LogAnnotation(content = "充值", type = "update")
public void serviceImplMethod() {
System.out.println("充值到賬100元");
}
下面我們隻需要在業務方法上添加自定義注解,然後在切面類的增強方法中擷取日志資訊(目前使用者、ip位址、操作時間、操作内容、操作類型等等),然後做持久化。
很明顯,日志記錄比較适合使用後置增強類型,是以我們可以在後置增強方法内通過下面代碼擷取自定義注解的屬性。
// 1.擷取方法簽名對象
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 2.擷取方法對象
Method method = signature.getMethod();
// 3.擷取方法上的注解 LogAnnotation為自定義注解類
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
// 4.擷取注解的值
String content = annotation.content();
String type = annotation.type();
可能會有一些不完善的地方,我想起來會更新。