最近学习AOP ,深感强大。本着理解框架,同时对于环绕通知的实现很困惑,于是简单的实现了 AOP 的四种通知方式(前置、后置、环绕、异常),重在体验回调的好处,不足之处请各位见谅。动态代理使用 JDK 的 Proxy 对象实现, CGLIB 不太熟悉 ...JDK 的动态代理通过接口来实现, CGLIB 是继承。
① 先是4 个用于回调的接口及一个标识接口
public interface AfterCallback extends Callback {
/**
* 后置回调
*/
void after();
}
public interface AroundCallback extends Callback {
/**
* 环绕
*
* @return 代理对象方法的返回值
*/
Object invoke(MethodHandler h);
}
public interface BeforeCallback extends Callback {
/**
* 前置回调
*/
void before();
}
public interface ThrowsCallback extends Callback {
/**异常回调
* @param ex
*/
void afterThrowing(Exception ex);
}
/**
* 回调标识接口
* @author Senny
*/
public interface Callback {
}
② 通知实现类,实现了4 个接口的方法
/**
* 模拟4个通知的实现类
*
* @author Senny
*/
public class TestAdvice implements AfterCallback, BeforeCallback,
AroundCallback, ThrowsCallback {
@Override
public void after() {
System.out.println("调用方法结束");
}
@Override
public void before() {
System.out.println("调用方法开始");
}
@Override
public Object invoke(MethodHandler h) {
System.out.println("环绕开始");
Object result = h.proceed();
System.out.println("环绕结束");
System.out.println("================");
return result;
}
@Override
public void afterThrowing(Exception ex) {
System.out.println("出现异常:" + ex.getMessage());
}
}
③ MethodHandler核心接口(同 MethodInvocation ),只提供了一个抽象方法。
/**
* 同MethodInvocation,只模拟了proceed方法
* @author Senny
*/
public interface MethodHandler {
Object proceed();
}
④ AOPProxy核心类,实现环绕和目标对象方法调用的逻辑。内部类实现 InvocationHandler 、 MethodHandler
/**
* 前置、后置、环绕、异常通知逻辑实现
*
* @author Senny
*/
public class AOPProxy {
/** 是否环绕 */
private boolean isAround = false;
/** 是否后置 */
private boolean isAfter = false;
/** 是否前置 */
private boolean isBefore = false;
/** 是否抛出通知 */
private boolean isThrow = false;
/** 目标对象 */
private Object targetObject;
/** 通知对象 */
private Callback advice;
/**
* @param targetObj
* 目标对象
* @param advice
* 通知对象
*/
public AOPProxy(Object targetObj, Callback advice) {
this.targetObject = targetObj;
this.advice = advice;
checkInterfaces(advice);
}
/**
* 获取代理对象,内部类实现方法调用
*
* @return 代理对象
*/
public Object getProxyObject() {
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
new InvocationHandlerImpl());
}
@SuppressWarnings("unchecked")
private void checkInterfaces(Object advice) {
Class[] interfaces = advice.getClass().getInterfaces();
for (Class clazz : interfaces) {
if (clazz.getName().equals("org.senny.support.AroundCallback")) {
isAround = true;
continue;
}
if (clazz.getName().equals("org.senny.support.AfterCallback")) {
isAfter = true;
continue;
}
if (clazz.getName().equals("org.senny.support.BeforeCallback")) {
isBefore = true;
continue;
}
if (clazz.getName().equals("org.senny.support.ThrowsCallback")) {
isThrow = true;
continue;
}
}
}
/** 代理对象方法调用实现 */
private class InvocationHandlerImpl implements InvocationHandler,
MethodHandler {
private Method method;
private Object[] args;
/**
* 第一层环绕
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
this.method = method;
this.args = args;
Object result = null;
// 已实现环绕
if (isAround) {
if (advice instanceof AroundCallback)
result = ((AroundCallback) advice).invoke(this);
} else
// 进入第二层
result = this.proceed();
return result;
}
/**
* 第二层前后置
*/
@Override
public Object proceed() {
if (isBefore)
if (advice instanceof BeforeCallback)
((BeforeCallback) advice).before();
// 目标对象完成方法的调用
try {
Object result = method.invoke(targetObject, args);
if (isAfter)
if (advice instanceof AfterCallback)
((AfterCallback) advice).after();
return result;
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
// InvocationTargetException 是一种包装由调用方法或构造方法所抛出异常的经过检查的异常。
if (isThrow) {
Exception targetEx = (Exception) e.getTargetException();// 获取抛出的目标异常。
((ThrowsCallback) advice).afterThrowing(targetEx);
}
// e.printStackTrace();
}
return null;
}
}
}
/**
* 目标对象 实现接口
*
* @author Senny
*/
public class TestTarget implements TargetInterface {
public String test1(String a) {
System.out.println("test1");
return a;
}
public void test2() {
System.out.println("test2");
}
@Override
public void test3() {
System.out.println("test3");
int a = 3 / 0;// 异常
System.out.println(a);
}
}
public static void main(String[] args) {
// 目标对象
TargetInterface target = new TestTarget();
// 通知对象
TestAdvice advice = new TestAdvice();
AOPProxy proxy = new AOPProxy(target, advice);
//代理对象 JDK以接口的方式实现动态代理
TargetInterface proxyObject = (TargetInterface) proxy.getProxyObject();
proxyObject.test1("测试方法1");
proxyObject.test2();
proxyObject.test3();
}
测试结果如下:
环绕开始
调用方法开始
test1
调用方法结束
环绕结束
================
环绕开始
调用方法开始
test2
调用方法结束
环绕结束
================
环绕开始
调用方法开始
test3
出现异常:/ by zero
环绕结束
================
PS:代码敲完,感觉对 Spring AOP 理解加深了。曾经看过 Robbin 大哥的一篇关于框架学习方法的帖子,大概意思是说,不能拘泥于配置方法的记忆,关键是理解框架为什么要这么做,以及怎么做的。 System Architect 之路,漫长啊!!加油!!!