💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 代理模式(Proxy) 代理模式主要用来控制对其他对象的访问,代理通常充当中间人的身份。一般可以分为如下4类: 1. 远程代理(Remote Proxy):控制对远程对象的访问,负责将请求及其参数编码,并向不同地址空间中的对象发送已经编码的请求。 2. 虚拟代理(Virtual Proxy) 3. 保护代理 4. 智能代理 java中的代理模式: 1. 静态代理 Java的静态代理是基于接口的代理模式,可以用于在不修改原来对象的代码的基础上,扩充对象的功能。例如: ~~~ package net.smrobot.proxy; /** * 静态代理 */ public class SimpleProxyDemo { /** * 传递一个接口参数 * @param iface */ public static void consumer(Interface iface) { iface.doSomething(); iface.somethingElse("zhangsan"); } public static void main(String[] args) { System.out.println("没有使用代理模式...."); consumer(new RealObject()); System.out.println("使用了代理模式..."); consumer(new SimpleProxy(new RealObject())); } } interface Interface { void doSomething(); void somethingElse(String arg); } class RealObject implements Interface { @Override public void doSomething() { System.out.println("Real Object:doSomething!"); } @Override public void somethingElse(String arg) { System.out.println("Real Object:somethingElse=" + arg); } } /** * 创建静态代理类 */ class SimpleProxy implements Interface { private Interface proxied; public SimpleProxy(Interface proxied) { this.proxied = proxied; } @Override public void doSomething() { System.out.println("Proxy Object:doSomething!"); proxied.doSomething(); } @Override public void somethingElse(String arg) { System.out.println("Proxy Object:somethingElse!"); proxied.somethingElse(arg); } } ~~~ 2. 动态代理 Java提供的动态代理可以动态的创建代理对象,对所代理的方法进行调用,在动态代理类上的所有调用都会被重定向到一个单一的调用处理器(Handler)上。因此使用Java的动态代理技术需要如下元素: 1. 要代理的对象是**基于接口**实现的。 2. 创建调用处理器,并实现InvocationHandler接口中的invoke方法。 3. 通过Proxy.newProxyInstance()来动态的创建一个代理对象。调用该代理对象的方法,就会将方法的调用重定向到处理器的invoke方法中。 例如: ~~~ package net.smrobot.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理 */ public class DynamicProxyDemo { public static void consumer(Interface iface) { iface.doSomething(); iface.somethingElse("zhangsan"); } public static void main(String[] args) { RealObject realObject = new RealObject(); consumer(realObject); System.out.println("使用动态代理并再次调用..."); Interface proxyInstance = (Interface)Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(realObject)); consumer(proxyInstance); } } class DynamicProxyHandler implements InvocationHandler { /** * 要代理的对象 */ private Object proxied; public DynamicProxyHandler(Object proxied) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("\n"); System.out.println("proxy:" + proxy.getClass() + "\nmethod:" + method + "\nargs:" + args); if (args != null) { System.out.println("方法的参数为...."); for (Object arg : args) { System.out.println(" " + arg); } } return method.invoke(proxied, args); } } ~~~ JDK的动态代理是基于反射技术实现的,还有基于字节码技术实现ASM或者cglib。 &nbsp; **Cglib的动态代理技术** JDK的动态代理只能代理基于接口的实现类,否则的话会抛出“ClassCastException异常”。而Cglib的动态代理技术可以实现基于类的动态代理,其主要生成了一个目标类的子类对象来覆盖掉目标类方法,因此如果目标类是用final修饰,则不可以使用Cglib技术。 1. 引入依赖 ~~~ <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.9</version> </dependency> ~~~ 2. 实现 ~~~ package net.smrobot.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * Cglib的动态代理模式 */ public class CglibProxyDemo { public static void main(String[] args) { // CGLIB dynamic proxy call CglibProxy proxy = new CglibProxy(); Panda panda = (Panda)proxy.getInstance(new Panda()); System.out.println(panda); panda.eat(); } } class Panda { public void eat() { System.out.println("The panda is eating..."); } } class CglibProxy implements MethodInterceptor { // 要代理的目标对象 private Object target; public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); // 设置代理对象的父类对象,就是要代理的目标对象 enhancer.setSuperclass(this.target.getClass()); // 设置回调函数 enhancer.setCallback(this); // 创建一个代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Before calling"); // 执行目标对象的代理方法 Object result = methodProxy.invokeSuper(o, objects); System.out.println("After calling"); return result; } } ~~~ 主要组成: 1. 要被代理的目标对象。 2. 实现了MethodInterceptor接口的代理对象,并重写intercept方法。 JDK动态代理和Cglib的动态代理对比: 1. JDK动态代理更可靠,同时JDK的版本升级的比较快,字节码包(cglib)也要随着更新。 2. Cglib有者更高的性能,同时可以用在非接口对象中。 动态代理的应用场景:包装RPC、面向切面编程(AOP)。 &nbsp; 【参考】 1. 《Java编程思想》动态代理。 2. https://www.fatalerrors.org/a/reflection-and-dynamic-proxy-jdk-proxy-and-cglib.html