参考资料:
http://www.importnew.com/15420.html
http://www.cnblogs.com/techyc/p/3455950.html
Spring是借助了动态代理(JDK dynamic proxy)和CGlib两种技术实现AOP的,本文将学习前人的例子使用动态代理模拟AOP的特性。
1. 环境
Java: jdk1.8.0_144
2. 学习动态代理Proxy.newProxyInstance()方法
它的三个参数如下
参数名 | 类型 | 说明 |
loader | ClassLoader | 被代理类的类加载器 |
interfaces | Class<?>[] | 被代理类实现的interface集合 |
h | InvocationHandler | 被代理类的所有方法调用,都会绑定到java.lang.reflect.InvocationHandler接口的invoke方法执行 |
3. 实现思路
- 通过JDK dynamic proxy代理目标对象
- 覆盖InvocationHandler的invoke方法,包装被代理对象的方法调用,动态添加逻辑来实现类似于after/before/around的AOP功能
在一定程度上,实现的思路与装饰器模式相似,它们区别在于
- 装饰器模式中的包装类需要知道被包装类的接口细节,而这里不需要
- 装饰器模式不需要使用反射和代理,而这里需要
4. 代码解析
https://github.com/hivsuper/study/tree/master/study-aop
- 将被代理的类及其接口
public interface Calculator { public int add(int a, int b); }
public class CalculatorImpl implements Calculator { @Override public int add(int a, int b) { return a + b; } }
- 绑定被代理对象的调度接口
import java.lang.reflect.InvocationHandler; public abstract class AbstractHandler implements InvocationHandler { private Object targetObject; public Object getTargetObject() { return targetObject; } public void setTargetObject(Object targetObject) { this.targetObject = targetObject; } }
- 生成代理的简单工厂
import java.lang.reflect.Proxy; import java.util.List; public class ProxyFactory { public static Object getProxy(Object targetObject, List<AbstractHandler> handlers) { Object proxyObject = null; if (handlers.size() > 0) { proxyObject = targetObject; for (AbstractHandler abstractHandler : handlers) { abstractHandler.setTargetObject(proxyObject); proxyObject = Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), abstractHandler); } return proxyObject; } else { return targetObject; } } }
- 测试类
import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.Test; import org.lxp.study.aop.AbstractHandler; import org.lxp.study.aop.ProxyFactory; public class CalculatorImplTest { @Test public void testAdd() throws Exception { Calculator calculator = new CalculatorImpl(); AbstractHandler before = new AbstractHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("...before..."); return method.invoke(getTargetObject(), args); } }; AbstractHandler after = new AbstractHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(getTargetObject(), args); System.out.println("...after..."); return result; } }; AbstractHandler around = new AbstractHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { StringBuilder sb = new StringBuilder(); for (Object arg : args) { sb.append(arg).append(","); } System.out.println("Parameters:" + sb.substring(0, sb.length() - 1)); Object result = method.invoke(getTargetObject(), args); System.out.println("Result:" + result); return result; } }; List<AbstractHandler> handlers = new ArrayList<AbstractHandler>(); handlers.add(before); handlers.add(after); handlers.add(around); Calculator proxy = (Calculator) ProxyFactory.getProxy(calculator, handlers); Assert.assertEquals(30, proxy.add(20, 10)); } }