java设计模式——代理模式之动态代理(3)

本文主要参考资料:《设计模式之禅》

接着《 java设计模式——代理模式的应用与扩展(2)》继续讲

目录:

1)什么是动态代理

2)动态代理模板

1)什么是动态代理

动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理那一个对象,相对的来说,自己写代理类的方式就是静态代理。现在有一个非常流行的名称叫做:面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制

我们还是以打游戏为例,将类图修改一下以实现动态代理,我们先来看看类图:

在类图中增加了一个InvocationHandler接口和GamePlayIH 类,作用就是产生一个对象的代理对象。其中InvocationHandler是JDK提供的动态代理接口,对被代理类的方法进行代理。

public interface IGamePlayer {

	//登录游戏
	public void login(String user,String password);
	
	//杀怪,这是网络游戏的主要特色
	public void killBoss();
	
	//升级
	public void upgrade();
}
public class GamePlayer implements IGamePlayer {
	private String name = "";
	
	//通过构造函数传递名称
	public GamePlayer(String _name){
		this.name = _name;
	}
		
	//打怪,最期望的就是杀老怪
	public void killBoss() {
		System.out.println(this.name + "在打怪!");
	}
	
	//进游戏之前你肯定要登录吧,这是一个必要条件
	public void login(String user, String password) {
		System.out.println("登录名为"+user + " 的用户 " + this.name + "登录成功!");
	}

	//升级,升级有很多方法,花钱买是一种,做任务也是一种
	public void upgrade() {
		System.out.println(this.name + " 又升了一级!");
	}
}
public class GamePlayIH implements InvocationHandler {
	//被代理者
	Class<?> cls =null;
	//被代理的实例
	Object obj = null;
	
	//我要代理谁
	public GamePlayIH(Object _obj){
		this.obj = _obj;
	}
	
	//调用被代理的方法
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
		Object result = method.invoke(this.obj, args);
		return result;
	}
}

其中invoke方法是接口InvocationHandler定义必须实现的,它完成对真实方法的调用

我们来详细讲解一下InvocationHanlder接口,动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那各位读者想想看,动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是空的,是的,代理已经实现它了,但是没有任何的逻辑含义,那怎么办?好办,通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。 

public class Client {

	public static void main(String[] args) throws Throwable  {
		//定义一个痴迷的玩家
		IGamePlayer player = new GamePlayer("张三");		
		//定义一个hanlder
		InvocationHandler handler = new GamePlayIH(player);		
		//开始打游戏,记下时间戳
		System.out.println("开始时间是:2009-8-25 10:45");		
		//获得类的class loader
		ClassLoader cl = player.getClass().getClassLoader();		
		//动态产生一个代理者
		IGamePlayer proxy = (IGamePlayer)Proxy.newProxyInstance(cl,new Class[]{IGamePlayer.class},handler);		
		//登录
		proxy.login("zhangSan", "password");		
		//开始杀怪
		proxy.killBoss();
		//升级
		proxy.upgrade();
		//记录结束游戏时间
		System.out.println("结束时间是:2009-8-26 03:40");
		
	}
}

我们还是让代练者帮我们打游戏,但是我们既没有创建代理类,也没有实现IGamePlayer接口,这就是动态代理!

不懂是吧?那我们继续往下看

现在我们如果想让游戏登录后发一个信息给我们,防止账号被人盗用,怎么做?可能大家第一反应是修改被代理类GamePlayer,但这不是好办法,我们看好办法:

看红色框框里面,只要在代理中增加一个判断就可以决定是否要发送信息。运行结果如下:

太棒了,有人用我的账号就发送一条信息给我,然后看看自己的账号是不是被人盗了,非常好,这就是AOP编程。

AOP编程没有使用什么新的技术,但是它对我们的设计,编码有非常大的影响,对于日志,事务,权限等都可以在系统设计阶段不用考虑,而在设计后用过AOP的方式切过去。

2. 动态代理模板

先来看看类图:

两条独立发展的路线。动态代理实现代理职责,业务逻辑Subject实现相关逻辑功能,两者之间没有必然的相互耦合的关系。

通知Advice从另一个切面切入,最终在高层模块也就是Client耦合,完成封装任务。

public interface Subject {
	
	//业务操作
	public void doSomething(String abc);
}
public class RealSubject implements Subject {

	//业务操作
	public void doSomething(String str) {
		System.out.println("do something!---->" + str);
	}
}
public class MyInvocationHandler implements InvocationHandler {
	//被代理的对象
	private Object target = null;
	//通过构造函数传递一个对象
	public MyInvocationHandler(Object _obj){
		this.target = _obj;
	}
	//代理方法	
	public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
		//执行被代理的方法
		return method.invoke(this.target, args);
	}
}

所有通过动态代理实现的方法全部通过invoke方法调用。

public interface IAdvice {
	
	//通知只有一个方法,执行即可
	public void exec();
}
public class BeforeAdvice implements IAdvice{
	
	public void exec(){
		System.out.println("我是前置通知,我被执行了!");
	}
}
public class DynamicProxy<T> {

	public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
		//寻找JoinPoint连接点,AOP框架使用元数据定义
		if(true){
			
			(new BeforeAdvice()).exec();   //执行一个前置通知
		}
		//执行目标,并返回结果
		return (T)Proxy.newProxyInstance(loader,interfaces, h);		
	}
}

猜你喜欢

转载自blog.csdn.net/qq_36582604/article/details/82290815
今日推荐