關關雎鳩,在河之洲。窈窕淑女,君子好逑。java
AOP
(Aspect Orient Programming
),咱們通常稱爲面向方面(切面)編程,做爲面向對象的一種補充,用於處理系統中分佈於各個模塊的橫切關注點,好比事務管理、日誌、緩存等等。 Spring
AOP
採用的是動態代理,在運行期間對業務方法進行加強,因此不會生成新類,Spring
AOP
提供了對JDK
動態代理的支持以及CGLib的支持。本章咱們不關注aop
代理類的實現,我簡單實現一個指定次序的鏈式調用。git
MethodInterceptor
定義攔截器鏈,MethodInvocation
遞歸進入下一個攔截器鏈中。類圖以下:github
public interface MethodInterceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
複製代碼
public interface MethodInvocation {
Object proceed() throws Throwable;
}
複製代碼
抽象類,實現MethodInterceptor
編程
public abstract class AbstractAspectJAdvice implements MethodInterceptor{
private Method adviceMethod;
private Object adviceObject;
public AbstractAspectJAdvice(Method adviceMethod, Object adviceObject) {
this.adviceMethod = adviceMethod;
this.adviceObject = adviceObject;
}
public Method getAdviceMethod() {
return this.adviceMethod;
}
public void invokeAdviceMethod() throws Throwable {
adviceMethod.invoke(adviceObject);
}
}
複製代碼
前置通知緩存
public class AspectJBeforeAdvice extends AbstractAspectJAdvice {
public AspectJBeforeAdvice(Method method, Object adviceObject) {
super(method, adviceObject);
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable{
this.invokeAdviceMethod();
Object o = invocation.proceed();
return o;
}
}
複製代碼
後置通知ide
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice {
public AspectJAfterReturningAdvice(Method method, Object adviceObject) {
super(method, adviceObject);
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable{
Object o = invocation.proceed();
this.invokeAdviceMethod();
return o;
}
}
複製代碼
實現MethodInvocation
,proceed()
方法遞歸實現鏈式調用。測試
public class ReflectiveMethodInvocation implements MethodInvocation {
private final Object targetObject;
private final Method targetMethod;
private final List<MethodInterceptor> interceptorList;
private int currentInterceptorIndex = -1;
public ReflectiveMethodInvocation(Object targetObject, Method targetMethod, List<MethodInterceptor> interceptorList) {
this.targetObject = targetObject;
this.targetMethod = targetMethod;
this.interceptorList = interceptorList;
}
@Override
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorList.size() - 1) {
return invokeJoinPoint();
}
this.currentInterceptorIndex++;
MethodInterceptor interceptor =
this.interceptorList.get(this.currentInterceptorIndex);
return interceptor.invoke(this);
}
private Object invokeJoinPoint() throws Throwable {
return this.targetMethod.invoke(this.targetObject);
}
}
複製代碼
模擬service
類this
public class NioCoderService {
public void testAop() {
System.out.println("http://niocoder.com/");
}
}
複製代碼
模擬通知類spa
public class TransactionManager {
public void start() {
System.out.println("start tx");
}
public void commit() {
System.out.println("commit tx");
}
public void rollback() {
System.out.println("rollback tx");
}
}
複製代碼
測試類,測試通知3d
public class ReflectiveMethodInvocationTest {
private AspectJBeforeAdvice beforeAdvice = null;
private AspectJAfterReturningAdvice afterReturningAdvice = null;
private NioCoderService nioCoderService;
private TransactionManager tx;
public void setUp() throws Exception {
nioCoderService = new NioCoderService();
tx = new TransactionManager();
beforeAdvice = new AspectJBeforeAdvice(TransactionManager.class.getMethod("start"), tx);
afterReturningAdvice = new AspectJAfterReturningAdvice(TransactionManager.class.getMethod("commit"), tx);
}
public void testMethodInvocation() throws Throwable {
Method method = NioCoderService.class.getMethod("testAop");
List<MethodInterceptor> interceptorList = new ArrayList<>();
interceptorList.add(beforeAdvice);
interceptorList.add(afterReturningAdvice);
ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, method, interceptorList);
mi.proceed();
}
public static void main(String[] args) throws Throwable {
ReflectiveMethodInvocationTest reflectiveMethodInvocationTest = new ReflectiveMethodInvocationTest();
reflectiveMethodInvocationTest.setUp();
reflectiveMethodInvocationTest.testMethodInvocation();
}
}
複製代碼
輸出:
start tx
http://niocoder.com/
commit tx
複製代碼
修改interceptorList
的順序
public void testMethodInvocation() throws Throwable {
Method method = NioCoderService.class.getMethod("testAop");
List<MethodInterceptor> interceptorList = new ArrayList<>();
interceptorList.add(afterReturningAdvice);
interceptorList.add(beforeAdvice);
ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, method, interceptorList);
mi.proceed();
}
複製代碼
輸出:
start tx
http://niocoder.com/
commit tx
複製代碼