自Java1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理示例。在sun刚推出动态代理时,还很难想象它有多大的实际用途,现在终于发现动态代理技术是实现AOP的绝好底层技术。
1.InvocationHandler接口
InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。InvocationHandler接口也被称为拦截器。
2.Proxy类
Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。这样描述可能很抽象,我们通过demo代码示例来解释。
3.代码示例
1)业务接口
/**
* 支付接口
*/
public interface IPay {
public void wechatPay();
}
2)支付接口的业务类实现
package com.zhangzz.service.impl;
import com.zhangzz.service.IPay;
/**
* 支付实现接口
*/
public class PayImpl implements IPay {
@Override
public void wechatPay() {
System.out.println("欢迎使用微信支付!");
}
}
3)横切逻辑InvocationHandler接口实现
package com.zhangzz.invocation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CommonHandler implements InvocationHandler {
/**
* 需要增强的目标类
*/
private Object target;
/**
* 保存业务方法执行的开始时间
*/
private final ThreadLocal<Long> local = new ThreadLocal();
/**
* 通过该构造方法将目标类传进来。
* @param obj
*/
public CommonHandler(Object obj){
this.target = obj;
}
/**
*
* @param proxy 最终生成的代理实例
* @param method 代理目标实例的某个方法,通过该参数可以发起目标实例方法的反射调用
* @param args 被代理实例某个方法的入参,再方法反射调用时使用。
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始执行");
local.set(System.currentTimeMillis());
//通过反射机制调用目标类的业务方法,该行注释以上的代码为AOP的前置增强代码逻辑
Object obj = method.invoke(target,args);
//下面的为后置增强逻辑
System.out.println("执行时间为:"+(System.currentTimeMillis()-local.get())+"ms");
return obj;
}
}
3)代理目标类,实现代理示例
package com.zhangzz;
import com.zhangzz.invocation.CommonHandler;
import com.zhangzz.service.IPay;
import com.zhangzz.service.impl.PayImpl;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
//希望被代理的目标业务类
IPay pay = new PayImpl();
//Proxy.newProxyInstance(...)的第一个参数,必须为目标类的类加载器,第二个参数为目标类的接口(数组),第三个为横切类的实例
IPay proxyPay = (IPay) Proxy.newProxyInstance(pay.getClass().getClassLoader(),pay.getClass().getInterfaces(),new CommonHandler(pay));
proxyPay.wechatPay();
}
}
通过以上代码结合注释,应该能很容易理解jdk的动态代理了。在横切的前置增强和后置增强,可以很轻松插入额外的逻辑,如事务管理、性能监控、权限控制等,完成我们重复的横切逻辑代码。