首先抛出问题:
1.什么是动态代理? 2.动态代理有什么用? 3.如何实现动态代理? 4.深入动态代理源码级
今天讲的是JDK实现的动态代理。据说是spring的AOP模块的核心。
那么什么是动态代理呢? 我们知道在程序中会写很多种方法,
那么现在问题来了:
我想实现在运行时期动态的改变某些写死的方法,继而增加一些我想要的方法,该怎么做呢?
动态代理实现的就是这个功能。
由此我么可以猜想,动态代理一定用到了java的反射机制。没错!来看代码
首先我们有一个接口 PInterface:
接口中给出两个公共的方法:
public void eat();
publci void end();
然后给出一个实现了此接口的实现类UserClass,我们称之为:用户类。
实现这两个方法:
public void eat(){System.out.println("吃啥");}
public void end(){System.out.println("刷碗);}
然后我们的重头戏来了:代理类ProxyClass,首先我们的这个代理类需要继承InvocationHandler接口,给出这个接口中的方法:如下
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
可以看到在这个接口中唯一的方法就是invoke方法,这个方法的用法是什么呢?一起来看。
在invoke方法中有三个参数,分别是Object类型的proxy,Method类型的method参数,数组类型的args。
首先proxy对象代表的是我们要代理的类,而method就是我们传入的方法,代理对象就是根据我们传入的方法来确定所要代理的对象,以及数组args。
我们这里给出自己定义的代理类方法:
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object ret = null;
try {
System.out.println("正在进行操作前的准备工作……");
//调用目标方法
ret = method.invoke(targetObject, args);
System.out.println("操作成功,正在进行确认处理……");
} catch (Exception e) {
e.printStackTrace();
System.out.println("error-->>" + method.getName());
throw e;
}
return ret;
首先要做的是:私有化一个Object的对象。
然后提供一个实例化代理实例的方法,在这个方法中,将Object类型的目标对象赋给使用这个方法的对象,返回当前代理对象的实例。
在invoke方法中,定义代理方法以及之前的用户类的代理方法。
我们来看一下这个方法的定义:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
再来看一下JDK对于两个参数的解释和使用说明:
@param obj the object the underlying method is invoked from
@param args the arguments used for the method call
由此可见第一个参数是实例对象,而第二个参数是唤起方法,也就是使用哪个方法来唤起代理对象。
在Client测试类中这样写:
ProxyClass dp = new ProxyClass();
PInterface userManager = (UserClass)dp.newProxyInstance(new ImpleClass());
UserClass.eat();
首先实例化我们的代理类对象。
然后调用实例化代理对象方法,赋给用户类。至于为什么代理类对象可以类型强转成用户类对象,大家可以思考一下。
最后用户类调用eat方法唤起代理对象。
最后执行结果是:
晚饭时间到
吃啥
吃炸鸡和啤酒吧
可以看到代理 类对于用户来说是透明的,用户只需要实例化一个代理类对象即可,至于代理类中的方法定义与用户无关。
用户看不到代理类是如何工作的,但是可以满足动态增加想要实现的功能的需求。
后续会继续分析Proxy.newProxyInstance()这个方法。