代理模式:为其他对象提供一种代理以便控制对这个对象的访问(所谓控制,就是可以在其调用行为,前后分别加入一些操作)。代理模式分类:1.静态代理(其实质是类的继承,比较容易理解)2.动态代理。
用JDK 动态代理实现面向切面编程(还有CGLIB 也可实现动态代理,且不需要真实对象类实现接口,但真实对象不能是final 类),以下Demo 实现在特定方法前后添加日志和事务的的功能。
1)Proxy 类 (真实对象的代理) 的三个参数
前两个参数用于生成$Proxy 的构造器,此构造器再以invocationHandler 为参数生成$Proxy 实例。
- classLoader: 类加载器,它由真实对象userService 得到,但其实跟userService 不是一一对应的关系;用任何一个对象都可以用同样的方法得到一样的类加载器;既然如此,用测试类本身也可以得到类加载器:this.getClass().getClassLoader(),再把this 省略,就变成了getClass().getClassLoader()。
类加载器打印出来就是:sun.misc.Launcher$AppClassLoader@18b4aac2 - interfaces: 接口数组,真实对象userService 所实现的所有接口。Proxy 用类加载器和接口数组这两个参数得到动态生成的Proxy 的Class 对象(getProxyClass0(loader, intfs)),再用此Class 对象获取其构造器(cl.getConstructor(constructorParams)),由构造器生成Proxy 实例(cons.newInstance(new Object[]{h}), 此处的h 就是Proxy 第三个参数invocationHandler).
- invocationHandler: 直译是调用处理器,它这个对象本质是Proxy 类的代理,也就是真实对象的代理 的代理。Proxy类实现了真实对象的接口,所以它的对象可以调用真实对象的方法,调用时是指派invocationHandler 去实际执行系统增强业务(即日志、事务等) 和真实业务。
2)InvocationHandler 的invoke 三个参数的作用
- proxy: 就是Proxy 的一个动态实例,用Idea debug 显示为:{$Proxy4@862} com.qf.service.impl.UserServiceImpl@5a8806ef. 这个参数在invoke 方法体内可以完全不用,所以很难理解它的作用,甚至知乎、Stackoverflow 上的回答都感觉不太对。Stackoverflow 上一个回答说作用是可以将代理对象返回以进行连续调用,并写了demo(https://stackoverflow.com/questions/22930195/understanding-proxy-arguments-of-the-invoke-method-of-java-lang-reflect-invoca),难道不需要连续调用的话就没用了吗?又查了很多资料,终于找到了一个比较符合逻辑的解释:invoke 第二个参数是method 怎么来的?$Proxy 动态实例 (即第一个参数proxy) 生成后(是class 文件),通过反向编译,可以看到里面有如下一段静态代码块(来源:(http://rejoy.iteye.com/blog/1627405)),也就是说只有proxy 实例在InvocationHandler 实现类里加载才能产生第二个参数method (静态代码块是虚拟机加载类的时候执行的,而且只执行一次),所以$Proxy 实例要把自己传给InvocationHandler 的invoke 方法。
m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);
InvocationHandler 源码中对proxy 的注释:the proxy instance that the method was invoked on
- method: 真实对象要实现的业务方法,由$Proxy 实例的静态代码块得到。
- args: 第二个参数method 的参数。
3)两个概念:系统增强服务(日志、事务、权限等) 与系统真实业务分离,放到 InvocationHandler 实现类invoke 方法里面的 这些出代码片段就是一个切面,本文Demo 中真实业务add() 就是切入点。
以下为InvocationHandler 实现类和测试类(含创建$Proxy 动态实例) 的代码。
public class DynamicProxy implements InvocationHandler {
private TransactionManager tx;
private LoggerManager log;
private Object object;
public DynamicProxy() {
}
//object 参数为真实对象,此例中为userService 对象
public DynamicProxy(TransactionManager tx, LoggerManager log, Object object) {
this.tx = tx;
this.log = log;
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
tx.begin();
log.beginLog();
Object invoke = method.invoke(object, args);
log.endLog();
tx.commit();
return invoke;
}
}
@Test
public void testDynamicAOP(){
LoggerManager log = new LoggerManager();
TransactionManager tm = new TransactionManager();
IUserService userService = new UserServiceImpl();
ClassLoader loader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
InvocationHandler handler = new DynamicProxy(tm, log, userService);
IUserService userServiceProxy = (IUserService) Proxy.newProxyInstance(loader, interfaces, handler);
userServiceProxy.add(new User("Rock"));
}