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

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

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

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

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

一、静态代理

下面来看具体代码

抽象角色:

public interface Subject {

    public void doSomething();
}

真实角色:

public class RealSubject implements Subject {
@Override
public void doSomething() { System.out.println("do something!");
}
}

代理角色:

public class PoxySubject implements Subject{
private RealSubject subject; @Override
public void doSomething() {
this.doPreThing(); if (null == subject) { subject = new RealSubject();
} subject.doSomething();
this.dopostThing();
} public void doPreThing() {
System.out.println("pre things");
} public void dopostThing() {
System.out.println("post things");
}
}

测试类(main方法)

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

运行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接口中声明过的方法)

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

抽象角色:

public interface Subject {
public void doSomething();
}

真实角色:

public class RealSubject implements Subject {

    public void doSomething() {
System.out.println("from real subject");
}
}

实现代理角色的类:

public class DynamicSubject implements InvocationHandler {

    private Object sub;

    public DynamicSubject(Object obj) {
this.sub = obj;
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("调用之前" + method); method.invoke(sub, args); System.out.println("调用之后" + method); return null;
}
}

测试类(main方法):

public class Client {

    public static void main(String[] args) {
RealSubject sub = new RealSubject();
InvocationHandler hanlder = new DynamicSubject(sub); //返回代理类的一个实例
Subject subject =(Subject)Proxy.newProxyInstance(hanlder.getClass().getClassLoader(), sub.getClass().getInterfaces(), hanlder);
subject.doSomething();
}
}

运行结果:

调用之前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. 使用VS+OpenCV调用深度学习模型

    最近项目有个任务,要在windows环境下用VS+OpenCV实现caffe模型的调用,于是在网上找了几个相关的博客跑了几个demo练练手.这些博客写得都很详细,但是有些细节由于版本更新的问题,配置的 ...

  2. String StringBuilder StringBuffer区别

    String StringBuilder StringBuffer String类是final类,不可以被继承,且它的成员方法也是final方法,当一个字符串对象进行操作操作时,任何的改变不会影响到这 ...

  3. extjs__(grid Panel绑定数据)

    1.修改面板名称 双击My Panel  就可以进行修改 2拖入一个grid  panel绑定数据 3.创建一个model  只是为了创建一个模型  相当于java中的模型层  只是数据的一个标准 4 ...

  4. Leetcode_5.最长回文子串

    最长回文子串 题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab& ...

  5. Eclipse常用20个快捷键

    Eclipse常用20个快捷键 1. Ctrl+F : 本文查找Find与替换Replace 2. Ctrl+H : 全局搜索,可按照文件类型搜索 3. Ctrl+1 : 快速修复,能快速的显示光标所 ...

  6. Android 视频播放器 (三):使用NBPlayer播放直播视频

    一.前言 在 Android 音视频开发学习思路 中,我们不断的学习和了解音视频相关的知识,随着知识点不断的学习,我们现在应该做的事情,就是将知识点不断的串联起来.这样才能得到更深层次的领悟.通过整理 ...

  7. 每天学点SpringCloud(九):SpringCloud最常用配置详解

    Eureka 属性名 说明 默认值 eureka.server.enable-self-preservation 关闭注册中心的保护机制,Eureka 会统计15分钟之内心跳失败的比例低于85%将会触 ...

  8. 吴恩达机器学习笔记6-梯度下降II(Gradient descent intuition)--梯度下降的直观理解

    在之前的学习中,我们给出了一个数学上关于梯度下降的定义,本次视频我们更深入研究一下,更直观地感受一下这个算法是做什么的,以及梯度下降算法的更新过程有什么意义.梯度下降算法如下: 描述:对

  9. 远程桌面连接:出现身份验证错误,要求的函数不受支持,可能是由于CredSSP加密Oracle修正的解决方法

    在做app时需要连接服务器来进行数据交互,但是在阿里云页面里连接服务器太不好用,所以使用windows自带的远程连接来进行. 一.但是连接的过程中出现了以下问题: 二.最初是有点迷茫的,不知道从哪里下 ...

  10. [2019BUAA软工助教]第0次代码作业

    [2019BUAA软工助教]第0次代码作业 前言 本博客为完成结对项目所需的先导知识,题目不难,请认真对待 :) 欢迎来到软件工程 :) 注:本次实验为附加作业,不做不扣分,做了有附加分 Part 0 ...