Spring AOP简单模拟

最近学习AOP ,深感强大。本着理解框架,同时对于环绕通知的实现很困惑,于是简单的实现了 AOP 的四种通知方式(前置、后置、环绕、异常),重在体验回调的好处,不足之处请各位见谅。动态代理使用 JDKProxy 对象实现, 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核心类,实现环绕和目标对象方法调用的逻辑。内部类实现 InvocationHandlerMethodHandler

/**
 * 前置、后置、环绕、异常通知逻辑实现
 * 
 * @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 之路,漫长啊!!加油!!!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值