软件开发培训学校:Java动态代理与静态代理以及它能为我们做什么

相信我们在网上和平时学习和工作中或多或少都接触过Java的代理模式,经常听到什么静态代理、动态代理的一些名词 。但我们是否真的很清楚这些呢?至少我在面试时,发现很多人并不很清楚 。首先代理比较好理解,就是帮一个人,或者一类人做一些事情 。迁移到面向对象的程序设计中,代理就是帮一个类去做一些事情,而这个代理的工具我们就称为代理类 。通过代理的方式去做事有什么好处呢?这就好比工厂和分销商做的事情一样,工厂可以直卖一些自己的产品,分销商同样也可以卖工厂生产的产品,那么为什么还有分销商的存在呢?因为分销商可以供一些额外的服务,或者在销售的过程中能够完成一些其他的事情,比如组合销售、根据本地情况做活动等,而这些可能是工厂不想关心或者也管不过来的 。这样的功能和角色承包给代理商就会使得分工比较明晰,并且又能够供一些额外或者定制的服务 。静态代理Java中的代理方式可以分为静态代理和动态代理 。静态代理的含义是代理类/对象在我们关心的程序运行前就已经确定或存在 。静态代理比较好理解,我们在日常工作中也是经常用到,比如一个已经存在的接口,我们不期望去更改它,但是现在要在原逻辑上新加一些逻辑或功能,比如原接口方法调用完成后发送一个消息之类的 。于是我们可以创建一个类,同样实现原接口,并且把之前存在的接口当做成员变量注入进来,调用其中的方法,并添加我们需要的功能 。静态代理的类图如下所示,需要被代理的实现类和代理类都实现了抽象接口AbstractInterface,而InterfaceProxy和InterfaceImpl间是聚合关系 。

软件开发培训学校:Java动态代理与静态代理以及它能为我们做什么

文章插图
 来看一段示例代码,ProductAuditCallbackService 是我们已有的一个接口,出于某些原因,这个接口不能继续对外使用,我们需要定义一个新的接口并且名称还要一样(主要是方便客户理解和对应原接口),但是我们需要添加一点“新逻辑” 。因此我们可以同样实现 ProductAuditCallbackService,ProductAuditCallbackServiceProxy 就是我们的代理类,之后外部调用就可以实例化我们的代理类,调用同名方法就好了 。1 public class ProductAuditCallbackServiceProxy implements ProductAuditCallbackService { 2 3 @Resource 4 private ProductAuditCallbackService productAuditCallbackService; 5 6 @Override 7 public Result auditProduct(ProductAuditRequest request, String auditStatus) { 8 if (auditStatus == "DELETED") { 9 return new Result<>;10 }11 return productAuditCallbackService.auditProduct(request, auditStatus);12 }13 14 15 ...16 } 动态代理动态代理的作用和静态代理一样,主要的区别就在于需要在运行时生成代理类 。在使用动态代理时,我们还需要定义一个在代理类和委托类之间的中介类,并且中介类需要实现 java.lang.reflect.InvocationHandler 接口 。1 package java.lang.reflect; 2 3 /** 4 * {@code InvocationHandler} is the interface implemented by 5 * the invocation handler of a proxy instance. 6 * 7 *Each proxy instance has an associated invocation handler. 8 * When a method is invoked on a proxy instance, the method 9 * invocation is encoded and dispatched to the {@code invoke}10 * method of its invocation handler.11 *12 * @author Peter Jones13 * @see Proxy14 * @since 1.315 */16 public interface InvocationHandler {17 18 public Object invoke(Object proxy, Method method, Object[] args)19 throws Throwable;20 }动态代理在框架类的代码中用到的频率并不低,而且能够使我们的代码看起来更高级一些,所以何乐而不为呢? 让我们来看一些实际的例子 。MethodInvocationHandler是一个中介类,实现了InvocationHandler接口,MethodMonitor 这个类的功能就是要统计我们的委托类的对象business中的方法被调用的次数和耗时,由于其主要功能不是我们关注的主要内容,所以忽略其实现 。1 public class MethodInvocationHandler implements InvocationHandler { 2 3 //被代理对象 4 private Object business; 5 6 private final MethodMonitor methodMonitor; 7 8 public MethodInvocationHandler(MethodMonitor methodMonitor) { 9 this.methodMonitor = methodMonitor;10 }11 12 /**13 * 代理方法14 */15 @Override16 public Object invoke(Object proxy, Method method, Object[] args)17 throws Throwable {18 19 long startTime = System.currentTimeMillis;20 21 Object result = method.invoke(this.business, args);22 23 //方法调用统计24 this.methodMonitor.methodCount(this.business.getClass.getSimpleName + POINT + method.getName, startTime);25 return result;26 }27 28 }其余示例代码及外部调用示例如下,我们的Business类里面拥有三个方法 。MethodSampleClient 则是一个封装起来的客户端 。我们不想让外部客户端感知我们的实现以及和Business的关系,于是我们在MethodSampleClient中定义了一个成员变量proxy,当外部需要Business供的一些功能时,我们通过proxy为其供 。Proxy.newProxyInstance 则是我们实例化一个代理类的方式,哟,这还是个工厂模式,可以阅读一些这个方法的说明,需要传入的三个参数依次是:需要被代理的类的ClassLoader,被代理类需要被代理的接口的集合,中介处理类的实例 。这里Business我写的是一个确定的类,其实真正在实际开发工作中,我们往往定义的抽象的接口或抽象类,知道运行时才会确定到底是哪个实现类的实例,这样可能更容易理解一些:运行时确定委托类的实现类,运行时生成代理类,并调用对应的委托类的方法 。1 public class Business { 2 3 public void createJob { 4 System.out.println("test createJob"); 5 } 6 7 8 public void processJob { 9 System.out.println("test processJob");10 }11 12 public void closeJob {13 System.out.println("test closeJob");14 }15 16 }17 18 19 20 public class MethodSampleClient {21 22 private Business business;23 24 @Getter25 private Object proxy;26 27 private InvocationHandler invocationHandler;28 29 30 public void init {31 this.business = new Business;32 this.invocationHandler = new MethodInvocationHandler(new MethodMonitor);33 this.proxy = bind(this.business, invocationHandler);34 }35 36 /**37 * 绑定对象, 直接初始化并返回代理类供客户端使用38 */39 public Object bind(Object business, InvocationHandler invocationHandler) {40 return Proxy.newProxyInstance(41 //被代理类的ClassLoader42 business.getClass.getClassLoader,43 //要被代理的接口,本方法返回对象会自动声称实现了这些接口44 business.getClass.getInterfaces,45 //代理处理器对象46 invocationHandler);47 }48 49 } 50 51 52 /**53 * A simple client test class54 */55 public class Test {56 57 public void main(String[] args) {58 MethodSampleClient methodSampleClient = new MethodSampleClient;59 methodSampleClient.init;60 61 methodSampleClient.getProxy.createJob;62 methodSampleClient.getProxy.processJob;63 methodSampleClient.getProxy.closeJob;64 }65 66 }为了说清楚这个过程,竟然还真的写了不少代码,看起来比较繁琐 。总结一下,动态代理无非按照下面的步骤来编写代码:


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: