spring AOP动态代理使用的是运行期织入的动态代理方式:有java原生的动态代理和cglib动态代理两种方式可选,下面我们为这两种方式分别编写一个实例,并在原理上做一些较深的介绍。
1、JAVA动态代理
java的动态代理是基于接口方法的代理,先看一个java动态代理例子:
我们先看下程序的类关系图吧
再来看看JdkDemo
@Test
public void proxy(){
Race race = new HumanRace();
PerformanceHandler handler = new PerformanceHandler(race);
Race proxyRace = (Race) Proxy.newProxyInstance(JdkDemo.class.getClassLoader(), new Class[]{Race.class}, handler);
proxyRace.race100m();
}
这就是一个动态代理的简单应用了,
这里代理了race接口,我们来看下race接口的代码
public interface Race {
void race100m();
}
这个接口就是一个跑100m的功能。
然后HumanRace实现了人跑100m
public class HumanRace implements Race {
@Override
public void race100m() {
System.out.println("human run 100m");
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
接下来就是一个实现代理接口的PerformanceHandler类
public class PerformanceHandler implements InvocationHandler {
private Object target;
private long startt;
public PerformanceHandler(Object target){
this.target = target;
}
private void begin(){
this.startt = System.currentTimeMillis();
System.out.println("开始时间:" + this.startt);
}
private void end(){
long endt=System.currentTimeMillis();
System.out.println("结束时间:"+endt+" 执行消耗:"+(endt-startt));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
begin();
Object result = method.invoke(target, args);
end();
return result;
}
}
invoke是InvocationHandler这个接口定义的方法,我们看下怎么操作的:
注意这块代码
Object result = method.invoke(target, args);
这个就是一个反射的调用,method就是race100m的方法,而target是什么对象,我们回头看下PerformanceHandler的实例化操作
Race race = new HumanRace();
PerformanceHandler handler = new PerformanceHandler(race);
传进来了一个HumanRace对象,可以通过下面的伪代码来帮助您理解上面的method.invoke操作
//这块代码是一个伪代码,拿来编译是有问题的
Method method = race.getClass().getMethod("race100m");
method.invoke(humanRace, args);
显而易见,Method就是Race的race100m的方法对象,invoke就是HumanRace对象执行这个方法。
接下来就是代理功能了,我们可以在这个代码的前后加各种不同业务的操作,begin和end就是我们这个统计性能的代码了。
我们来看下最后的方法执行
Race proxyRace = (Race) Proxy.newProxyInstance(JdkDemo.class.getClassLoader(), new Class[]{Race.class}, handler);
proxyRace.race100m();
Proxy.newProxyInstance顾名思义Proxy类帮我们新实例化了一个代理实例对象,再看看这个对象的调用运行结果
开始时间:1539925173622
human run 100m
结束时间:1539925273624 执行消耗:100002
可见代理对象在原有对象的方法上已经织入了我们添加了的业务逻辑。
总结
jdk的动态代理正如Proxy.newProxyInstance方法的几个参数表述般,我们需要注意两个点,一个是传入的是接口对象,一个传入的是Invocationhandler的实现类对象。jdk的动态代理就是代理的接口,通过实现接口实现代理的方式。
看完上面的内容我们是不是还是有很多困惑
为什么要实现动态代理
Proxy是怎么创建一个我没有定义的类的
这个我会再用一片博文来深入解决上面的这些问题。