💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] 所谓代理代理模式可以在不修改被代理对象的基础上,**通过扩展代理类,进行一些功能的附加与增强**。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。 比如,代理类可以补充一些打印日志,统计时长的方法。 ## Java 静态代理 ~~~ //通用的接口 public interface Movie { void play(); } //真正的实现这个 Movie 接口的类 public class RealMovie implements Movie { @Override public void play() { System.out.println("您正在观看电影 《肖申克的救赎》"); } } //代理类 public class Cinema implements Movie { RealMovie movie; public Cinema(RealMovie movie) { super(); this.movie = movie; } @Override public void play() { guanggao(true); movie.play(); guanggao(false); } public void guanggao(boolean isStart){ if ( isStart ) { System.out.println("电影马上开始了"); } else { System.out.println("电影马上结束了"); } } } // 方法 public class ProxyTest { public static void main(String[] args) { RealMovie realmovie = new RealMovie(); Movie movie = new Cinema(realmovie); movie.play(); ~~~ ## Java 动态代理 ### Demo ~~~ //通用的接口 public interface SellWine { void mainJiu(); } //真正的实现类 public class MaotaiJiu implements SellWine { @Override public void mainJiu() { // TODO Auto-generated method stub System.out.println("我卖得是茅台酒。"); } } //代理类 public class GuitaiA implements InvocationHandler { private Object pingpai; public GuitaiA(Object pingpai) { this.pingpai = pingpai; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("销售开始:"+this.getClass().getSimpleName()); method.invoke(pingpai, args); System.out.println("销售结束"); return null; } } public class Test { public static void main(String[] args) { MaotaiJiu maotaijiu = new MaotaiJiu(); InvocationHandler jingxiao1 = new GuitaiA(maotaijiu); SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(), MaotaiJiu.class.getInterfaces(), jingxiao1); dynamicProxy.mainJiu(); } } 结果; 销售开始 GuitaiA 我卖得是茅 ~~~ ### 语法 #### Proxy 动态代码涉及了一个非常重要的类 Proxy。正是通过 Proxy 的静态方法 newProxyInstance才会动态创建代理的实例对象。 ~~~ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) ~~~ 下面讲解它的 3 个参数意义。 * loader 自然是类加载器 * interfaces 代码要用来代理的接口 * h 一个 InvocationHandler 对象 #### InvocationHandler InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理 ~~~ public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } ~~~ * proxy 代理对象 * method 代理对象调用的方法 * args 调用的方法中的参数 ### 原理 #### newProxyInstance newProxyInstance 实际上就是动态生成的代理类,类名是**包名+$Proxy+id序号**。 ~~~ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); //核心方法 创建类定义 Class<?> cl = getProxyClass0(loader, intfs); try { final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; ...。 //反射初始化 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { .. } ~~~ #### getProxyClass0 ~~~ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { ... 。 // 直接通过缓存获取,如果获取不到,注释说会通过 ProxyClassFactory 生成。 return proxyClassCache.get(loader, interfaces); } ~~~ #### ProxyClassFactory  ~~~ /** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // Proxy class 的前缀是 “$Proxy”, private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } ~~~ defineClass0() 甚至是一个 native 方法。我们只要知道,动态创建代理这回事就好了。 ## Android 通过动态代理设置事件监听 ~~~ public class MainActivity extends AppCompatActivity { private Button bt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt = (Button) findViewById(R.id.bt); proxySetOnclick(); } //通过代理为button设置监听 private void proxySetOnclick() { try { //获得真实回调的方法(后期可以用注解获得这里hardCode了) Method realClick = this.getClass().getMethod("realClick",View.class); //创建一个代理 ProxyHandle handle = new ProxyHandle(this, realClick); //设置代理 返回的是对应的接口 (OnClickListener实例对象) View.OnClickListener proxyObj = (View.OnClickListener)Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(), new Class[]{View.OnClickListener.class}, handle); //调用对应View的设置监听方法 之后会到代理handle里去(对象可以用注解获得这里暂不分析) bt.setOnClickListener(proxyObj); } catch (Exception e) { e.printStackTrace(); } } //真实回调方法 public void realClick(View v) { Toast.makeText(this,"点击了",Toast.LENGTH_SHORT).show(); } } public class ProxyHandle implements InvocationHandler { private Object realObj; private Method realMethod; public ProxyHandle(Object realObj,Method realMethod){ this.realObj=realObj; this.realMethod=realMethod; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果真实对象跟方法都不为null 则直接返回真是方法(这里真实方法必须跟接口方法参数保存一致) if (realObj!=null&&realMethod!=null){ return realMethod.invoke(realObj,args); }else { return method.invoke(proxy,args); } ~~~ ## 参考资料 [轻松学,Java 中的代理模式及动态代理](https://blog.csdn.net/briblue/article/details/73928350)