参考资料:

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));
} }

最新文章

  1. Alpha阶段总结
  2. 使用vim 查看二进制文件
  3. css知识点补充、css属性、
  4. CSS实现样式布局
  5. 从报错“无效操作,连接被关闭”探究Transaction的Timeout超时机制
  6. 封装cookie
  7. spice up your desktop
  8. HTML——超文本标记语言
  9. 微信小程序选项卡功能
  10. Dynamics CRM中跨域调用Web API 2
  11. 关于npm安装报错 网络问题等等等
  12. keepalived安装与配置,组建高可用服务器
  13. 获取各种编码(Unicode,UTF8等)的识别符
  14. 细说shiro之四:在web应用中使用shiro
  15. RNN/LSTM/GRU/seq2seq公式推导
  16. Java 面试中遇到的坑
  17. php 截取字符串指定长度
  18. linux查看日志文件内容命令(面试被常问到的问题)
  19. Python 入门(十)列表生成式
  20. struct模块-黏包的解决方法

热门文章

  1. mappedBy的作用
  2. 钓鱼(洛谷 P1717)
  3. [NOIP1998] 提高组 洛谷P1011 车站
  4. 【git】远程仓库版本回退方法
  5. 《TCP/IP详解卷1:协议》——第3章 IP:网际协议(转载)
  6. vagrant的学习 之 优化
  7. 钱币兑换问题---hdu1284(完全背包)
  8. idea、jdk、eclispe中空main方法的线程数量不一样,why?
  9. AES算法加密java实现
  10. C语言最小生成树prim算法(USACO3.1)