Spring Cloud Alibaba-AOP(十九)
阿新 • • 發佈:2019-12-31
簡介
AOP(面向切面程式設計),作為OOP(面向物件程式設計)的補充,用於處理哪些業務無關的,例如鑑權,日誌等公共邏輯,將之抽取封裝成一個可重用的模組(切面),減少程式碼重複,降低耦合,提高系統可維護性。
方式
靜態代理
在編譯階段將AspectJ(切面)織入到Java位元組碼生成AOP代理類
動態代理
在執行階段在記憶體中臨時生產一個AOP物件且在特定的切點做了增強處理
- JDK動態代理(基於介面)
- CGLIB動態代理(基於繼承)
術語
- Advice(通知/增強):切面需要做的具體工作
- Join point(連線點):允許使用通知的地方
- Poincut(切點):執行的位置
- Aspect(切面):通知和切點的結合
- Introduction(引入):切面定義的屬性方法應用到目標類
- target(目標):被通知的物件
- Weaving(織入):把切面加入程式程式碼的過程
常用的增強型別
- 前置通知(before):在某連線點之前執行的通知,但這個通知不能阻止連線點前的執行(除非丟擲異常)
- 返回後通知(afterReturning):在某連線點正常完成後執行的通知
- 丟擲異常後通知(afterThrowing):在方法丟擲異常退出時執行的通知
- 後通知(after):當某連線點退出的時候執行的通知
- 環繞通知(around):包圍一個連線點通知
執行順序
- @Order(1):越小越先執行
- around->before->around->after->afterReturning
- 橙色:@Order(1),綠色:@Order(2)
Springboot引入AOP
- 加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
複製程式碼
- 寫註解
無
複製程式碼
- 寫配置
無
複製程式碼
Introduction
package com.virgo.user.auto;
import com.virgo.user.service.TestService;
import com.virgo.user.service.TestServiceImpl;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;
/**
* @author zhaozha
* @date 2019/10/24 下午1:00
*/
@Aspect
@Component
public class IntroductionAop {
@DeclareParents(value = "com.virgo.user..service..*" ,defaultImpl = TestServiceImpl.class)
public TestService testService;
}
package com.virgo.user.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author zhaozha
* @date 2019/10/24 下午1:02
*/
@Service
@Slf4j
public class TestServiceImpl implements TestService{
@Override
public void test() {
log.info("all can use");
}
}
...
// CommonService使用TestService
TestService testService = (TestService)commonServiceImpl;
testService.test();
...
複製程式碼
順序
- 程式碼
package com.virgo.user.auto;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author zhaozha
* @date 2019/10/24 下午1:29
*/
@Slf4j
@Aspect
@Component
@Order(1)
public class TestAopOrder1 {
@Pointcut("execution(* com.virgo.user.service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void begin() {
log.info("2:{}","before");
}
@After("pointcut()")
public void commit() {
log.info("9:{}","after");
}
@AfterReturning("pointcut()")
public void afterReturning(JoinPoint joinPoint) {
log.info("10:{}","afterReturning");
}
@AfterThrowing("pointcut()")
public void afterThrowing() {
log.info("afterThrowing");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
log.info("1:{}","around");
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
log.info("8:{}","around");
}
}
}
package com.virgo.user.auto;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author zhaozha
* @date 2019/10/24 下午1:11
*/
@Slf4j
@Aspect
@Component
@Order(2)
public class TestAopOrder2 {
@Pointcut("execution(* com.virgo.user.service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void begin() {
log.info("4:{}","before");
}
@After("pointcut()")
public void commit() {
log.info("6:{}","after");
}
@AfterReturning("pointcut()")
public void afterReturning(JoinPoint joinPoint) {
log.info("7:{}","afterReturning");
}
@AfterThrowing("pointcut()")
public void afterThrowing() {
log.info("afterThrowing");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
log.info("3:{}","around");
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
log.info("5:{}","around");
}
}
}
複製程式碼
- 效果
註解生效AOP
註解
- @Target:註解的作用目標
- ElementType.TYPE:允許被修飾的註解作用在類、介面和列舉上
- ElementType.FIELD:允許作用在屬性欄位上
- ElementType.METHOD:允許作用在方法上
- ElementType.PARAMETER:允許作用在方法引數上
- ElementType.CONSTRUCTOR:允許作用在構造器上
- ElementType.LOCAL_VARIABLE:允許作用在本地區域性變數上
- ElementType.ANNOTATION_TYPE:允許作用在註解上
- ElementType.PACKAGE:允許作用在包上
- @Retention:註解的生命週期
- RetentionPolicy.SOURCE:Annotations are to be discarded by the compiler.(編譯期可見,不會寫入 class 檔案)
- RetentionPolicy.CLASS:Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.(寫入 class 檔案,類載入丟棄)
- RetentionPolicy.RUNTIME:Annotations are to be recorded in the class file by the compiler and retained by the VM at run time,so they may be read reflectively.(永久儲存,可以反射獲取)
- @Documented:註解是否應當被包含在 JavaDoc 檔案中
- @Inherited:是否允許子類繼承該註解
AOP
- 程式碼
package com.virgo.user.auto;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author zhaozha
* @date 2019/10/24 下午1:39
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAop {
String value() default "";
}
package com.virgo.user.auto;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author zhaozha
* @date 2019/10/24 下午1:53
*/
@Slf4j
@Aspect
@Component
@Order(1)
public class TestAnnotationAop {
@Pointcut(value = "@annotation(logAop)",argNames = "logAop")
public void pointcut(LogAop logAop) {
}
@Around(value = "pointcut(logAop)",argNames = "joinPoint,logAop")
public Object around(ProceedingJoinPoint joinPoint,LogAop logAop) throws Throwable {
try {
log.info(logAop.value());
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
log.info("");
}
}
}
複製程式碼
- 效果(方法加註釋@LogAop("測試Annotation"))
execution
execution(* com.virgo.user.service...(..))
- 第一個*:任意的返回值
- com.virgo.user.service:包名
- .. :當前包及其子包
- *:所有類
- .*(..) 表示任何方法,括號代表引數 .. 表示任意引數