java静态代理和动态代理的优缺点,Java 静态代理

  java静态代理和动态代理的优缺点,Java 静态代理

  00-1010前言1。静态代理和装饰模式2的区别。动态代理JDK动态代理CGlib动态代理实现

  00-1010在学习Spring的过程中,掌握代理模式是必然的。本文总结了代理模式。顾名思义,代理就是你委托别人为你做事,所以代理模式也叫委托模式。比如领导要做什么事情,可以委托秘书帮他做。这时候秘书就可以算是领导的代理人了。这个用这个例子来解释。代理模式分为静态代理和动态代理。

  

目录

 

  00-1010静态代理,代理类和被代理类实现同一个接口,代理类同时持有被代理类的引用,所以当我们需要调用被代理类的方法时,可以通过调用被代理类的方法来实现。

  假设举例:s的工作是召开会议和评估员工。

  先定义一个接口:

  包com.sharpcj公共接口IWork { void meeting();int evaluate(字符串名);}然后定义领导类:

  包com.sharpcj导入Java . util . random;班长实现iwork { @ override public void meeting(){ system . out . println(领导上午要组织开会);} @ Override public int evaluate(String name){ int score=new Random(system . current time millis())。nextInt(20)80;system . out . println(string . format(领导给%s的评价是%s ,名称,分数));返回分数;} }秘书类:

  包com.sharpcj公共课秘书实现IWork {私教领袖mLeader公共秘书(Leader mLeader){ this . mLeader=mLeader;} @ override public void meeting(){ system . out . println(秘书先给老板准备材料);mleader . metting();} @ Override public int evaluate(String name){ return mleader . evaluate(name);} }测试类:

  包com.sharpcjpublic class TestApp { public static void main(String[]args){ Leader Leader=new Leader();秘书秘书=新秘书(领导);secretary . meeting();secretary.evaluate(“喜悦”);} }执行结果:

  这段代码非常简单。注意,在调用秘书类的会议方法时,我们调用了领导类的会议方法。在此之前,我们扩展了这个方法。这时候可能有人会有疑问,这似乎有点装饰者模式。这到底是怎么回事?

  

前言

其实装饰者模式和代理模式还是有很多区别的。装饰模式侧重于向对象动态添加方法,而代理模式侧重于控制对对象的访问。换句话说,使用代理模式,代理类可以对其客户端隐藏对象的特定信息。因此,当使用代理模式时,我们经常在代理类中创建一个对象的实例。此外,当我们使用装饰器模式时,我们通常的做法是将原始对象作为参数传递给装饰器的构造函数。

 

  lockquote>我们可以用另外一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。

  先看看两者的 UML 类图区别:

  代理模式:

  

 

  装饰者模式:

  

 

  两者伪代码:

  代理模式:

  

Interface Subject { void doAction()}public class RealSubject implements Subject{ @Override public void doAction() {};}public class Proxy implements Subject{ private RealSubject realSubject; public Proxy(RealSubject realSubject) { //关系在编译时确定 this.realSubject = realSubject; } @Override public void doAction() { …. realSubject.doAction(); …. }}

装饰者模式;

 

  

Interface Component { void doAction()}public class ConcreteComponent implement Component { @Override public void doAction() {};}public class Decorator implements Component { private Component component; public Decorator(Component component) { //关系在编译时确定 this.component = new component; } public void doAction() { …. component.doAction(); …. }}

其实代理模式和装饰者模式侧重点不一样,代理模式重点在于明确了被代理的类。如上例中,秘书很明确要代理的是的领导。而装饰者模式侧重于拓展类的方法,装饰类持有的实现Component接口的类的对象不是固定的,也就是说,装饰类可以根据在调用时传入的参数,装饰任意一个实现了 Component 接口的类。

 

  

 

  

二、动态代理

动态代理的根据实现方式的不同可以分为 JDK 动态代理和 CGlib 动态代理。

 

  JDK 动态代理:利用反射机制生成一个实现代理接口的类,在调用具体方法前调用InvokeHandler来处理。CGlib 动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。

  

 

  

JDK 动态代理

还是以上面的例子为例:首先,定一个类实现InvocationHandler接口,并实现 invoke 方法:

 

  

package com.sharpcj;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class WorkInvocationHandler implements InvocationHandler { private Object object; public WorkInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("object: " + object.getClass().getSimpleName()); System.out.println("proxy: " + proxy.getClass().getSimpleName()); if ("meeting".equals(method.getName())) { System.out.println("代理先准备会议材料..."); return method.invoke(object, args); } else if ("evaluate".equals(method.getName())) { if(args[0] instanceof String) { if ("James".equals(args[0])) { System.out.println("James 犯过错误,所以考评分数较低..."); return 70; } } return method.invoke(object, args); } return null; }}

然后通过Proxy.newProxyInstance()方法创建代理对象:

 

  

package com.sharpcj;import java.lang.reflect.Proxy;public class TestApp { public static void main(String[] args) { /*Leader leader = new Leader(); Secretary secretary = new Secretary(leader); secretary.meeting(); secretary.evaluate("Joy");*/ Leader leader = new Leader(); IWork proxy = (IWork) Proxy.newProxyInstance(Leader.class.getClassLoader(), new Class[]{IWork.class}, new WorkInvocationHandler(leader)); proxy.meeting(); proxy.evaluate("Joy"); proxy.evaluate("James"); }}

输出结果:

 

  

 

  我们看到,通过 WorkInvocationHandler 类,我们同样可以代理 Leader 类的方法的实现,实际上我们实现的是任意的方法的实现,只是我们在创建代理对象的时候传入的是 Iwork 接口以及 Leader 类对象。

  

这里需要注意的是:在 InvocationHandler 接口的 invoke 方法中第一个参数 proxy, 并不是我们调用方法的对象,那这个参数是什么呢?代码中,我特别增加相应打印,打印出了 proxy 的类名,实际上 proxy 是代理对象本身,它的意义在于,我们可以在 invoke 方法中,返回该代理对象,然后进行连续调用。

 

  

看如下例子:

 

  

package com.sharpcj.proxytest;public interface IWork { IWork work(String subject);}
package com.sharpcj.proxytest;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class WorkInvocationHandler implements InvocationHandler { private Object object; public WorkInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("work".equals(method.getName())){ System.out.println("--- work: " + args[0]); return proxy; } return null; }}
package com.sharpcj.proxytest;import java.lang.reflect.Proxy;public class TestApp { public static void main(String[] args) { IWork worker = (IWork) Proxy.newProxyInstance(IWork.class.getClassLoader(), new Class[]{IWork.class}, new WorkInvocationHandler(new IWork() { @Override public IWork work(String subject) { return null; } })); worker.work("AAA").work("BBB").work("CCC"); }}

结果如下:

 

  

 

  

 

  

CGlib 动态代理实现

首先添加 cglib 依赖

 

  build.gradle 文件:

  

... dependencies { // 引入 cglib 库 compile cglib:cglib:3.1 testCompile group: junit, name: junit, version: 4.12}...

前面说了,cglib 针对类进行代理,我们以上面的 Leader 类为例,先创建一个类实现MethodInterceptor接口:

 

  

package com.sharpcj;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class LeaderMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if ("meeting".equals(method.getName())) { System.out.println("代理先准备会议材料..."); return methodProxy.invokeSuper(o, objects); } else if ("evaluate".equals(method.getName())) { if(objects[0] instanceof String) { if ("James".equals(objects[0])) { System.out.println("James 犯过错误,所以考评分数较低..."); return 70; } } return methodProxy.invokeSuper(o, objects); } return null; }}

测试代码:

 

  

package com.sharpcj;import net.sf.cglib.core.DebuggingClassWriter;import net.sf.cglib.proxy.Enhancer;import java.lang.reflect.Proxy;public class TestApp { public static void main(String[] args) { // System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:tempcode"); //保存生成的 class 文件 Enhancer enhancer = new Enhancer(); // 通过CGLIB动态代理获取代理对象的过程 enhancer.setSuperclass(Leader.class); // 设置enhancer对象的父类 enhancer.setCallback(new LeaderMethodInterceptor()); // 设置enhancer的回调对象 Leader proxy= (Leader)enhancer.create(); // 创建代理对象 // 通过代理对象调用目标方法 proxy.meeting(); proxy.evaluate("Joy"); proxy.evaluate("James"); }}

结果如下:

 

  

 

  MethodInterceptor接口只有一个intercept方法,这个方法有4个参数:

  1)obj表示增强的对象,即实现这个接口类的一个对象;2)method表示要被拦截的方法;3)args表示要被拦截方法的参数;4)proxy表示要触发父类的方法对象;需要注意的是:实际调用是methodProxy.invokeSuper(), 如果使用invoke()方法,则需要传入被代理的类对象,否则出现死循环,造成 stackOverflow 。

  到此这篇关于深入理解Java动态代理与静态代理的文章就介绍到这了,更多相关Java动态静态代理内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: