关闭

静态代理和动态模式

594人阅读 评论(0) 收藏 举报

案例场景:

1、一个售票站点,可以代买火车票,当我们需要买火车票的时候,我们可以自己去火车站买,也可以找售票点买火车票,在这里,我们可以把售票点视为代理类。从程序的角度上讲,我们就相当与一个对象,如果每个人都自己去火车站买票,那么要实现这个功能的话,相当与在每个对象中都要写上一个买票的方法,况且买票前后可能要做一些相关的操作,例如排队等候,退票等等,这样实现的程序代码重用性很高,所以我们可以把这些公共的事交给代理类去做,我们只要想买票,那就交给代理类,让代理类帮我们办好,我们最后只需要取票即可,所有的人都可以找这个代理类。

2、在日常生活中,我们可能有这样的需求,实现吃饭-工作-睡觉,但是我们的主体可能是工作,例如我们定义一个工作的实现类workImpl,里面有个工作的方法doWork,但是工作前我们得吃饭,工作后我们得睡觉,这些我们不能直接定义在workImpl中,因为它只能处理工作的方法,纯面向对象的思想只允许将类的相关属性和方法写在一个类中,因此按照这个思想,面向对象是不能帮我们解决的,因此这里我们可以使用面向切面编程,把吃饭和睡觉这些方法交给代理类去做,在这里相当与一个切面。


代理模式涉及到的角色:

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

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

真实角色:代理角色所代表的真实对象,使我们最终要引用的对象。


下面,我们用代码来描述上面的场景2:

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

public interface Work {
	public void doWork();

}
代理角色

package cn.com.test1;
//ProxyWork这里被认为是一个切面了,不再是个类,因此它可以有吃饭、睡觉等各种方法。
public class ProxyWork implements Work {
	private WorkImpl workImpl;//真实对象的引用
	
	public Proxy(){
		workImpl=new WorkImpl();
	}
	
	public void doWork(){
		eat();//工作前吃饭
		workImpl.doWork();
		sleep();//工作后睡觉
		
	}


        //附加其它操作
public void eat(){System.out.println("吃饭");}
public void sleep(){System.out.println("睡觉");}}


真实角色:使我们最终要引用的对象。

package cn.com.test1;

public class WorkImpl implements Work {

	public void doWork() {
		System.out.println("工作");

	}
}


测试类:

public static void main(String[] args) {
		Work work=new ProxyWork();
		work.doWork();
}

输出结果:吃饭  工作  睡觉
当我们调用工作方法的时候,代理类帮我们把吃饭和睡觉都做好了,就是说当我们要执行某个业务逻辑的时候,在执行前或执行后都要执行的方法,我们可以交给代理类去做,让代理类帮我们实现。


动态代理:

使用上面代理模式的弊端:在ProxyWork代理类中,只能处理工作,也就是说只能完成吃饭-工作-睡觉,我们有时候会有很多中间方法,比如说吃饭-运动-睡觉,吃饭-玩游戏-睡觉...,也就是中间方法很多,上面只能处理工作,不灵活,这时候我们可以使用动态代理;

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

(1)Interface InvocationHandler:该接口中只定义了一个方法

  public Object invoke(Object obj,Method method,Object[ ] args);在实际使用时,第一个参数obj一般是指代理类,method是指被代理的方法,例如上面的work,args表示方法参数数组,这个抽象方法在代理类中动态实现。

编写上面的动态代理类:

package cn.com.test1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//定义动态代理类
public class DynaProxy implements InvocationHandler {
	private Object obj;//真实对象
	public DynaProxy(Object obj){
		this.obj=obj;
		
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		eat();
		//执行真实对象中的方法(方法所在的对象,方法接收的参数数组)
		Object o=method.invoke(obj, args);
		sleep();
		return o;
	}
	
	public void eat(){
		System.out.println("吃饭");
	}

	public void sleep(){
		System.out.println("睡觉");
	}
}


(2)Proxy:该类即为动态代理类,主要包括:protected  Proxy(InvocationHandler h):构造函数,用于给内部的h赋值

static Class getProxyClass(ClassLoader loader,Class[ ] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的接口数组

static Object newProxyInstance(ClassLoader loader,Class[ ] interfaces,InvocationHandler h),返回代理类的一个实例,返回后的代理类可以当作被代理类使用。

编写上面的测试类:

public static void main(String[] args) {
		// 声明一个真实对象
		Work work = new WorkImpl();
		// 声明一个能AOP执行的真实对象方法中的对象
		DynaProxy dynaProxy = new DynaProxy(work);
		// 产生代理对象,相当与上面的ProxyWork
		//newProxyInstance(真实对象使用的类加载器,要代理的类的接口,Aop执行的方法)
		Object obj = Proxy.newProxyInstance(work.getClass.getClassLoader(),
				work.getClass.getClassInterfaces(), dynaProxy);
		Work w=(Work)obj;
		w.doWork();
		
}

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



1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:421774次
    • 积分:5864
    • 等级:
    • 排名:第4329名
    • 原创:215篇
    • 转载:39篇
    • 译文:3篇
    • 评论:113条
    最新评论