java静态代理与动态代理简单分析

转载 2018年04月14日 22:41:38

原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/5860749.html

 

1、动态代理(Dynamic Proxy)
  代理分为静态代理和动态代理,静态代理是在编译时就将接口、实现类、代理类一股脑儿全部手动完成,但如果我们需要很多的代理,每一个都这么手动的去创建实属浪费时间,而且会有大量的重复代码,此时我们就可以采用动态代理,动态代理可以在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能。
  其实方法直接调用就可以完成功能,为什么还要加个代理呢?
  原因是采用代理模式可以有效的将具体的实现与调用方进行解耦,通过面向接口进行编码完全将具体的实现隐藏在内部。
2、代理实现的一般模式
  其实代理的一般模式就是静态代理的实现模式:首先创建一个接口(JDK代理都是面向接口的),然后创建具体实现类来实现这个接口,在创建一个代理类同样实现这个接口,不同指出在于,具体实现类的方法中需要将接口中定义的方法的业务逻辑功能实现,而代理类中的方法只要调用具体类中的对应方法即可,这样我们在需要使用接口中的某个方法的功能时直接调用代理类的方法即可,将具体的实现类隐藏在底层。
  第一步:定义总接口Iuser.java

1 package ceshi1;
2 public interface Iuser {
3     void eat(String s);
4 }

  第二步:创建具体实现类UserImpl.java

复制代码
1 package ceshi1;
2 public class UserImpl implements Iuser {
3   @Override
4   public void eat(String s) {
5     System.out.println("我要吃"+s);
6   }
7 }
复制代码

  第三步:创建代理类UserProxy.java

复制代码
 1 package ceshi1;
 2 public class UserProxy implements Iuser {
 3   private Iuser user = new UserImpl();
 4   @Override
 5   public void eat(String s) {
 6     System.out.println("静态代理前置内容");
 7     user.eat(s);
 8     System.out.println("静态代理后置内容");
 9   }
10 }
复制代码

  第四步:创建测试类ProxyTest.java

复制代码
1 package ceshi1;
2 public class ProxyTest {
3   public static void main(String[] args) {    
4     UserProxy proxy = new UserProxy();
5     proxy.eat("苹果");
6   }
7 }
复制代码

  运行结果:

1 静态代理前置内容
2 我要吃苹果
3 静态代理后置内容

3、动态代理的实现
  动态代理的思维模式与之前的一般模式是一样的,也是面向接口进行编码,创建代理类将具体类隐藏解耦,不同之处在于代理类的创建时机不同,动态代理需要在运行时因需实时创建。
  第一步:定义总接口Iuser.java

1 package ceshi1;
2 public interface Iuser {
3   void eat(String s);
4 }

  第二步:创建具体实现类UserImpl.java

复制代码
1 package ceshi1;
2 public class UserImpl implements Iuser {
3   @Override
4   public void eat(String s) {
5     System.out.println("我要吃"+s);
6   }
7 }
复制代码

  第三步:创建实现InvocationHandler接口的代理类

复制代码
 1 package ceshi1;
 2 import java.lang.reflect.InvocationHandler;
 3 import java.lang.reflect.Method;
 4 public class DynamicProxy implements InvocationHandler {
 5   private Object object;//用于接收具体实现类的实例对象
 6   //使用带参数的构造器来传递具体实现类的对象
 7   public DynamicProxy(Object obj){
 8     this.object = obj;
 9   }
10   @Override
11   public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
12     System.out.println("前置内容");
13     method.invoke(object, args);
14     System.out.println("后置内容");
15     return null;
16   }
17 }
复制代码

  第四步:创建测试类ProxyTest.java

复制代码
 1 package ceshi1;
 2 import java.lang.reflect.InvocationHandler;
 3 import java.lang.reflect.Proxy;
 4 public class ProxyTest {
 5   public static void main(String[] args) {
 6     Iuser user = new UserImpl();
 7     InvocationHandler h = new DynamicProxy(user);
 8     Iuser proxy = (Iuser) Proxy.newProxyInstance(Iuser.class.getClassLoader(), new Class[]{Iuser.class}, h);
 9     proxy.eat("苹果");
10   }
11 }
复制代码

  运行结果为:

1 动态代理前置内容
2 我要吃苹果
3 动态代理后置内容

4、通过上面的动态代理实例我们来仔细分析研究一下动态代理的实现过程
(1)首先我要说的就是接口,为什么JDK的动态代理是基本接口实现的呢?
  因为通过使用接口指向实现类的实例的多态实现方式,可以有效的将具体的实现与调用之间解耦,便于后期修改与维护。
再具体的说就是我们在代理类中创建一个私有成员变量(private修饰),使用接口来指向实现类的对象(纯种的多态体现,向上转型的体现),然后在该代理类中的方法中使用这个创建的实例来调用实现类中的相应方法来完成业务逻辑功能。
这么说起来,我之前说的“将具体实现类完全隐藏”就不怎么正确了,可以改成,将具体实现类的细节向调用方完全隐藏(调用方调用的是代理类中的方法,而不是实现类中的方法)。
  这就是面向接口编程,利用java的多态特性,实现程序代码的解耦。
(2)创建代理类的过程
  如果你了解静态代理,那么你会发现动态代理的实现其实与静态代理类似,都需要创建代理类,但是不同之处也很明显,创建方式不同!
  不同之处体现在静态代理我们知根知底,我们知道要对哪个接口、哪个实现类来创建代理类,所以我们在编译前就直接实现与实现类相同的接口,直接在实现的方法中调用实现类中的相应(同名)方法即可;而动态代理不同,我们不知道它什么时候创建,也不知道要创建针对哪个接口、实现类的代理类(因为它是在运行时因需实时创建的)。
  虽然二者创建时机不同,创建方式也不相同,但是原理是相同的,不同之处仅仅是:静态代理可以直接编码创建,而动态代理是利用反射机制来抽象出代理类的创建过程。
  让我们来分析一下之前的代码来验证一下上面的说辞:
    第一点:静态代理需要实现与实现类相同的接口,而动态代理需要实现的是固定的Java提供的内置接口(一种专门提供来创建动态代理的接口)InvocationHandler接口,因为java在接口中提供了一个可以被自动调用的方法invoke,这个之后再说。
    第二点:private Object object;
        public UserProxy(Object obj){this.object = obj;}
  这几行代码与静态代理之中在代理类中定义的接口指向具体实现类的实例的代码异曲同工,通过这个构造器可以创建代理类的实例,创建的同时还能将具体实现类的实例与之绑定(object指的就是实现类的实例,这个实例需要在测试类中创建并作为参数来创建代理类的实例),实现了静态代理类中private Iuser user = new UserImpl();一行代码的作用相近,这里为什么不是相同,而是相近呢,主要就是因为静态代理的那句代码中包含的实现类的实例的创建,而动态代理中实现类的创建需要在测试类中完成,所以此处是相近。
    第三点:invoke(Object proxy, Method method, Object[] args)方法,该方法是InvocationHandler接口中定义的唯一方法,该方法在调用指定的具体方法时会自动调用。其参数为:代理实例、调用的方法、方法的参数列表
  在这个方法中我们定义了几乎和静态代理相同的内容,仅仅是在方法的调用上不同,不同的原因与之前分析的一样(创建时机的不同,创建的方式的不同,即反射),Method类是反射机制中一个重要的类,用于封装方法,该类中有一个方法那就是invoke(Object object,Object...args)方法,其参数分别表示:所调用方法所属的类的对象和方法的参数列表,这里的参数列表正是从测试类中传递到代理类中的invoke方法三个参数中最后一个参数(调用方法的参数列表)中,在传递到method的invoke方法中的第二个参数中的(此处有点啰嗦)。
    第四点:测试类中的异同
  静态代理中我们测试类中直接创建代理类的对象,使用代理类的对象来调用其方法即可,若是别的接口(这里指的是别的调用方)要调用Iuser的方法,也可以使用此法
动态代理中要复杂的多,首先我们要将之前提到的实现类的实例创建(补充完整),然后利用这个实例作为参数,调用代理来的带参构造器来创建“代理类实例对象”,这里加引号的原因是因为它并不是真正的代理类的实例对象,而是创建真正代理类实例的一个参数,这个实现了InvocationHandler接口的类严格意义上来说并不是代理类,我们可以将其看作是创建代理类的必备中间环节,这是一个调用处理器,也就是处理方法调用的一个类,不是真正意义上的代理类,可以这么说:创建一个方法调用处理器实例。
  下面才是真正的代理类实例的创建,之前创建的”代理类实例对象“仅仅是一个参数
    Iuser proxy = (Iuser) Proxy.newProxyInstance(Iuser.class.getClassLoader(), new Class[]{Iuser.class}, h);
  这里使用了动态代理所依赖的第二个重要类Proxy,此处使用了其静态方法来创建一个代理实例,其参数分别是:类加载器(可为父类的类加载器)、接口数组、方法调用处理器实例
  这里同样使用了多态,使用接口指向代理类的实例,最后会用该实例来进行具体方法的调用即可。

Java业务分析实例

业务设计是整个项目中的灵魂所在,更是一位有经验的开发者必备的从业技能。本课程在读者学习完Java课程的基础之上进行全面深入的实例分析。官方QQ群:612148723。
  • 2016年12月31日 20:37

深入浅出java静态代理和动态代理

首先介绍一下,什么是代理:   代理模式,是常用的设计模式。特征是,代理类与委托类有相同的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类。以及事后处理消息。   代理类和委托类,...
  • zc474235918
  • zc474235918
  • 2015-07-25 22:05:40
  • 1886

动态代理和静态代理到底有什么区别,好处在哪里?

动态代理和静态代理到底有什么区别,好处在哪里?
  • mine_song
  • mine_song
  • 2017-05-07 21:05:19
  • 3452

静态代理和动态代理的理解

Java 静态代理 静态代理通常用于对原有业务逻辑的扩充。比如持有二方包的某个类,并调用了其中的某些方法。然后出于某种原因,比如记录日志、打印方法执行时间,但是又不好将这些逻辑写入二方包的方法里...
  • WangQYoho
  • WangQYoho
  • 2017-08-25 18:04:24
  • 4956

Java代理模式详解及案例分析:静态代理/动态代理

标题:Java代理模式详解及案例分析:静态代理/动态代理 我们以几个问题,来开始我们今天的学习,如果下面几个问题,你都能说出个一二,那么恭喜你,你已经掌握了这方面的知识。 1,什么是代理模式? 2,...
  • reggergdsg
  • reggergdsg
  • 2016-11-03 19:56:58
  • 1953

java代理(静态代理和jdk动态代理以及cglib代理)

说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等。 记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读...
  • fighterandknight
  • fighterandknight
  • 2016-04-20 17:34:56
  • 5811

JAVA学习篇--静态代理VS动态代理

本篇博客的由来,之前我们学习大话设计,就了解了代理模式,但为什么还要说呢?原因:1,通过DRP这个项目,了解到了动态代理,认识到我们之前一直使用的都是静态代理,那么动态代理又有什么好处呢?它们二者的区...
  • hejingyuan6
  • hejingyuan6
  • 2014-07-01 20:36:04
  • 40946

java静态代理与动态代理的区别

java静态代理和动态代理 本文动态代理部分内容大量引自:http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/  一、代理概念 ...
  • u014381710
  • u014381710
  • 2015-10-25 22:15:22
  • 2417

Java设计模式之—静态代理和动态代理

代理从字面意思来看就是,替代XX去做某事,在我们的程序中,一般替代实际对象去进行操作,扮演着中间人的角色: 客户端 –> 业务类 客户端 –> 代理 –>业务类(代理) 代理接口int...
  • jeffleo
  • jeffleo
  • 2016-08-17 00:08:35
  • 1092

动态代理与静态代理区别

一、代理概念  为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委...
  • ikownyou
  • ikownyou
  • 2016-11-08 13:47:14
  • 7484
收藏助手
不良信息举报
您举报文章:java静态代理与动态代理简单分析
举报原因:
原因补充:

(最多只允许输入30个字)