动态代理是大型框架中经常用到的经典的技术之一,博主在理解spring的控制反转(依赖注入)的思想时回头着重复习了一下java的动态代理。

在说动态代理之前我们先简单说一说代理是用来干什么的,用于什么样的业务场景然后在引入静态代理和动态代理。

代理模式一般涉及到的角色有
–抽象角色:声明真实对象和代理对象的共同接口
–代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
–真实角色:代理角色所代表的真实对象,是我们最终要引用的对象

在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。

一、静态代理

下面来看具体代码

抽象角色:

  1. public interface Subject {
  2.  
  3. public void doSomething();
  4. }

真实角色:

  1. public class RealSubject implements Subject {
  2. @Override
  3. public void doSomething() {
  4.  
  5. System.out.println("do something!");
  6. }
  7. }

代理角色:

  1. public class PoxySubject implements Subject{
  2. private RealSubject subject;
  3.  
  4. @Override
  5. public void doSomething() {
  6. this.doPreThing();
  7.  
  8. if (null == subject) {
  9.  
  10. subject = new RealSubject();
  11. }
  12.  
  13. subject.doSomething();
  14. this.dopostThing();
  15. }
  16.  
  17. public void doPreThing() {
  18. System.out.println("pre things");
  19. }
  20.  
  21. public void dopostThing() {
  22. System.out.println("post things");
  23. }
  24. }

测试类(main方法)

  1. public class Client {
  2. /**
  3. * 静态代理模式 作用是为其他对象提供一种代理以控制对这个对象的访问。
  4. * 在本例中的作用是我们不仅可以完成doSomething()方法,而且还可以控制在这个方法前后我们再另外做一些事情。
  5. * @param args
  6. */
  7. public static void main(String[] args) {
  8. Subject subject = new PoxySubject();
  9. subject.doSomething();
  10. }
  11. }

运行main方法:

pre things
do something!
post things

我们发现通过这种方式,我们隐藏了真实角色而是通过代理角色完成了真实角色所做的事情。并且我们可以在代理角色中做一些手脚实现一些我们自己想实现的方法。这就是静态代理的作用。但是很快我们发现其中的局限性。

如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这就是静态代理的局限性,这个问题可以通过Java的动态代理类来解决。

二、动态代理

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法
-public object invoke(Object obj,Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容

-protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
-static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
-static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

接下来我们用动态代理实现之前的例子

抽象角色:

  1. public interface Subject {
  2. public void doSomething();
  3. }

真实角色:

  1. public class RealSubject implements Subject {
  2.  
  3. public void doSomething() {
  4. System.out.println("from real subject");
  5. }
  6. }

实现代理角色的类:

  1. public class DynamicSubject implements InvocationHandler {
  2.  
  3. private Object sub;
  4.  
  5. public DynamicSubject(Object obj) {
  6. this.sub = obj;
  7. }
  8.  
  9. public Object invoke(Object proxy, Method method, Object[] args)
  10. throws Throwable {
  11. System.out.println("调用之前" + method);
  12.  
  13. method.invoke(sub, args);
  14.  
  15. System.out.println("调用之后" + method);
  16.  
  17. return null;
  18. }
  19. }

测试类(main方法):

  1. public class Client {
  2.  
  3. public static void main(String[] args) {
  4. RealSubject sub = new RealSubject();
  5. InvocationHandler hanlder = new DynamicSubject(sub);
  6.  
  7. //返回代理类的一个实例
  8. Subject subject =(Subject)Proxy.newProxyInstance(hanlder.getClass().getClassLoader(), sub.getClass().getInterfaces(), hanlder);
  9. subject.doSomething();
  10. }
  11. }

运行结果:

调用之前public abstract void com.wenge.dynamicporxy.Subject.doSomething()
from real subject
调用之后public abstract void com.wenge.dynamicporxy.Subject.doSomething()

我们还是实现了静态代理所实现的功能,而且我们的程序有了更好的可扩展性。我们可以通过这种方式代理不止一个类,而是多个只要这个类实现了上层接口,更为关键的是这一切是动态生成的,显然这是利用了java的反射技术。这样的话动态代理就可以做很多事情了,最经典的就是spring框架中依赖注入,有兴趣的童鞋可以深入去看看源代码。

所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

实现动态代理的步骤:

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理
4.通过代理调用方法

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

欢迎指正讨论

javase基础回顾(三) 动态代理的更多相关文章

  1. mybatis 基础1(动态代理)

    我目前使用的是mybatis 3.3.0版本. 可使用 1.xml文本, 2.dao类, 3.sqlSession.getMapper(Class<T> type), 生成sql类, 原理 ...

  2. 重学JAVA基础(三):动态代理

    1.接口 public interface Hello { public void sayHello(); } 2.实例类 public class Hello2 { public void sayH ...

  3. 学习Spring必学的Java基础知识(2)----动态代理

    Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Java知识进行学习.Spring AOP使用了两种代理机制:一种是基于JDK的 ...

  4. Spring AOP系列(三) — 动态代理之JDK动态代理

    JDK动态代理 JDK动态代理核心是两个类:InvocationHandler和Proxy 举个栗子 为便于理解,首先看一个例子: 希望实现这样一个功能:使用UserService时,只需关注自己的核 ...

  5. 《Java基础知识》动态代理(InvocationHandler)详解

    1. 什么是动态代理 对象的执行方法,交给代理来负责.比如user.get() 方法,是User对象亲自去执行.而使用代理则是由proxy去执行get方法. 举例:投资商找明星拍广告,投资商是通过经纪 ...

  6. 【Java 基础】Java动态代理

    Java动态代理InvocationHandler和Proxy java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口Invo ...

  7. 【Java基础】 Java动态代理机制

    在Java的动态代理机制中,有两个重要的类.一个是InvocationHandler,另一个是Proxy. InvocationHandler:每一个动态代理类都必须要实现InvocationHand ...

  8. java 基础之--java动态代理

    1.抽象角色:声明真实对象与代理对象的共同接口: 2.代理角色:相当于中介的作用,bridge,内部包含对真实角色的reference,在执行真实操作对象时,附加其他操作,相当于对真实角色的封装: 3 ...

  9. JavaSE基础(三)--Java基础语法

    Java 基础语法 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如 ...

随机推荐

  1. wx 参数传值

    1: data-id 我们可以给HTML元素添加自定义的data-*属性 example:   假设页面里有下面的元素存在: <div id="myDiv" data-nam ...

  2. 下载、安装JDK并配置JDK的环境变量

    概念简介: JDK:(Java Development Kit)Java语言的软件开发工具包,它包含了Java程序的开发工具和Java程序的运行环境JRE: JRE:(Java Runtime Env ...

  3. 1.Spring AOP应用

    首先咱们来了解一下具体的业务场景(这是个真实的项目的业务场景):具体的业务是这样的,现在系统中有六十多个主档(功能模块),每个主档都有新增.修改.删除功能,当我们在对每个主档做这些操作时需要对其记录日 ...

  4. 6-使用requests库封装类处理get/post请求

    1.request安装 1)pip安装,直接pip install requests 2)下载离线包安装,加压后,命令行进入路径,执行python setup.py install 2.创建工程 注意 ...

  5. Ajax获取Json多个集合并同时遍历

    Ajax获取Json多个集合并同时遍历: 方法一.:将多个集合放入MAP集合. 后台:Servlet @Override protected void doPost(HttpServletReques ...

  6. CentOS 5 常见的configure error的解决方法

    仅限于CentOS 5 configure: error: No curses/termcap library found 网上有的说法是: --with-named-curses-libs=/usr ...

  7. #254 Find the Longest Word in a String

    找出最长单词 在句子中找出最长的单词,并返回它的长度. 函数的返回值应该是一个数字. 当你完成不了挑战的时候,记得开大招'Read-Search-Ask'. 这是一些对你有帮助的资源: String. ...

  8. 架构(三)MongoDB安装配置以及集群搭建

    一 安装 1.1 下载MongoDB 我个人不太喜欢用wget url, 之前出现过wget下载的包有问题的情况 https://fastdl.mongodb.org/linux/mongodb-li ...

  9. 大叔学ML第三:多项式回归

    目录 基本形式 小试牛刀 再试牛刀 调用类库 基本形式 上文中,大叔说道了线性回归,线性回归是个非常直观又简单的模型,但是很多时候,数据的分布并不是线性的,如: 如果我们想用高次多项式拟合上面的数据应 ...

  10. 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

    1.前言 标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西.本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么. (本文同步 ...