1.接口代理,必须有接口和子实现:
实现一个代理,需要公共接口,实现接口的目标类,代理类,通过代理类构造函数传入目标类入参来持有目标类的具体实例,代为执行具体类实例方法。分为动态代理(接口实现)和静态代理,静态代理在编译时已经确定实际类
动态代理(JDK):在运行时动态生成,通过proxy类和invocationhandler接口动态生成代理类和代理对象。内部通过反射机制生成代理方法。
生成步骤:定义公共接口,实现公共接口的目标类(被代理对象)。实现invocationhandler接口的类传入被代理对象。proxy.newProxyInstance实例生成代理类实例。
原理:Proxy.getProxyClass获取到代理类,通过代理类.getConstructor生成构造器。Constructor.newInstance生成代理类实例。内部Proxy.getProxyClass其实是通过反射机制生成了一个代理类Proxy0 extend Proxy Imple 公共接口,Proxy 类持有InvocationHandler对象(入参传入的是目标类). 生成的动态代理类里边有代理接口的方法(内部调用handler.invoke(this,m3,null)),其实代理类实例调用的方法就是内部handler调用invoke,而handler.invoke我们有自己的实现。
java内存反编译出来的类:
proxy.Person;publicfinalclass$Proxy0extendsProxyimplements Person
{
privatestatic Method m1;
privatestatic Method m2;
privatestatic Method m3;
privatestatic Method m0;
/** *注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白
*为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有一个
*被代理对象的实例,不禁会想难道是....? 没错,就是你想的那样。
*
*super(paramInvocationHandler),是调用父类Proxy的构造方法。
*父类持有:protected InvocationHandler h;
*Proxy构造方法:
* protected Proxy(InvocationHandler h) {
* Objects.requireNonNull(h);
* this.h = h;
* }
*
*/public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
//这个静态块本来是在最后的,我把它拿到前面来,方便描述static {
try {
//看看这儿静态块儿里面有什么,是不是找到了giveMoney方法。请记住giveMoney通过反射得到的名字m3,其他的先不管m1 = Class.forName("java.lang.Object").getMethod("equals",newClass[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString",newClass[0]);
m3 = Class.forName("proxy.Person").getMethod("giveMoney",newClass[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
thrownew NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
thrownew NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
/** *
*这里调用代理对象的giveMoney方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
*this.h.invoke(this, m3, null);这里简单,明了。
*来,再想想,代理对象持有一个InvocationHandler对象,InvocationHandler对象持有一个被代理的对象,
*再联系到InvacationHandler中的invoke方法。嗯,就是这样。
*/publicfinalvoid giveMoney()
throws
{
try {
this.h.invoke(this, m3,null);
return;
}
catch(Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
thrownew UndeclaredThrowableException(localThrowable);
}
}
//注意,这里为了节省篇幅,省去了toString,hashCode、equals方法的内容。原理和giveMoney方法一毛一样。}
因为有继承,所以这种实现只能对接口进行代理,不能对类进行代理
参考资料:https://www.cnblogs.com/gonjan-blog/p/6685611.html
2:子类继承方式代理:Cglib代理
使用Enchancer类指定代理父类和回调拦截方法实现动态代理,在内存中创建一个代理类的子类。基于字节码实现,通过在子类中通过拦截的方式拦截父类方法调用
反射:根据路径获取class,创建class实例,根据class获取方法:method是父子类全部public,dechared是当前类的所有方法。method.invoke(实例,参数)。一般效率没有那么低,虽然有验证,递归循环等操作,但是method也放入了一些缓存