1. 自己实现代理类
public interface BizDemo {
void helloGirl(String name);
void helloBoy(String name);
}
public class BizDemoImpl implements BizDemo{
@Override
public void helloGirl(String name) {
System.out.println( name + "helloGirl in BizDemoImpl");
}
@Override
public void helloBoy(String name) {
System.out.println( name + "helloBoy in BizDemoImpl");
}
}
public class BizDemoImplProxy implements BizDemo {
private BizDemo real;
BizDemoImplProxy(BizDemo real) {
this.real = real;
}
@Override
public void helloGirl(String name) {
System.out.println("proxy by BizDemoImplProxy");
this.real.helloGirl(name);
}
@Override
public void helloBoy(String name) {
System.out.println("proxy by BizDemoImplProxy");
this.real.helloBoy(name);
}
}
public static void main(String[] args) {
BizDemo demo = new BizDemoImpl();
demo.helloGirl("Lucy");
BizDemo demoProxy = new BizDemoImplProxy(demo);
demoProxy.helloGirl("Lucy");
}
//输出
LucyhelloGirl in BizDemoImpl
proxy by BizDemoImplProxy
LucyhelloGirl in BizDemoImpl
2. 用java动态代理生成类
- 首先让我们忘掉对BizDemoImpl做代理,看看java自动生成代理类的效果
先实现一个InvocationHandler
public class ProxyHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy invoke." + args[0]);
return null;
}
}
如下可以看到,只要有BizDemo这个接口,就可以通过java动态代理生成一个类,这个类拥有接口BizDemo的一切方法,并且把所有方法调用,都透传到ProxyHandler的invoke方法中。
public static void main(String[] args) {
Class[] inf = new Class[] {BizDemo.class};
BizDemo d = (BizDemo) Proxy.newProxyInstance(BizDemo.class.getClassLoader(), inf, new ProxyHandler());
d.helloGirl("javaDynamicProxy");
d.helloBoy("javaDynamicProxy boy");
}
//输出
proxy invoke.javaDynamicProxy
proxy invoke.javaDynamicProxy boy
尽管我们可以让java给我们动态生成一个类,这个类实现了BizDemo接口,但是这样的类没有太多的实际意义。我们的目的是代理BizDemoImpl,看看我们是怎么达到的
- 让代理产生实际意义,对BizDemoImpl做代理
其实很简单,我们只要把BizDemoImpl实例塞到ProxyHandler里,在invoke方法再调一次不就行了吗,于是我们创新创建一个Handler: ProxyHandler1
- 让代理产生实际意义,对BizDemoImpl做代理
public class ProxyHandler1 implements InvocationHandler {
private BizDemo real;
public ProxyHandler1(BizDemo real) {
this.real = real;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy invoke." + args[0]);
method.invoke(real, args);
return null;
}
}
public static void main(String[] args) {
BizDemo demo = new BizDemoImpl();
Class[] inf = new Class[] {BizDemo.class};
BizDemo d = (BizDemo) Proxy.newProxyInstance(BizDemo.class.getClassLoader(), inf, new ProxyHandler1(demo));
d.helloGirl("javaDynamicProxy");
d.helloBoy("javaDynamicProxy boy");
}
//输出
proxy invoke.javaDynamicProxy
javaDynamicProxyhelloGirl in BizDemoImpl
proxy invoke.javaDynamicProxy boy
javaDynamicProxy boyhelloBoy in BizDemoImpl
可以看到,动态代理生成的类,真正的代理了BizDemoImpl实例demo
单从上述例子看,用java动态代理,反而更复杂类,要引入InvocationHandler和java.lang.reflect.Proxy,但仔细想是有好处的,
第一,不管用户的interface有多少个方法,最终都代理收拢到InvocationHandler的invoke
第二,如果项目有很多interface要代理,代理类会成倍增加,难以维护
java动态代理类图如下,
$Proxxy0是java动态生成的类,这个类继承类Proxy实现了BizDemo接口,也就是上述的main中的d,对d的调用,先到$Proxy0, $Proxxy0委托给父类的Proxy的成员变量InvocationHandler 实例,即ProxyHandler1实例;而ProxyHandler1实例的invoke方法里最终调用了被代理的BizDemoImpl。
总之看起来很绕,框架类的代码往往牺牲直观来实现通用和简洁
3. 神秘的动态生成的代理类
所谓动态生成,就是java在运行时生成,这种类只在内存,当然也可以把它保存到文件,看看它神秘的面纱
public static void main(String[] args) {
BizDemo demo = new BizDemoImpl();
Class[] inf = new Class[] {BizDemo.class};
BizDemo d = (BizDemo) Proxy.newProxyInstance(BizDemo.class.getClassLoader(), inf, new ProxyHandler1(demo));
d.helloGirl("javaDynamicProxy");
d.helloBoy("javaDynamicProxy boy");
// 保存动态类到文件
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", BizDemoImpl.class.getInterfaces());
try {
File file = new File("Proxy0.class");
FileOutputStream out = new FileOutputStream(file);
out.write(classFile);
} catch (Exception e) {
}
|
动态类代码如下,重要的三个点
- 动态类$Proxy0 extends Proxy implements BizDemo,继承Proxy实现BizDemo
- 所有调实现BizDemo接口的方法,都委托到父类Proxy的 h,对这个例子,就是ProxyHandler1实例
- Proxy的成员h,是抽象接口InvocationHandler,具体类由用户自己定制,体现了,依赖抽象而不依赖具体实现类的常用设计思想。
说明:$Proxy0的0是java动态生成代理类的编号,如果有多个编号自动递增
public final class $Proxy0 extends Proxy implements BizDemo {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
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 helloGirl(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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 void helloBoy(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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"));
m4 = Class.forName("test.BizDemo").getMethod("helloGirl", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("test.BizDemo").getMethod("helloBoy", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
4. 生成代理类的老方法
public static void main(String[] args) {
BizDemo demo = new BizDemoImpl();
//1. 获取代理类的Class对象
Class<?> proxyClass = Proxy.getProxyClass(BizDemo.class.getClassLoader(), new Class[] {BizDemo.class});
try {
// 2. 获取构造函数反射
Constructor con = proxyClass.getConstructor(InvocationHandler.class);
//3. 通过反射创建类实例
BizDemo demo1 = (BizDemo) con.newInstance(new ProxyHandler1(demo));
demo1.helloGirl("proxyclass");
} catch (Exception e) {
e.printStackTrace();
}
}
如果看源码可以得知Proxy.newProxyInstance其实是封装了上述过程。
5. 可能遇到的坑
public static void main(String[] args) {
BizDemo demo = new BizDemoImpl();
Class[] inf = new Class[] {BizDemo.class};
BizDemo d = (BizDemo) Proxy.newProxyInstance(BizDemo.class.getClassLoader(), inf, new ProxyHandler1(demo));
BizDemo d1 = (BizDemo) Proxy.newProxyInstance(BizDemo.class.getClassLoader(), BizDemoImpl.class.getInterfaces(), new ProxyHandler1(demo));
BizDemo d2 = (BizDemo) Proxy.newProxyInstance(BizDemo.class.getClassLoader(), BizDemo.class.getInterfaces(), new ProxyHandler1(demo));
}
d和d1都没问题,d2会报错,因为BizDemo.class.getInterfaces()返回长度0的的Class数组,具体可以看getInterfaces的接口注释说明
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy invoke." + args[0]);
method.invoke(real, args);
// method.invoke(proxy, args);// 导致递归调用
return null;
}
invoke传入的proxy看起来用不到。在ProxyHandler1的invoke方法中,传入的proxy是$Proxy0,如果用method.invoke(proxy, args),会递归调用,最终导致递归栈溢出。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。