动态代理与CGLib
Posted wqff-biubiu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理与CGLib相关的知识,希望对你有一定的参考价值。
一、动态代理是利用Java反射机制实现的
JAVA反射机制:在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
类加载过程中的加载过程会在内存中生成一个代表此Class文件的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。通过这个Class的实例对象,可以知道这个类的所有属性和方法.
JDK中反射包java.lang.reflect则提供了操作这个类的任意方法和属性的设计。java.lang.reflect包中主要实体类Method、Field、Constructor分别对应着类的方法、属性及构造方法,
另外反射包中的Proxy类与InvocationHandler接口是实现了动态代理的超类与接口
java.lang.reflect.Proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
java.lang.reflect.InvocationHandler是代理实例的调用处理程序 实现的接口。
二、动态代理的实现例子
public class DynamicProxyTest {
interface IHello{ void sayHello(); } static class Hello implements IHello{ @Override public void sayHello() { System.out.println("hello world"); } } static class DynamicProxy implements InvocationHandler{ Object target; Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("welcome"); return method.invoke(target,args); } } public static void main(String[] args){ IHello target = new Hello(); System.out.println(target.getClass().getClassLoader()); System.out.println(Arrays.toString(target.getClass().getInterfaces())); System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//在对应package下生成代理类$Proxy0.class IHello hello = (IHello) new DynamicProxy().bind(target); hello.sayHello(); } }
其中Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this)这行代码生成的代理类$Proxy0.class,如下
package com.sun.proxy; import com.app.proxy.IHello; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements IHello { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void sayHello() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.app.proxy.IHello").getMethod("sayHello"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
可以看出生成的代理类
继承了Proxy,实现了target.getClass().getInterfaces()--IHello,组合了this--构造方法中super(InvocationHander)
不仅实现了被代理类接口的方法sayHello,另外重写了toString,hashCode,equals方法,但格式都是一样的
super.h.invoke(this,mx,new Object[]{varx});//super.h.invoke即invocationHandler接口的实现类DynamicProxy.invoke(),
这样导致代理类的hashCode,toString与被代理类的hashCode,toString一样,但是实际类型是不同的。下面是一些验证
public static void main(String[] args) { IHello target = new Hello(); IHello hello = (IHello) new DynamicProxy().bind(target); System.out.println("target.toString:"+target.toString());//target.toString:com.app.proxy.Hello@eed1f14 System.out.println("target.hashCode:"+target.hashCode());//target.hashCode:250421012 System.out.println("proxy.toString:"+hello.toString());//proxy.toString:com.app.proxy.Hello@eed1f14 System.out.println("proxy.hashCode:"+hello.hashCode());//proxy.hashCode:250421012 System.out.println("target == proxy:"+(target == hello));//target == proxy:false hello.sayHello(); }
以上是关于动态代理与CGLib的主要内容,如果未能解决你的问题,请参考以下文章