最近学习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
之路,漫长啊!!加油!!!
- aop.rar (12.2 KB)
- 描述: 模拟AOP源码
- 下载次数: 12
分享到:
相关推荐
通过动态代理模拟Spring AOP,通过动态代理模拟Spring AOP
模拟spring aop技术,一个小demo,希望对您理解aop有所帮助.
以注解方式模拟Spring IoC AOP,了解Spring是如何实现的.
用Spring AOP模乘坐地铁服务中的安检(对应前置通知)、刷卡进站、乘坐及刷卡出站(对应可以是环绕通知)、运行过程中的异常(异常通知)、记录此次行程(最终通知)全过程
通过模拟SpringAOP,设置四个Advice实现简单的切面编程
从http://www.cnblogs.com/sunniest/p/4543271.html 这里摘抄的源码,具体教程可以看这个文章
这两种代理方式在Spring AOP中起到关键作用,用于实现横切关注点的切面编程。通过学习它们的原理和实际应用,您将能够更好地理解和利用Spring AOP来提高您的应用程序的可维护性和可扩展性。 内容亮点: JDK动态...
Spring IOC AOP MVC 简单例子
这是一个基于spring AOP静态代理模拟的案例,可以更好的理解spring的aop作用
1、编写切面类,包含权限审核方法和日志记录方法,这两个方法将来会织入到...5、编写案例,运用Spring AOP技术,要求包含前置通知、后置通知、环绕通知、返回通知、异常返回通知。请掌握这五种通知的特点,及应用场景
java 动态代理实现,模拟了spring实现aop的原理,对学习面向切面编程的朋友有帮助!
SpringIOC和AOP实现机制模拟,来自与网络。
NULL 博文链接:https://zlx19900228.iteye.com/blog/843289
NULL 博文链接:https://johnyi.iteye.com/blog/385443
以注解方式模拟Spring_IoC,AOP,看完后可以加深理解Spring的实现.
模拟实现spring IOC AOP的例子,如果你是eclipse开发工具,解压直接导入就可以,别忘了,导入dom4j的jar包。
spring aop的具体实现与理论.AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构...
模拟spring ioc aop的功能,理解spring ioc 和 aop 的实现原理和机制。
这是一个很好的关于模拟spring的aop和ioc的源代码