java的proxy动态代理-Proxy类深度探究
来源:https://www.cnblogs.com/cenyu/p/6289209.html
三种代理:https://www.cnblogs.com/tuhooo/p/6601876.html
本文将利用Java Proxy类及代理模式 探究中的例子继续对Proxy进行探究,为了描述方便,本文现将场景描述一次。
场景:有一个接口叫超市即Supermarket,所有的超市都要实现这个接口,超市这个接口有两个方法,buy()和sell(),buy()用来进货,sell()用来销售。常见的超市有Walmart(沃尔玛),Carrefour(家乐福)等。现在当地的管理部门要对超市进行监控,需要在部分超市或者所有超市的行为进行监控。
实现:本对Supermarket接口进行代理,主要是参考了Proxy的源码,本文将jdk中Proxy类生成代理类的过程进行了简化,被简化后的Proxy类源码如下:
package java.lang.reflect;
import java.lang.reflect.Proxy.KeyFactory;
import java.lang.reflect.Proxy.ProxyClassFactory;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
import sun.misc.ProxyGenerator;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
public class Proxy {
/**
* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
// 参数为InvocationHandler的构造方法
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
// 获取代理类
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces){
final Class<?>[] intfs = interfaces.clone();
return getProxyClass0(loader, intfs);
}
// 获取代理类,newProxyInstance 和 getProxyClass都要调用
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
// 调用ProxyClassFactory 的apply, 并返回一个代理类
return proxyClassCache.get(loader, interfaces);
}
// 直接获取代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
{
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 利用自定义的InvocationHandler 新建一个实例
return cons.newInstance(new Object[]{h});
}
// 代理类生成工厂
private static final class ProxyClassFactory{
// ----------- 这两个参数是代理类的名称 , 即代理类的名字为$Proxy0,$proxy1...--------
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
// --------------利用传入的接口信息,生成代理类的字节码,并返回Class 对象
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
}
}
}
源码解读:
此部分需要Class类的知识,请参考java Class类探究,另Class 类的实例表示正在运行的 Java 应用程序中的类和接口(!!!)
Proxy类:
<1>方法
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
该方法用来生成一个代理类,该方法有两个参数:
第一个:classLoader
第二个:需要代理的接口,即需要代理的对象必须实现的接口,在java中,Class对象表示一个接口。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
该方法直接生成代理类对象,实质就是通过代理类的Constructor生成一个实例。
<2>变量
protectedInvocationHandlerh;
Proxy中有一个InvocationHandler变量,可以通过Proxy的构造函数传入,或者直接调用newProxyInstance(ClassLoaderloader,Class<?>[] interfaces, InvocationHandler h)时,将自定义的InvocationHandler传入。
<3>内部类
ProxyClassFactory类:
是Proxy类的内部类,生成代理类关键部分,利用传入的接口,生成一个代理类的字节码,转成一个Class对象,并返回。
代理类探究:
本文利用generator将实现了Supermarket的Walmart生成一个代理类,并且将对应的字节码输出成.class文件,转化代码所示:
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import sun.misc.ProxyGenerator;
public class Generator {
public static void gen() {
Supermarket walmart = new Walmart();
try {
// 生成代理类
Supermarket proxySupermarket = (Supermarket) ProxyFactory.getProxy(walmart,
walmart.getClass().getSuperclass().getInterfaces());
// ---- 探究 代理类 ---------
// 将Class对象写入文件生成Class字节码,将字节码写成.class文件
String proxyClassFileName = "ProxySupermarket";
byte[] classFile = ProxyGenerator.generateProxyClass(proxyClassFileName, walmart.getClass().getSuperclass().getInterfaces());
String paths = "D:/";
FileOutputStream out = null;
try {
// 将生成的.class文件保留到硬盘中
out = new FileOutputStream(paths + proxyClassFileName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e){
e.printStackTrace();
} finally{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main (String[]args){
gen();
}
}
将该.class本地反编译成java文件,如下所示:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class ProxySupermarket extends Proxy
implements Supermarket
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public ProxySupermarket(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void sell()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void buy()
throws
{
try
{
this.h.invoke(this, m4, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("Supermarket").getMethod("sell", new Class[0]);
m4 = Class.forName("Supermarket").getMethod("buy", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
从代码中可以看出,代理类只是将传入的接口实现,生成了一个新类,在类的方法中,只是将新类的Method传入InvocationHandler中,由InvocationHandler的invoke()方法调用代理后的方法,可以增加一些操作。
如上所述就是jdk的动态代理,jdk对一个对象生成代理对象时,需要该对象的接口信息,如果想对一个没有实现接口的对象进行代理,可以使用cglib。
本人认为代理模式与装饰者模式有些区别:
从设计的角度来说,装饰者模式的目的在于增强被装饰者的功能,是为了原有功能更好用;而动态代理只是为了增加额外的动作,一般而言动态代理添加的动作都与被代理者没有关系,都是一些辅助功能,如记录功能等。
从实现的角度来说,动态代理是利用反射实现的,而装饰者模式是新的对象包裹了一个原有对象,有依赖关系,是组合形式。
---------------------
作者:学渣的第六感
来源:CSDN
原文:https://blog.csdn.net/zhao123h/article/details/51413000
版权声明:本文为博主原创文章,转载请附上博文链接!