您的位置:首页 > 其它

23种设计模式----------代理模式(三) 之 动态代理模式

2014-12-14 00:42 441 查看
(上一篇)种设计模式----------代理模式(二)

当然代理模式中,用的最广泛的,用的最多的是 动态代理模式。

动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。

抽象接口的类图如下:



      --图来自设计模式之禅

所以动态代理模式要有一个InvocationHandler接口 和 GamePlayerIH实现类。其中 InvocationHandler是JD提供的动态代理接口,对被代理类的方法进行代理。

代码实现如下

抽象主题类或者接口:

package com.yemaozi.proxy.dynamic;

/*
* 动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。
*/
public interface IGamePlayer {
//登录游戏
public void login(String username, String password);

//击杀Boss
public void killBoss();

//升级
public void upGrade();
}


需要被代理类:

package com.yemaozi.proxy.dynamic;

public class GamePlayer implements IGamePlayer {

private String name = "";

public GamePlayer(String name){
this.name = name;
}

public void login(String username, String password) {
System.out.println("登录名为 "+username+" 进入游戏," + name + " 登录成功!");
}

public void killBoss() {
System.out.println(this.name + " 击杀了Boss!");
}

public void upGrade() {
System.out.println(this.name + "升级了!");
}

}


动态代理处理器类:

package com.yemaozi.proxy.dynamic;

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

public class GamePlayerInvocationHandler implements InvocationHandler{

//被代理的对象
private Object obj;

//将需要代理的实例通过处理器类的构造方法传递给代理。
public GamePlayerInvocationHandler(Object obj){
this.obj = obj;
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
if("login".equalsIgnoreCase(method.getName())){
//这个在主题方法不受任何影响的情况下,在主题方法前后添加新的功能,或者增强主题方法,
//从侧面切入从而达到扩展的效果的编程,就是面向切面编程(AOP Aspect Oriented Programming)。
//AOP并不是新技术,而是相对于面向对象编程的一种新的编程思想。在日志,事务,权限等方面使用较多。
System.out.println("代理登录游戏!");
result = method.invoke(this.obj, args);
return result;
}
result = method.invoke(this.obj, args);
return result;
}

}


由于代理是动态产生的,所以不需要再声明代理类。

动态代理场景类:

package com.yemaozi.proxy.dynamic;

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

public class Client {
public static void main(String[] args) {
IGamePlayer gp = new GamePlayer("张三");
InvocationHandler gpHandler = new GamePlayerInvocationHandler(gp);
//获取真实主题类的ClassLoader
ClassLoader classLoader = gp.getClass().getClassLoader();
//动态产生一个代理者。
Class<?>[] cls = new Class[]{IGamePlayer.class};
IGamePlayer proxyGp = (IGamePlayer) Proxy.newProxyInstance(classLoader, cls, gpHandler);
proxyGp.login("zhangsan", "123456");
proxyGp.killBoss();
proxyGp.upGrade();
}
}

执行结果:
代理登录游戏!
登录名为 zhangsan 进入游戏,张三 登录成功!
张三 击杀了Boss!
张三升级了!

//在此,我们没有创建代理类,但是确实有代理类帮我们完成事情。


其中,在此代理模式中,不仅代理是动态产生的(即在运行的时候生成),而且还在代理的时候,也增加了一些处理。在此处增加的处理,其实就是另一种编程思想-----面向切面编程思想(AOP Aspect Oriented Programming)。

带有AOP的动态代理模式类图:



        --图来自设计模式之禅

从上图中,可以看出有两个相对独立的模块(Subject和InvocationHandler)。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。然而,通知Advice从另一个切面切入,最终在上层模块就是Client耦合,完成逻辑的封装。

代码清单如下

抽象主题或者接口:

package com.yemaozi.proxy.dynamic_aop;

public interface Subject {
public void doSomething(String str);
//...可以多个逻辑处理方法。。。
}


真实主题:

package com.yemaozi.proxy.dynamic_aop;

public class RealSubject implements Subject{

public void doSomething(String str) {
//do something...
System.out.println("do something..." + str);
}

}


通知接口:

package com.yemaozi.proxy.dynamic_aop;

//通知接口及定义、
public interface IAdvice {
public void exec();
}


前置通知:

package com.yemaozi.proxy.dynamic_aop;

public class BeforeAdvice implements IAdvice {
//在被代理的方法前来执行,从而达到扩展功能。
public void exec() {
System.out.println("前置通知被执行!");
}
}


后置通知:

package com.yemaozi.proxy.dynamic_aop;

public class AfterAdvice implements IAdvice {

//在被代理的方法后来执行,从而达到扩展功能。
public void exec() {
System.out.println("后置通知被执行!");
}
}


动态代理的处理器类:

所有的方法通过invoke方法类实现。

package com.yemaozi.proxy.dynamic_aop;

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

public class MyInvocationHandler implements InvocationHandler {

//被代理的对象
private Subject realSubject;
//通过MyInvocationHandler的构造方法将被代理对象传递过来。
public MyInvocationHandler(Subject realSubject){
this.realSubject = realSubject;
}
//执行被代理类的方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在执行方法前,执行前置通知。
IAdvice beforeAdvice = new BeforeAdvice();
beforeAdvice.exec();
Object result = method.invoke(this.realSubject, args);
//在执行方法后,执行后置通知。
IAdvice afterAdvice = new AfterAdvice();
afterAdvice.exec();
//前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。
return result;
}

}


动态代理类:

package com.yemaozi.proxy.dynamic_aop;

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

public class DynamicProxy {

/**
* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)
* loader:
*             一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。
* interfaces:
*             一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口,
*             如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。
*             即,查找出真是主题类的所实现的所有的接口。
* handler:
*             一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。
*             该InvocationHandler与主题类有着关联。
*/
public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
@SuppressWarnings("unchecked")
T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
return t;
}
}


从动态的产生动态代理类。

动态代理场景类:

package com.yemaozi.proxy.dynamic_aop;

import java.lang.reflect.InvocationHandler;

public class AOPClient {

public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new MyInvocationHandler(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Class<?>[] interfaces = realSubject.getClass().getInterfaces();
Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler);
proxySubect.doSomething("这是一个Dynamic AOP示例!!!");
}
}

执行结果:
前置通知被执行!
do something...这是一个Dynamic AOP示例!!!
后置通知被执行!


动态代理中invoke的动态调用:



动态代理类DynamicProxy是个纯粹的动态创建代理类通用类。

所以在具体业务中,可以在进一步封装具体的具有业务逻辑意义的DynamicProxy类。

代码如下

具体业务的动态代理:

package com.yemaozi.proxy.dynamic_aop;

import java.lang.reflect.InvocationHandler;
//具体业务的动态代理。
public class SubjectDynamicProxy extends DynamicProxy {
public static <T> T newProxyInstance(Subject subject){
ClassLoader classLoader = subject.getClass().getClassLoader();
Class<?>[] interfaces = subject.getClass().getInterfaces();
InvocationHandler handler = new MyInvocationHandler(subject);
T t = newProxyInstance(classLoader, interfaces, handler);
return t;
}
}


动态代理在现在用的是非常的多的,如像Spring AOP ,DBCP连接池,AspectJ等。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: