当前位置: 首页 > news >正文

Java 代理模式-JDK动态代理

Java 代理模式-JDK动态代理

在软件开发中,设计模式是解决特定问题的一种通用方法,它帮助我们以更高效、更灵活的方式构建复杂的系统。代理模式(Proxy Pattern)作为结构型设计模式之一,广泛应用于各种场景。其核心思想是通过引入代理对象,为目标对象的访问提供一种间接方式,这种间接性不仅提升了代码的扩展性和维护性,还为功能的增强和安全控制提供了便利。

23种设计模式

一、创建型模式 (5个)

核心思想:处理对象创建的复杂性,将对象的创建与使用分离。

  1. 单例模式 (Singleton)
  2. 工厂方法模式 (Factory Method)
  3. 抽象工厂模式 (Abstract Factory)
  4. 建造者模式 (Builder)
  5. 原型模式 (Prototype)

二、结构型模式 (7个)

核心思想:关注类和对象的组合,形成更大的结构。

  1. 适配器模式 (Adapter)
  2. 装饰器模式 (Decorator)
  3. 代理模式 (Proxy)
  4. 外观模式 (Facade)
  5. 桥接模式 (Bridge)
  6. 组合模式 (Composite)
  7. 享元模式 (Flyweight)

三、行为型模式 (11个)

核心思想:关注对象之间的通信和职责分配。

  1. 观察者模式 (Observer)
  2. 模板方法模式 (Template Method)
  3. 策略模式 (Strategy)
  4. 职责链模式 (Chain of Responsibility)
  5. 状态模式 (State)
  6. 命令模式 (Command)
  7. 迭代器模式 (Iterator)
  8. 中介者模式 (Mediator)
  9. 备忘录模式 (Memento)
  10. 访问者模式 (Visitor)
  11. 解释器模式 (Interpreter)

一、代理模式

在实际应用中,代理模式可以分为静态代理和动态代理静态代理在编译时就确定了代理类的结构,而动态代理则通过运行时动态生成代理类,灵活应对多样化的需求。无论是为方法增加日志记录,性能监控,还是实现安全控制,代理模式都能够提供强大的支持。

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。
在这里插入图片描述

二、静态代理

(一)静态代理

静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。

(二)静态代理简单实现

基于前面讨论的代理模式 UML 类图。本示例模拟了一个用户服务,在添加用户前后添加日志记录功能。

1、定义服务接口

/*** 用户服务接口(interface)* 定义代理类和真实类共用的方法*/
public interface UserService {void addUser(String username);void deleteUser(String username);
}

2、被代理对象实现接口,完成具体的业务逻辑

UserServiceImpl类实现UserService接口。UserServiceImpl可以具体实施addUser()和deleteUser()动作:

/*** 用户服务实现类(RealSubject)* 包含实际的业务逻辑*/
public class UserServiceImpl implements UserService {@Overridepublic void addUser(String username) {// 模拟添加用户的业务逻辑System.out.println("添加用户: " + username);try {// 模拟一些处理时间Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 这里可能有数据库操作等复杂逻辑}@Overridepublic void deleteUser(String username) {// 模拟删除用户的业务逻辑System.out.println("删除用户: " + username);try {// 模拟一些处理时间Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 这里可能有数据库操作等复杂逻辑}
}

3、代理类实现接口,完成委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

UserServiceProxy类,这个类也实现了UserService接口,但是还另外持有一个实现UserService接口的对象realService。由于实现了UserService接口,同时持有一个实现UserService接口的对象,那么它可以代理实现UserService接口的对象执行addUser()和deleteUser()方法。

/*** 用户服务代理类(静态代理 Proxy)* 在编译时就已经确定,实现了相同的接口*/
public class UserServiceProxy implements UserService {// 持有真实主题的引用private UserService realService;public UserServiceProxy() {// 在代理类中创建真实对象this.realService = new UserServiceImpl();}// 也可以通过构造函数注入真实对象,增加灵活性public UserServiceProxy(UserService realService) {this.realService = realService;}@Overridepublic void addUser(String username) {// 预处理:记录日志、验证权限等preAddUser(username);// 调用真实主题的方法realService.addUser(username);// 后处理:记录日志、更新缓存等postAddUser(username);}@Overridepublic void deleteUser(String username) {// 预处理preDeleteUser(username);// 调用真实主题的方法realService.deleteUser(username);// 后处理postDeleteUser(username);}// 预处理方法private void preAddUser(String username) {System.out.println("[日志] 开始添加用户: " + username + ",时间: " + new java.util.Date());// 这里可以添加权限验证等逻辑}// 后处理方法private void postAddUser(String username) {System.out.println("[日志] 成功添加用户: " + username + ",时间: " + new java.util.Date());// 这里可以添加缓存更新等逻辑}// 删除用户的预处理方法private void preDeleteUser(String username) {System.out.println("[日志] 开始删除用户: " + username + ",时间: " + new java.util.Date());}// 删除用户的后处理方法private void postDeleteUser(String username) {System.out.println("[日志] 成功删除用户: " + username + ",时间: " + new java.util.Date());}
}

4、客户端使用代理

/*** 客户端类* 通过代理类使用服务,不需要知道背后的真实实现*/
public class Client {public static void main(String[] args) {System.out.println("=== 使用静态代理 ===");// 创建代理对象UserService userService = new UserServiceProxy();// 通过代理对象调用方法userService.addUser("张三");System.out.println();userService.deleteUser("李四");System.out.println("\n=== 使用依赖注入的方式 ===");// 也可以通过构造函数注入真实对象UserService realService = new UserServiceImpl();UserService proxyWithInjection = new UserServiceProxy(realService);proxyWithInjection.addUser("王五");}
}

这里并没有直接通过UserServiceImpl(被代理对象)来执行addUser()和deleteUser()方法,而是通过UserServiceProxy(代理对象)来代理执行了,这就是代理模式。

在这里插入图片描述

代理模式最主要的就是有一个公共接口(UserService),一个被代理类(UserServiceImpl),一个代理类(UserServiceProxy),代理类持有被代理类的实例,代为执行被代理类实例方法。上面说到,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。比如在添加操作前,进行添加日志,在结束后,也添加日志等等操作.

这种操作,也是使用代理模式的一个很大的优点。最直白的就是在Spring中的面向切面编程(AOP),我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。其实也是切面思想的主要思路

三、动态代理

(一)动态代理

代理类在程序运行时创建的代理方式被成为动态代理。

我们上面静态代理的例子中,代理类(UserServiceProxy)是自己定义好的,在程序运行之前就已经编译完成。

然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。

相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

(二)动态代理简单实现

JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。

InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类

的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建

一个符合某一接口的实例,生成目标类的代理对象。

在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象

1、定义服务接口

首先,我们创建一个Person接口。这个接口就是学生(被代理类),和班长(代理类)的公共接口,他们都有上交班费的行为。这样,学生上交班费就可以让班长来代理执行。

/*** 创建Person接口*/
public interface Person {//上交班费void giveMoney();
}

2、被代理对象实现接口,完成具体的业务逻辑

Student类实现Person接口。

public class Student implements Person {private String name;public Student(String name) {this.name = name;}@Overridepublic void giveMoney() {try {//假设数钱花了一秒时间Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(name + "上交班费50元");}
}

再定义一个检测方法执行时间的工具类,在任何方法执行前先调用start方法,执行后调用finsh方法,就可以计算出该方法的运行时间,这也是一个最简单的方法执行时间检测工具。

public class MonitorUtil {private static ThreadLocal<Long> tl = new ThreadLocal<>();public static void start() {tl.set(System.currentTimeMillis());}//结束时打印耗时public static void finish(String methodName) {long finishTime = System.currentTimeMillis();System.out.println(methodName + "方法耗时" + (finishTime - tl.get()) + "ms");}
}

3、代理类实现接口,完成委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

创建StuInvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。在invoke方法中执行被代理对象target的相应方法。在代理过程中,我们在真正执行被代理对象的方法前加入自己其他处理。这也是Spring中的AOP实现的主要原理,这里还涉及到一个很重要的关于java反射方面的基础知识。

public class StuInvocationHandler<T> implements InvocationHandler {//invocationHandler持有的被代理对象T target;public StuInvocationHandler(T target) {this.target = target;}/*** proxy:代表动态代理对象* method:代表正在执行的方法* args:代表调用目标方法时传入的实参*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理执行" +method.getName() + "方法");  //代理过程中插入监测方法,计算该方法耗时MonitorUtil.start();Object result = method.invoke(target, args);MonitorUtil.finish(method.getName());return result;}
}

4、客户端使用操作与分析

public class ProxyTest {public static void main(String[] args) {//创建一个实例对象,这个对象是被代理的对象Person zhangsan = new Student("张三");//创建一个与代理对象相关联的InvocationHandlerInvocationHandler stuHandler = new StuInvocationHandler<Person>(zhangsan);//创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);//代理执行上交班费的方法stuProxy.giveMoney();}
}

创建了一个需要被代理的学生张三,将zhangsan对象传给了stuHandler中,我们在创建代理对象stuProxy时,将stuHandler作为参数了的,上面也有说到所有执行代理对象的方法都会被替换成执行invoke方法,也就是说,最后执行的是StuInvocationHandler中的invoke方法。

动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。例如,这里的计时,所有的被代理对象执行的方法都会被计时,然而我只做了很少的代码量。

动态代理的过程,代理对象和被代理对象的关系不像静态代理那样一目了然,清晰明了。因为动态代理的过程中,我们并没有实际看到代理类,也没有很清晰地的看到代理类的具体样子,而且动态代理中被代理对象和代理对象是通过InvocationHandler来完成的代理过程的,其中具体是怎样操作的,为什么代理对象执行的方法都会通过InvocationHandler中的invoke方法来执行。带着这些问题,我们就需要对java动态代理的源码进行简要的分析,弄清楚其中缘由。

四、动态代理原理分析

我们利用Proxy类的newProxyInstance方法创建了一个动态代理对象,查看该方法的源码,发现它只是封装了创建动态代理类的步骤

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException {Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();//防御性拷贝(Defensive Copy),保护内部数据不受外部修改的影响//.clone() 操作创建了 interfaces 数组的一个副本。这样,Proxy 类内部使用的 intfs 就是一个私有的、不受外界干扰的数组。无论外部代码如何修改原始的 interfaces 数组,都不会影响到代理类的生成和代理实例的行为。final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** Look up or generate the designated proxy class.*/Class<?> cl = getProxyClass0(loader, intfs);//动态生成代理类的 Class 对象//首先,它会在一个缓存中查找是否已经存在为这个特定的类加载器和接口组合生成过的代理类。如果找到了,就直接返回缓存的 Class 对象。这提高了性能,避免了重复生成相同的类。//如果在缓存中没有找到,它就会动态地生成一个新的代理类。/** Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}/*** parameter types of a proxy class constructor 指定代理类的构造函数参数类型* constructorParams 是一个在 Proxy 类中定义的静态变量:* private static final Class<?>[] constructorParams = { InvocationHandler.class };*/final Constructor<?> cons = cl.getConstructor(constructorParams);//获取代理类的构造器对象//获取代理类中那个唯一的、参数类型为 InvocationHandler.class 的公共构造方法。final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}return cons.newInstance(new Object[]{h});//反射调用构造器,实例化代理对象//方法调用被委托给其内部持有的 InvocationHandler 实例 h。//调用 h 的 invoke 方法。//在 invoke 方法内部,你可以通过 method 参数知道哪个方法被调用了,通过 args 参数获得调用参数,然后插入你的自定义逻辑(如AOP中的前置通知、后置通知),最后通过 method.invoke(realSubject, args) 来调用真实对象的方法。} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}

重点是这四处位置:

final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {//目标类实现的接口不能大于65535if (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//已经生成过代理类会放到cache里,没有生成过的话,会由ProxyClassFactory创建。//因此,我们可以直接找到ProxyClassFactory,查看代理类是如何创建的。return proxyClassCache.get(loader, interfaces);
}

因此,我们可以继续找到ProxyClassFactory,查看代理类是如何创建的。

//代理类生成工厂
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {//代理类名称前缀private static final String proxyClassNamePrefix = "$Proxy";//用原子类来生成代理类的序号, 以此来确定唯一的代理类private static final AtomicLong nextUniqueNumber = new AtomicLong();@Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);for (Class<?> intf : interfaces) {//这里遍历interfaces数组进行验证, 主要做三件事情//1.intf是否可以由指定的类加载进行加载//2.intf是否是一个接口//3.intf在数组中是否有重复}//生成代理类的包名String proxyPkg = null;//生成代理类的访问标志, 默认是public final的int accessFlags = Modifier.PUBLIC | Modifier.FINAL;for (Class<?> intf : interfaces) {//获取接口的访问标志int flags = intf.getModifiers();//如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同if (!Modifier.isPublic(flags)) {//生成的代理类的访问标志设置为finalaccessFlags = Modifier.FINAL;//获取接口全限定名, 例如:java.util.CollectionString name = intf.getName();int n = name.lastIndexOf('.');//剪裁后得到包名:java.utilString pkg = ((n == -1) ? "" : name.substring(0, n + 1));//生成的代理类的包名和接口包名是一样的if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {//代理类如果实现不同包的接口, 并且接口都不是public的, 那么就会在这里报错throw new IllegalArgumentException("non-public interfaces from different packages");}}}//如果接口访问标志都是public的话, 那生成的代理类都放到默认的包下:com.sun.proxyif (proxyPkg == null) {proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}//生成代理类的序号long num = nextUniqueNumber.getAndIncrement();//生成代理类的全限定名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0String proxyName = proxyPkg + proxyClassNamePrefix + num;//这里是核心, 用ProxyGenerator来生成字节码, 该类放在sun.misc包下byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName,interfaces, accessFlags);try {//根据二进制文件生成相应的Class实例return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {throw new IllegalArgumentException(e.toString());}}
}

该工厂的apply方法会被调用用来生成代理类的Class对象.

  1. 在代码中可以看到JDK生成的代理类的类名是“$Proxy”+序号。
  2. 如果接口是public的,代理类默认是public final的,并且生成的代理类默认放到com.sun.proxy这个包下。
  3. 如果接口是非public的,那么代理类也是非public的,并且生成的代理类会放在对应接口所在的包下。
  4. 如果接口是非public的,并且这些接口不在同一个包下,那么就会报错。

最应该关注的是 Class<?> cl = getProxyClass0(loader, intfs);这句,这里产生了代理类,后面代码中的构造器也是通过这里产生的类来获得,可以看出,这个类的产生就是整个动态代理的关键,由于是动态生成的类文件,我这里不具体进入分析如何产生的这个类文件,只需要知道这个类文件时缓存在java虚拟机中的,我们可以通过下面的方法将其打印到文件里面,一睹真容:


byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",Student.class.getInterfaces());
String path = "D:\\JavaProject\\Test\\bin\\proxy\\StuProxy.class";
try(FileOutputStream fos = new FileOutputStream(path)) {fos.write(classFile);fos.flush();System.out.println("代理类class文件写入成功");
} catch (Exception e) {System.out.println("写文件错误");
}

对这个class文件进行反编译

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;import proxy.Person;public final class $Proxy0 extends Proxy implements Person {private static Method m1;private static Method m2;private static Method m3;private static Method m0;/*** 注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白* 为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有一个* 被代理对象的实例.* <p>* 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", new Class[]{Class.forName("java.lang.Object")});m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m3 = Class.forName("proxy.Person").getMethod("giveMoney", 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());}}/*** 这里调用代理对象的giveMoney方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。* this.h.invoke(this, m3, null);这里简单,明了。* 来,再想想,代理对象持有一个InvocationHandler对象,InvocationHandler对象持有一个被代理的对象,* 再联系到InvacationHandler中的invoke方法。嗯,就是这样。*/public final void giveMoney()throws {try {this.h.invoke(this, m3, null);return;} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}//注意,这里为了节省篇幅,省去了toString,hashCode、equals方法的内容。原理和giveMoney方法一毛一样。}

jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件时放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。通过对这个生成的代理类源码的查看,我们很容易能看出,动态代理实现的具体过程。

我们可以对InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。

代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。也就是说,动态代理通过中介类实现了具体的代理功能。

总结:生成的代理类:$Proxy0 extends Proxy implements Person,我们看到代理类继承了Proxy类,所以也就决定了java动态代理只能对接口进行代理Java的继承机制注定了这些动态代理类们无法实现对class的动态代理

五、InvocationHandler接口和Proxy类分析

InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法
看下官方文档对InvocationHandler接口的描述:

{@code InvocationHandler} is the interface implemented bythe <i>invocation handler</i> of a proxy instance.<p>Each proxy instance has an associated invocation handler.When a method is invoked on a proxy instance, the methodinvocation is encoded and dispatched to the {@code invoke}method of its invocation handler.{@code InvocationHandler} 是代理实例的 调用处理器 实现的接口。每个代理实例都有一个关联的调用处理器。当在代理实例上调用方法时,方法调用被编码并分发到其调用处理器的 {@code invoke} 方法

当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法:

    /*** proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0* method:我们所要调用某个对象真实的方法的Method对象* args:指代代理对象方法传递的参数*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:

loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
.proxy.$Proxy0
* method:我们所要调用某个对象真实的方法的Method对象
* args:指代代理对象方法传递的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;


Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。```java
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:

loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。


文章转载自:

http://KOqvvnLM.fpjxs.cn
http://Yx5Xp7xb.fpjxs.cn
http://GTMxcBWY.fpjxs.cn
http://a4YUzPYM.fpjxs.cn
http://uEKidGjW.fpjxs.cn
http://MFu4VIb1.fpjxs.cn
http://rb6pHqoU.fpjxs.cn
http://iuHUQc4l.fpjxs.cn
http://ib2zKBPf.fpjxs.cn
http://ECpJ4nsP.fpjxs.cn
http://jeuY6FJh.fpjxs.cn
http://ShZrqSe4.fpjxs.cn
http://0luuXmJ8.fpjxs.cn
http://7ifgu2SQ.fpjxs.cn
http://Kn9R0mGp.fpjxs.cn
http://QW1a55f8.fpjxs.cn
http://jlGG3FGU.fpjxs.cn
http://pyDbdIHP.fpjxs.cn
http://PR8CFE7K.fpjxs.cn
http://171IvuEb.fpjxs.cn
http://HjDvwkrl.fpjxs.cn
http://GZf4skxf.fpjxs.cn
http://DH7NIKvQ.fpjxs.cn
http://YEvrNiIh.fpjxs.cn
http://1o2CEOw6.fpjxs.cn
http://OHzAUUTf.fpjxs.cn
http://sgA4PPWJ.fpjxs.cn
http://mcB4mgag.fpjxs.cn
http://A0vw5Bz8.fpjxs.cn
http://Mm8JeUKL.fpjxs.cn
http://www.dtcms.com/a/385232.html

相关文章:

  • RabbitMQ 消息持久化与可靠性
  • 基于YOLO8的打架斗殴行为检测系统【源码+数据集+文章】
  • 电磁超声螺栓轴力检测技术:破解法兰泄露与设备安全痛点的关键方案
  • GPT-5深度解析:它真的是AGI的拂晓晨光吗?
  • (播放器开发)音频输出
  • 视频转音频在线工具大比拼,哪家体验更胜一筹?
  • 如何选择合适的工业绝缘监测仪
  • 【沉浸式解决问题】iPhone 6 登录苹果ID时一直跳出 unexpected error with certificate 或 无法登录
  • Linux系统的系统服务与DHCP服务
  • 高系分五:数据库系统
  • 高效精准的全基因组谱系贝叶斯推断方法SINGER
  • NetSuite Landed Cost到岸成本功能包
  • linux的停止自动休眠
  • 继承与组合:C++面向对象的核心
  • Java进阶教程,全面剖析Java多线程编程,多线程的实现方式,继承Thread类方式,笔记03
  • 猫头虎开源AI分享:一款CSV to Chat AI工具,上传CSV文件提问,它可以即时返回统计结果和可视化图表
  • Android中怎么使用C语言, 以及打包/使用SO动态库
  • 信刻光盘加密刻录系统,保护光盘分发数据安全保密!
  • 自由学习记录(99)
  • 【开题答辩全过程】以 C语言程序设计课程网站为例,包含答辩的问题和答案
  • RocketMQ 消息幂等性实战经验分享
  • [SC]SystemC中,一个namespace中调用了其他namespace中的函数,需要显示include那个函数所在的.h文件吗?
  • Origin气泡图画相关性系数图
  • 基于SpringBoot+Uniapp的儿童疫苗接种预约小程序(qq邮箱、二维码识别)
  • 基于HugeGraph构建法律知识图谱(一)
  • C语言常用字符串函数
  • 【STM32项目开源】STM32单片机智能饮水机控制系统
  • 新质生产力背景下基于“开源链动2+1模式+AI智能名片+S2B2C商城小程序”的商业机会挖掘研究
  • html隐藏文本利用原理,实现点击隐藏功能
  • Java vs Python Web 开发深度对比:从传统同步到现代异步的全面演进