java代理模式及动态代理类

1.      代理模式

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式一般涉及到的角色有:

抽象角色:声明真实对象和代理对象的共同接口;

代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。(参见文献1)

以下以《Java与模式》中的示例为例:

抽象角色:

abstract public class Subject

{

abstract public void request();

}

真实角色:实现了Subject的request()方法。

public class RealSubject extends Subject

{

public RealSubject()

{

}

public void request()

{

System.out.println("From real subject.");

}

}

代理角色:

public class ProxySubject extends Subject

{

private RealSubject realSubject;  //以真实角色作为代理角色的属性

public ProxySubject()

{

}

public void request()  //该方法封装了真实对象的request方法

{

preRequest();

if( realSubject == null )

{

realSubject = new RealSubject();

}

realSubject.request();  //此处执行真实对象的request方法

postRequest();

}

private void preRequest()

{

//something you want to do before requesting

}

private void postRequest()

{

//something you want to do after requesting

}

}

客户端调用:

Subject sub=new ProxySubject();

Sub.request();

由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他方法(preRequest(),postRequest()),可以处理一些其他问题。

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

2.动态代理类

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

(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),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接口中声明过的方法)。

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

在使用动态代理类时,我们必须实现InvocationHandler接口,以第一节中的示例为例:

抽象角色(之前是抽象类,此处应改为接口):

public interface Subject

{

abstract public void request();

}

具体角色RealSubject:同上;

代理角色:

import java.lang.reflect.Method;

import java.lang.reflect.InvocationHandler;

public class DynamicSubject implements InvocationHandler {

private Object sub;

public DynamicSubject() {

}

public DynamicSubject(Object obj) {

sub = obj;

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("before calling " + method);

method.invoke(sub,args);

System.out.println("after calling " + method);

return null;

}

}

该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;此外,在该类还实现了invoke方法,该方法中的

method.invoke(sub,args);

其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或之后执行一些相关操作。

客户端

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

public class Client

{

static public void main(String[] args) throws Throwable

{

RealSubject rs = new RealSubject();  //在这里指定被代理类

InvocationHandler ds = new DynamicSubject(rs);  //初始化代理类

Class cls = rs.getClass();

//以下是分解步骤

/*

Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;

Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});

Subject subject =(Subject) ct.newInstance(new Object[]{ds});

*/

//以下是一次性生成

Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),

cls.getInterfaces(),ds );

subject.request();

}

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

原文地址:http://blog.csdn.net/dyh8818/article/details/314668

Java动态代理一——动态类Proxy的使用

1.什么是动态代理?

答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
2.为什么使用动态代理?

答:因为动态代理可以对请求进行任何处理

3.使用它有哪些好处?

答:因为动态代理可以对请求进行任何处理
4.哪些地方需要动态代理?

答:不允许直接访问某些类;对访问要做特殊处理等

目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现

以下为模拟案例,通过动态代理实现在方法调用前后向控制台输出两句字符串

目录结构

<br/>

定义一个HelloWorld接口


 1 package com.ljq.test;
2
3  /**
4 * 定义一个HelloWorld接口
5 *
6 * @author jiqinlin
7 *
8 */
9  public interface HelloWorld {
10 public void sayHelloWorld();
11 }

<br/>

类HelloWorldImpl是HelloWorld接口的实现


 1 package com.ljq.test;
2
3  /**
4 * 类HelloWorldImpl是HelloWorld接口的实现
5 *
6 * @author jiqinlin
7 *
8 */
9  public class HelloWorldImpl implements HelloWorld{
10
11 public void sayHelloWorld() {
12 System.out.println("HelloWorld!");
13 }
14
15 }

HelloWorldHandler是 InvocationHandler接口实现


 1 package com.ljq.test;
2
3  import java.lang.reflect.InvocationHandler;
4  import java.lang.reflect.Method;
5
6  /**
7 * 实现在方法调用前后向控制台输出两句字符串
8 *
9 * @author jiqinlin
10 *
11 */
12  public class HelloWorldHandler implements InvocationHandler{
13 //要代理的原始对象
14   private Object obj;
15
16 public HelloWorldHandler(Object obj) {
17 super();
18 this.obj = obj;
19 }
20
21 /**
22 * 在代理实例上处理方法调用并返回结果
23 *
24 * @param proxy 代理类
25 * @param method 被代理的方法
26 * @param args 该方法的参数数组
27 */
28 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
29 Object result = null;
30 //调用之前
31   doBefore();
32 //调用原始对象的方法
33 result=method.invoke(obj, args);
34 //调用之后
35 doAfter();
36 return result;
37 }
38
39 private void doBefore(){
40 System.out.println("before method invoke");
41 }
42
43 private void doAfter(){
44 System.out.println("after method invoke");
45 }
46
47 }

测试类


package com.ljq.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class HelloWorldTest { public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorldImpl();
InvocationHandler handler=new HelloWorldHandler(helloWorld); //创建动态代理对象
HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance(
helloWorld.getClass().getClassLoader(),
helloWorld.getClass().getInterfaces(),
handler);
proxy.sayHelloWorld();
}
}

原文地址:http://www.cnblogs.com/linjiqin/archive/2011/02/18/1957600.html

Java代理模式的更多相关文章

  1. Java代理模式示例程序

    Java代理模式示例程序 当然不是我想出来的,是我看的一个网上教程里的. 模拟的是一个对电脑公司的代理 真实类的接口: public interface SaleComputer { public S ...

  2. java 代理模式 总结

    1.前言 最近舍友去面试遇到了关于java代理模式的问题. 我虽然知道怎么使用,但是没有做过正经的总结,因此有了这篇随笔,好好总结一下三大代理模式底层原理. 事实上,在开发项目的时候,基本用不上代理, ...

  3. 浅谈java代理模式

    讲解java代理模式 目录 讲解java代理模式 何谓代理模式 静态代理 动态代理 JDK动态代理 CGLIB动态代理 何谓代理模式 代理模式,即Proxy Pattern,23种java常用设计模式 ...

  4. Java代理模式/静态代理/动态代理

    代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委 ...

  5. JAVA代理模式与动态代理模式

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某 ...

  6. java 代理模式一: 静态代理

    代理模式: 代理模式的作用:为其他对象提供一种代理以控制对 特定对象  的访问. 某种情况下,一个客户不想或者直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用:通过代理对象引用. ...

  7. 18 java 代理模式 (转)

    静态代理 1.新建一个接口,这个接口所提供的方法是关于数据库操作的 public interface EmployeeDao { public void updateSalary(); } 2.建一个 ...

  8. JAVA 代理模式(Proxy)

    1.代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式一般涉 ...

  9. Java代理模式——静态代理模式

    一:代理模式 代理模式的作用是:为其他对象提供一种代理以控制这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 二:代理模式设计 ...

随机推荐

  1. RDLC的部署(无法找到Microsoft.ReportViewer.ProcessingObjectModel.dll文件)

    CMD命令:C:\Windows\assembly\GAC_MSIL\ rdlc 相比微软的其他产品来说,做得还真是够烂的了,比水晶报表也烂得多. 但不知为何我还是宁可先择 rdlc.并且渐渐上手了. ...

  2. 分享Kali Linux 2016.2第47周虚拟机

    分享Kali Linux 2016.2第47周虚拟机该虚拟机使用Kali Linux 2016.2第47周的64位镜像安装而成.基本设置如下:(1)该系统默认设置单CPU双核,内存为2GB,硬盘为50 ...

  3. JavaOne_2016演讲视频:

    http://list.youku.com/albumlist/show?id=28553407&qq-pf-to=pcqq.group

  4. ACM Color the fence

    Color the fence 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 Tom has fallen in love with Mary. Now Tom w ...

  5. 使用AFNetworking 2.0 请求数据时出现错误 Request failed: unacceptable content-type: text/html 解决方法

    使用AFNetworking 2.0 请求数据时出现错误 Request failed: unacceptable content-type: text/html 解决方法 添加一行 manager. ...

  6. 一个动画 Label (走马观花)

    UILabel中一个水平移动的Label UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 300, 300)]; U ...

  7. 【BZOJ】2212: [Poi2011]Tree Rotations

    题意 给一棵\(n(1 \le n \le 200000)\)个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少. 分析 可以发现如果交换非叶结点的左右子树,对子树内的交换无影响, ...

  8. 【BZOJ】3757: 苹果树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3757 题意:n个节点的树,每个点有一种颜色.现有m种询问,每次询问x y a b表示x到y的路径上颜 ...

  9. 不错的判断 UITextView 内容不超过20个字符串的方法

    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSSt ...

  10. LightOJ 1245 数学题,找规律

    1.LightOJ 1245   Harmonic Number (II)   数学题 2.总结:看了题解,很严谨,但又确实恶心的题 题意:求n/1+n/2+....+n/n,n<=2^31. ...