设计模式—静态代理模式和动态代理模式(Proxy Pattern)

一、静态代理模式

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。—《Head First设计模式 》书中对代理模式的定义。打个比方说,你要买火车票,但是你又不想去很远的火车站去买,所以你会选择去附近的代售点去买,但是,你要知道代售点并不是自己买票,只有火车站才真正卖票,代售点卖给你的票其实是通过火车站实现的

代理模式有三个组成部分:

(1)抽象角色:通过接口或抽象类声明真实角色实现的业务方法;

(2)代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作;

(3)真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

代理模式UML图如下:


接下来,我们来看一个示例:

抽象角色:

package com.proxy01;

//抽象角色
public interface Subject {
	void request();
}

真实角色:

package com.proxy01;
//真实角色
public class RealSubject implements Subject {
	
	@Override
	public void request() {
		System.out.println("From real subject");
	}

}

代理角色:

package com.proxy01;

public class  ProxySubject  implements Subject  {
	  // 以真实角色作为代理角色的属性
	  private  Subject realSubject;

	  public  ProxySubject(Subject realSubject)  {this.realSubject = realSubject ;}

	  // 该方法封装了真实对象的request方法
	  public void  request()  {
	     preRequest();
	     realSubject.request();  // 此处执行真实对象的request方法
	     postRequest();
	  }
	  private static void preRequest(){
		  System.out.println("前置处理");
	  }
	  private static void  postRequest(){
		  System.out.println("后置处理");
	  }
}

客户端:

package com.proxy01;

public class Client {
	public static void main(String[] args) {
		RealSubject real = new RealSubject();
		Subject sub = new  ProxySubject(real);
		sub.request();
	}
}

运行结果:

前置处理
From real subject
后置处理

以上介绍的是静态代理模式,静态代理在程序运行之前,代理类的.class文件就已经存在了。而接下来要介绍的动态代理模式在程序运行时,运用反射机制动态创建而成。


二、Java中的动态代理模式

从JDK1.3开始,java中引入了动态代理机制。动态代理有两部分组成,分别是:

(1)代理接口,是代理类实现的一个接口。

(2)代理实例,是代理类的一个实例。

相关的接口或类有如下两个:InvocationHandler和Proxy,都位于java.lang.reflect包下。

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

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

其中:

Object proxy:指代我们代理那个真实对象;

Method method:指代的是我们所要调用真实对象的某个方法的Method对象 ;
Object[] args:方法调用时所需要的参数 。


接下来我们来看看Proxy类,Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了好多方法,但是我们用的最多的就是 newProxyInstance这个方法

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
其中:

loader:一个ClassLoder 对象,定义了由哪个ClassLoder 对象来对生成的代理进行加载;

interface:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一个接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了;

h:一个Invocationhandler对象,表示的是当我这个动态代理对象在调用方法 的时候,会关联到哪一个Invocationhandler对象上。

动态代理UML图如下:


此图来源于:http://www.cnblogs.com/machine/archive/2013/02/21/2921345.html

同样,我们来实现一个简单实例

抽象角色:

package com.proxy;

//抽象角色
public interface Subject {
	void request();
}
具体角色:

package com.proxy;
//具体角色
public class RealSubject implements Subject {
	
	@Override
	public void request() {
		System.out.println("From real subject");
	}

}
代理处理器:

package com.proxy;
//代理处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicSubject implements InvocationHandler {
	private Object sub;

	public DynamicSubject() {}
	
	public DynamicSubject(Object sub) {
		super();
		this.sub = sub;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("前置处理");
		method.invoke(sub, args);
		System.out.println("后置处理");
		return null;
	}
}
客户端:

package com.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client {
	public static void main(String[] args) throws Throwable{
		RealSubject rs=new RealSubject();
		InvocationHandler ds=new DynamicSubject(rs);
		Class cls=rs.getClass();
		
		Subject subject=(Subject)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), ds);
		subject.request();
				
	}
}
运行结果:

前置处理
From real subject
后置处理
参考:java的动态代理机制详解    java代理机制









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值