使用自定義註解和切面AOP實現Java程式增強
The string {@code "unchecked"} is used to suppress * unchecked warnings. Compiler vendors should document the * additional warning names they support in conjunction with this * annotation type. They are encouraged to cooperate to ensure * that the same names work across multiple compilers. * @return the set of warnings to be suppressed */ String[] value(); } ``` 這個註解有一個字串陣列的值,需要我們使用註解的時候傳遞。可以在型別、屬性、方法、引數、建構函式和區域性變數前使用,宣告週期是編譯期。 這個註解的主要作用是壓制編譯告警的。 ## 2.AOP介紹(AspectJ暫不討論) ### 2.1 Spring AOP基本概念 1. 是一種動態編譯期增強性AOP的實現 2. 與IOC進行整合,不是全面的切面框架 3. 與動態代理相輔相成 4. 有兩種實現:基於jdk動態代理、cglib ### 2.2 Spring AOP與AspectJ區別 1. Spring的AOP是基於動態代理的,動態增強目標物件,而AspectJ是靜態編譯時增強,需要使用自己的編譯器來編譯,還需要織入器 2. 使用AspectJ編寫的java程式碼無法直接使用javac編譯,必須使用AspectJ增強的ajc增強編譯器才可以通過編譯,寫法不符合原生Java的語法;而Spring AOP是符合Java語法的,也不需要指定編譯器去編譯,一切都由Spring 處理。 ### 2.3 使用步驟 1. 定義業務元件 2. 定義切點(重點) 3. 定義增強處理方法(切面方法) 這邊用下面例子的AOP類來進行說明 (基於Spring AOP的) ```java /** * @Author Song * @Date 2020/5/26 9:50 * @Version 1.0 */ @Slf4j @Aspect @Component public class EagleEyeAspect { @Pointcut("@annotation(com.ctgu.song.plantfactory.v2.annotation.EagleEye)") public void eagleEye() { } @Around("eagleEye()") public Object around(ProceedingJoinPoint pjp) throws Throwable { long begin = System.currentTimeMillis(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); Signature signature = pjp.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); EagleEye eagleEye = method.getAnnotation(EagleEye.class); String desc = eagleEye.desc(); log.info("============請求開始=========="); log.info("請求連結:{}", request.getRequestURI().toString()); log.info("介面描述:{}", desc); log.info("請求型別:{}", request.getMethod()); log.info("請求方法:{}.{}", signature.getDeclaringTypeName(), signature.getName()); log.info("請求IP:{}", request.getRemoteAddr()); log.info("請求入參:{}", JSON.toJSONString(pjp.getArgs())); Object result = pjp.proceed(); long end = System.currentTimeMillis(); log.info("請求耗時:{}ms", end - begin); log.info("請求返回:{}", JSON.toJSONString(result)); log.info("=============請求結束==========="); return result; } } ``` 這邊先不看程式碼的具體內容,先簡單介紹一下用到AOP中常用的註解 - **@Aspect** : 指定切面類; - **@Pointcut**:公共切入點表示式 - 通知方法 - 前置通知(@Before) 目標方法執行之前,執行註解的內容 - 後置通知(@After)目標方法執行之後,執行註解的內容 - 返回通知 (@AfterReturning)目標方法返回後,執行註解的內容 - 異常通知 (@AfterThrowing)目標方法丟擲異常後,執行註解的內容 - 環繞通知 (@Around)目標方法執行前後,分別執行一些程式碼 注意 **定義好切片類後要將其加入Spring容器內才能使用哦 (可以使用@Component註解)** ## 3. 具體實現(一個例子) ### 1.首先定義一個註解,程式碼如下 ```java /** * @Author Song * @Date 2020/5/26 9:44 * @Version 1.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface EagleEye { /** * @Retention(RetentionPolicy.RUNTIME) * 定義了註解的生命週期為執行時 *
* @Target(ElementType.METHOD) * 定義了註解的作用域為方法 *
* Documented * 標識該註解可以被JavaDoc記錄 *
* 定義註解名稱為EagleEye(鷹眼,哈哈~~) *
* 定義一個元素desc,用來描述被修飾的方法 *
* 介面描述
*
* @return
*/
String desc() default "";
}
```
### 2.定義切片內並寫好自己想要增強的方法
直接貼程式碼了~~
```java
/**
* @Author Song
* @Date 2020/5/26 9:50
* @Version 1.0
*/
@Slf4j
@Aspect
@Component
public class EagleEyeAspect {
@Pointcut("@annotation(com.ctgu.song.plantfactory.v2.annotation.EagleEye)")
public void eagleEye() {
}
@Around("eagleEye()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
EagleEye eagleEye = method.getAnnotation(EagleEye.class);
String desc = eagleEye.desc();
log.info("============請求開始==========");
log.info("請求連結:{}", request.getRequestURI().toString());
log.info("介面描述:{}", desc);
log.info("請求型別:{}", request.getMethod());
log.info("請求方法:{}.{}", signature.getDeclaringTypeName(), signature.getName());
log.info("請求IP:{}", request.getRemoteAddr());
log.info("請求入參:{}", JSON.toJSONString(pjp.getArgs()));
Object result = pjp.proceed();
long end = System.currentTimeMillis();
log.info("請求耗時:{}ms", end - begin);
log.info("請求返回:{}", JSON.toJSONString(result));
log.info("=============請求結束===========");
return result;
}
}
```
在@Pointcut裡通過@annotation來配置切點,代表我們的AOP切面會切到所有用EagleEye註解修飾的類。
然後使用@Around環繞通知在被註解的方法前後執行一些程式碼
`Object result = pjp.proceed();`
這行程式碼之前就是**執行目標方法之前需要執行的程式碼** ,這行程式碼之後就是**執行目標方法之後需要執行的程式碼**
### 3. 註解的使用
只需要在需要被註解的方法上面使用自己的註解就行了 這裡拿我自己專案中的一個Controller中的方法舉例
```java
@EagleEye(desc = "分頁查詢實驗")
@GetMapping("/experiment")
@ApiOperation("分頁查詢實驗")
public RsBody