动态代理是大型框架中经常用到的经典的技术之一,博主在理解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. 去除最后一个li的样式

    推荐::::方法一,使用:first-child    纯css的:first-child伪类就可以胜任此任务,操作很方便,代码量忽略不计.支持IE7+,不支持IE6 :first-child /:l ...

  2. shell脚本学习-循环

    跟着RUNOOB网站的教程学习的笔记 for循环 与其他编程语言类似,shell支持for循环. for循环一般格式为: for var in item1 item2 ... itemN do com ...

  3. linux 环境统配

    #java JAVA_HOME=/opt/jdk CLASSPATH=$JAVA_HOME/lib/ PATH=$PATH:$JAVA_HOME/bin export PATH JAVA_HOME C ...

  4. poj 3468 A Simple Problem with Integers(线段树区间更新)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  5. PHP单一文件入口框架简析

    <?php /** * PHP单一文件框架设计简析 * 1.MVC架构实现 * 2.URL路由原理 */ //URL路由原理 /** * 路由作用 * 获取url中的c和a变量,执行c类对应的方 ...

  6. #224 Profile Lookup (for in & if )

    我们有一个对象数组,里面存储着通讯录. 函数 lookUp 有两个预定义参数:firstName值和prop属性 . 函数将会检查通讯录中是否存在一个与传入的 firstName 相同的联系人.如果存 ...

  7. pwnable.kr详细通关秘籍(二)

    i春秋作家:W1ngs 原文来自:pwnable.kr详细通关秘籍(二) 0x00 input 首先看一下代码: 可以看到程序总共有五步,全部都满足了才可以得到flag,那我们就一步一步来看 这道题考 ...

  8. Java开发微服务为什么一定要选spring cloud?

    来自:网易乐得技术团队,作者:董添 李秉谦 现如今微服务架构十分流行,而采用微服务构建系统也会带来更清晰的业务划分和可扩展性.同时,支持微服务的技术栈也是多种多样的,本系列文章主要介绍这些技术中的翘楚 ...

  9. Javascript高级编程学习笔记(74)—— 表单(2)表单提交及重置

    表单提交 表单的很大一部分作用就是帮助用户完成和服务器的交互 所以表单提交是表单中比较重要的部分 虽然现如今的大部分应用场景都使用 AJAX 的异步请求来代替表单,但是仍有部分操作需要使用表单来完成, ...

  10. Redis学习笔记之Redis基本数据结构

    Redis基础数据结构 Redis有5种基本数据结构:String(字符串).list(列表).set(集合).hash(哈希).zset(有序集合) 字符串string 字符串类型是Redis的va ...