理解:不直接访问目标类,通过代理类调用目标类来完成操作。
简而言之就是直接调用变为了间接调用。
好处:在代理类调用目标类之前和之后去添加一些预处理和后处理的操作,扩展不属于目标类的功能。
静态代理:需要我们事先编写目标类对应的代理类代码,然后编译生成字节码文件。
在程序运行时直接去读这些字节码文件进行运行。
动态代理:不需要事先给目标类编写代理类代码,而是在运行中通过反射自动生成代理对象(以JDK动态代理举例)。
JDK动态代理是基于Java的反射机制实现的。使用jdk中接口和类实现代理对象的动态创建。
JDK的动态要求目标对象必须实现接口,这是java设计上的要求。
从jdk1.3以来, java语言通过java.lang.reflect包提供三个类支持代理模式Proxy, Method和 InovcationHandler.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public class TestReflect {
public static void main(String[] args) {
//System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
ProxyHandler proxyHandler = new ProxyHandler();
List list = (List)proxyHandler.getInstance(new ArrayList());
list.add("这里代理的是ArrayList类");
}
}
//实现InvocationHandler的Handler
class ProxyHandler implements InvocationHandler{
private Object targetObj;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前");
Object invoke = method.invoke(targetObj, args);
System.out.println("执行后");
return invoke;
}
public Object getInstance(Object targetObj){
this.targetObj=targetObj;
//创建一个代理类,参数固定: 目标对象类加载器,目标对象接口,实现了InvocationHandler的Handler
return Proxy.newProxyInstance(
targetObj.getClass().getClassLoader(),
targetObj.getClass().getInterfaces(),
this
);
}
}
由于ArrayList实现了List接口,我们直接拿ArrayList进行测试。
demo中并没有事先编写ArrayList的代理类,为什么能够代理ArrayList类呢?
Proxy类中的newProxyInstance会调用getProxyClass0方法getProxyClass0会从proxyClassCache中获取Class>proxyClassCache构建的第二个参数 ProxyClassFactory()中apply()方法会生成字节码ProxyGenerator.generateProxyClass()会根据saveGeneratedFiles这个boolean值判断是否在本地生成字节码文件我们在测试代码中加入System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true")这句话就会在本地生成代理类的字节码文件。 public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{ /*
* Look up or generate the designated proxy class.
*/
Class> cl = getProxyClass0(loader, intfs);
//忽略其他代码
private static Class> getProxyClass0(ClassLoader loader,
Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
private static final WeakCache[], Class>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static final class ProxyClassFactory
implements BiFunction[], Class>>
{
// 忽略其他代码
@Override
public Class> apply(ClassLoader loader, Class>[] interfaces) {
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
public static byte[] generateProxyClass(final String var0, Class>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
// 忽略其他代码
}
}
从图中可以看出,代理类对象实现了ArrayList类中实现的所有接口,并且继承了一个Proxy类。
Proxy类中有定义InvocationHandler 成员属性,
protected InvocationHandler h;
又因为代理类中有目标类中的所有方法,即可通过调用Proxy类的InvocationHandler的实现类的invoke方法来完成对目标类的代理。
jdk动态代理的缺陷:
Java是单继承机制,目标类如果继承了一些父类的方法,那么代理类就无法操作那些方法;(因为代理类必须继承Proxy类,那就无法继承目标类的父类了)目标类没有接口就无法实现动态代理,显然不合理。
版权声明:我们致力于保护作者版权,注重分享,被刊用文章【java动态代理(动态代理)】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!;
工作时间:8:00-18:00
客服电话
电子邮件
beimuxi@protonmail.com
扫码二维码
获取最新动态
