AOP: 面向切面編程(Aspect Oriented Programming),和Java結構中的OOP是截然不同兩種的邏輯,可以理解爲是對OOP的一種補充,對程序結構的另一種思考。
在OOP的一等公民是類(Class),而在AOP中則是切面(Aspect),AOP典型應用就是事務管理器。
其實在Spring IoC 容器並不依賴於AOP,所以你可以在IoC中不使用AOP,但是在 Spring 使用AOP 提供了非常方面的支持。
本文將簡單介紹AOP用法,包括各個名詞定義與舉例。
本文大部分知識點,來源於Spring 官方文檔:https://docs.spring.io/spring/docs/2.5.x/reference/aop.html
例子
下面是在Spring 中,定義一個切面:
@Aspect
public class WorldAop implements Ordered {
@Pointcut("execution(* com.anla.springaop.service.*.*(..))")
private void returnPointcut() {
}
@Before("returnPointcut()")
public void doBefore(JoinPoint joinPoint) {
String apiName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
System.out.println("========== 調用方法WorldAop:{} start ==========, " + apiName);
for (Object arg : joinPoint.getArgs()) {
System.out.println("arg:," + arg);
}
System.out.println("========== 調用方法WorldAop:{} end ==========, " + apiName);
}
@Around("returnPointcut()")
public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("pjp is :" + pjp);
return pjp.proceed();
}
@Override
public int getOrder() {
return 10;
}
}
@Aspect
@Aspect
註解,表明這個類是個切面。
例如:
@Aspect
public class NotVeryUsefulAspect {
}
@Pointcut
@Pointcut
定義一個切入點,可以理解爲正則表達式,即類方法方法執行點的表達式。
實際上,AOP切點支持在任意位置切入,但是Spring AOP 只支持部分 PointCut表達式:
execution
用於匹配方法的切入點within
限制切點爲某一些特定的類型。即對Spring 切入點的所有方法this
限定當前執行的方法的 bean實例 是某一種類型target
限制執行放的類型是某一種類型,和上一種來說是對比方法不同,使用this和使用target。args
限制執行的方法,參數是怎樣的@target
: 限制切入點,這個類具有某一種類型的註解@args
: 限制方法的參數,是使用什麼樣的註解@within
:@annotation
: 限制切入點,方法有 這個註解時候會被攔截
執行階段切面
這裏包括這幾種註解:@Before
, @AfterReturning
, @AfterThrowing
, @Around
等幾種。
分別是代表 方法執行前後的邏輯(@Before
, @AfterReturning
),以及 報錯後的邏輯@AfterThrowing
,
方法執行前後的邏輯,包括前和後 @Around
。
例如 下面 @Around
例子:
@Aspect
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
// Around 類型切面
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
}
while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
如果切面需要狀態?
如果切面不是單例的,需要狀態怎麼做?
例如熔斷降級,需要監控每一個方法,他們有不同狀態,Spring AOP提供了一種基於類似於原型模式方法:
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {
private int someState;
@Before(com.xyz.myapp.SystemArchitecture.businessService())
public void recordServiceUsage() {
// ...
}
}
即使用 @Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
這種方式去聲明一個切面,那麼每一個切入點都會有一個切面了。
參考:
覺得博主寫的有用,不妨關注博主公衆號: 六點A君。
哈哈哈,一起研究Spring: