门户网站营销怎么做wordpress分销商城
news/
2025/9/29 5:42:24/
文章来源:
门户网站营销怎么做,wordpress分销商城,详情页模板尺寸,深圳工业设计展2021本篇博文会从代理的概念出发#xff0c;介绍Java中动态代理技术的使用#xff0c;并进一步探索它的实现原理。由于个人水平有限#xff0c;叙述中难免出现不清晰或是不准确的地方#xff0c;希望大家可以指正#xff0c;谢谢大家#xff1a;#xff09; 一、概述 1. 什么… 本篇博文会从代理的概念出发介绍Java中动态代理技术的使用并进一步探索它的实现原理。由于个人水平有限叙述中难免出现不清晰或是不准确的地方希望大家可以指正谢谢大家 一、概述 1. 什么是代理 我们大家都知道微商代理简单地说就是代替厂家卖商品厂家“委托”代理为其销售商品。关于微商代理首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁也就是说“委托者”对我们来说是不可见的其次微商代理主要以朋友圈的人为目标客户这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商代理和厂家进一步抽象前者可抽象为代理类后者可抽象为委托类被代理类。通过使用代理通常有两个优点并且能够分别与我们提到的微商代理的两个特点对应起来 优点一可以隐藏委托类的实现优点二可以实现客户与委托类间的解耦在不修改委托类代码的情况下能够做一些额外的处理。 2. 静态代理 若代理类在程序运行前就已经存在那么这种代理方式被成为静态代理这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。下面我们用Vendor类代表生产厂家BusinessAgent类代表微商代理来介绍下静态代理的简单实现委托类和代理类都实现了Sell接口Sell接口的定义如下 public interface Sell {void sell();void ad();
} Vendor类的定义如下 public class Vendor implements Sell {public void sell() {System.out.println(In sell method);}public void ad() {System,out.println(ad method)}
} 代理类BusinessAgent的定义如下 1 public class BusinessAgent implements Sell {2 private Vendor mVendor;3 4 public BusinessAgent(Vendor vendor) {5 mVendor vendor;6 }7 8 public void sell() { mVendor.sell(); }9 public void ad() { mVendor.ad(); }
10 } 从BusinessAgent类的定义我们可以了解到静态代理可以通过聚合来实现让代理类持有一个委托类的引用即可。 下面我们考虑一下这个需求给Vendor类增加一个过滤功能只卖货给大学生。通过静态代理我们无需修改Vendor类的代码就可以实现只需在BusinessAgent类中的sell方法中添加一个判断即可如下所示 public class BusinessAgent implements Sell {...public void sell() {if (isCollegeStudent()) {vendor.sell();}}...
} 这对应着我们上面提到的使用代理的第二个优点可以实现客户与委托类间的解耦在不修改委托类代码的情况下能够做一些额外的处理。静态代理的局限在于运行前必须编写好代理类下面我们重点来介绍下运行时生成代理类的动态代理方式。 二、动态代理 1. 什么是动态代理 代理类在程序运行时创建的代理方式被成为动态代理。也就是说这种情况下代理类并不是在Java代码中定义的而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理动态代理的优势在于可以很方便的对代理类的函数进行统一的处理而不用修改每个代理类的函数。这么说比较抽象下面我们结合一个实例来介绍一下动态代理的这个优势是怎么体现的。 现在假设我们要实现这样一个需求在执行委托类中的方法之前输出“before”在执行完毕后输出“after”。我们还是以上面例子中的Vendor类作为委托类BusinessAgent类作为代理类来进行介绍。首先我们来使用静态代理来实现这一需求相关代码如下 public class BusinessAgent implements Sell {private Vendor mVendor;public BusinessAgent(Vendor vendor) {this.mVendor vendor;}public void sell() {System.out.println(before);mVendor.sell();System.out.println(after);}public void ad() {System.out.println(before);mVendor.ad();System.out.println(after);}
} 从以上代码中我们可以了解到通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑这里只存在两个方法所以工作量还不算大假如Sell接口中包含上百个方法呢这时候使用静态代理就会编写许多冗余代码。通过使用动态代理我们可以做一个“统一指示”从而对所有代理类的方法进行统一处理而不用逐一修改每个方法。下面我们来具体介绍下如何使用动态代理方式实现我们的需求。 2. 使用动态代理 1InvocationHandler接口 在使用动态代理时我们需要定义一个位于代理类与委托类之间的中介类这个中介类被要求实现InvocationHandler接口这个接口的定义如下 public interface InvocationHandler {Object invoke(Object proxy, Method method, Object[] args);
} 从InvocationHandler这个名称我们就可以知道实现了这个接口的中介类用做“调用处理器”。当我们调用代理类对象的方法时这个“调用”会转送到invoke方法中代理类对象作为proxy参数传入参数method标识了我们具体调用的是代理类的哪个方法args为这个方法的参数。这样一来我们对代理类中的所有方法的调用都会变为对invoke的调用这样我们可以在invoke方法中添加统一的处理逻辑也可以根据method参数对不同的代理类方法做不同的处理。因此我们只需在中介类的invoke方法实现中输出“before”然后调用委托类的invoke方法再输出“after”。下面我们来一步一步具体实现它。 2委托类的定义 动态代理方式下要求委托类必须实现某个接口这里我们实现的是Sell接口。委托类Vendor类的定义如下 public class Vendor implements Sell {public void sell() {System.out.println(In sell method);}public void ad() {System,out.println(ad method)}
} 3中介类 上面我们提到过中介类必须实现InvocationHandler接口作为调用处理器”拦截“对代理类方法的调用。中介类的定义如下 1 public class DynamicProxy implements InvocationHandler {2 private Object obj; //obj为委托类对象3 4 public DynamicProxy(Object obj) {5 this.obj obj;6 }7 8 Override9 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
10 System.out.println(before);
11 Object result method.invoke(obj, args);
12 System.out.println(after);
13 return result;
14 }
15 } 从以上代码中我们可以看到中介类持有一个委托类对象引用在invoke方法中调用了委托类对象的相应方法第11行看到这里是不是觉得似曾相识通过聚合方式持有委托类对象引用把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗实际上中介类与委托类构成了静态代理关系在这个关系中中介类是代理类委托类就是委托类 代理类与中介类也构成一个静态代理关系在这个关系中中介类是委托类代理类是代理类。也就是说动态代理关系由两组静态代理关系组成这就是动态代理的原理。下面我们来介绍一下如何”指示“以动态生成代理类。 4动态生成代理类 动态生成代理类的相关代码如下 public class Main {public static void main(String[] args) {//创建中介类实例DynamicProxy inter new DynamicProxy(new Vendor());//加上这句将会产生一个$Proxy0.class文件这个文件即为动态生成的代理类文件System.getProperties().put(sun.misc.ProxyGenerator.saveGeneratedFiles,true); //获取代理类实例sellSell sell (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(),new Class[] {Sell.class}, inter));//通过代理类对象调用代理类方法实际上会转到invoke方法调用sell.sell();sell.ad();}} 在以上代码中我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的调用处理器。这个方法的声明如下 public static Object newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h) throws IllegalArgumentException 方法的三个参数含义分别如下loader定义了代理类的ClassLoderinterfaces代理类实现的接口列表h调用处理器也就是我们上面定义的实现了InvocationHandler接口的类实例 我们运行一下看看我们的动态代理是否能正常工作。我这里运行后的输出为 说明我们的动态代理确实奏效了。 上面我们已经简单提到过动态代理的原理这里再简单的总结下首先通过newProxyInstance方法获取代理类实例而后我们便可以通过这个代理类实例调用代理类的方法对代理类的方法的调用实际上都会调用中介类调用处理器的invoke方法在invoke方法中我们调用委托类的相应方法并且可以添加自己的处理逻辑。下面我们来看一下生成的代理类的代码究竟是怎样的。 3. 动态代理类的源码分析 通过运行Main我们会得到一个名为“$Proxy”的class文件这个文件即为动态生成的代理类我们通过反编译来查看下这个代理类的源代码 package com.sun.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements Sell {//这5个Method对象分别代表equals()、toString()、ad()、sell()、hashCode()方法private static Method m1;private static Method m2;private static Method m4;private static Method m3;private static Method m0;//构造方法接收一个InvocationHandler对象为参数这个对象就是代理类的“直接委托类”真正的委托类可以看做代理类的“间接委托类”public $Proxy0(InvocationHandler var1) throws {supervar1);}//对equals方法的调用实际上转为对super.h.invoke方法的调用父类中的h即为我们在构造方法中传入的InvocationHandler对象以下的toString()、sell()、ad()、hashCode()等方法同理public final boolean equals(Object var1) throws {try {return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String toString() throws {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void ad() throws {try {super.h.invoke(this, m4, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void sell() throws {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws {try {return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}//这里完成Method对象的初始化通过反射在运行时获得Method对象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]);m4 Class.forName(Sell).getMethod(ad, new Class[0]);m3 Class.forName(Sell).getMethod(sell, new Class[0]);m0 Class.forName(java.lang.Object).getMethod(hashCode, new Class[0]);} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
} 我们可以看到以上代码的逻辑十分简单我们在注释中也做出了相关的说明。以上代码中涉及到反射的使用对于反射还不是很熟悉的小伙伴可以参考这里Java核心技术点之反射 现在我们已经了解了动态代理的使用也搞清楚了它的实现原理更进一步的话我们可以去了解动态代理类的生成过程只需要去阅读newProxyInstance方法的源码即可这个方法的逻辑也没有复杂的地方这里就不展开了。大家可以参考这篇文章公共技术点之动态代理 三、参考资料 1. Java Docs 2. 《深入理解Java虚拟机》 3. 公共技术点之动态代理 转载于:https://www.cnblogs.com/absfree/p/5392639.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/921454.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!