您的位置:首页 > 编程语言 > Java开发

设计模式之禅——代理模式(二)代理模式&AOP编程&JDK对代理模式的支持

2016-08-28 10:19 225 查看
本篇文章还是用上一篇动态代理的例子设计模式之禅——代理模式(一)普通代理&强制代理&虚拟代理&动态代理

下面再贴一遍动态代理部分的代码,看过前一篇的可以省略~

例子:游戏玩家找代理刷怪升级

动态代理的代码

//玩家接口类
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;
}
@Override
public void login(String user, String password) {
System.out.println("登录名为" + user + "的用户" + this.name + "登陆成功");
}

@Override
public void killBoss() {
System.out.println(this.name + " 在打怪");

}

@Override
public void upgrade() {
System.out.println(this.name + " 又生了一级");

}

}


//动态代理的Handler类
public class GamePlayIH implements InvocationHandler {

//被代理者
Class cls = null;
//被代理的实例
Object obj = null;
public GamePlayIH(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
Object result = method.invoke(this.obj, args);
return result;
}
}


//Client类
public class Client {
public static void main(String[] args) {
//定义一个主题
Subject subject = new RealSubject();
//定义一个主题的代理
Subject proxy =SubjectDynamicProxy.newProxyInstance(subject);
proxy.doSomething("Finish");
}
}
/*Output
开始时间: 2016-8-28 10:12
登录名为zhangsan的用户张三登陆成功
张三 在打怪
张三 又生了一级
结束时间: 2016-8-28 10:14

*/


ok,上一篇我们已经讲了动态代理最简单的表现形式,现在我们为之前的例子加一个需求——想让游戏登陆之后发一个信息给我们,防止账号被人盗用。怎么处理呢?直接修改被代理类GamePlayer?No,不需要!

只需要修改GamePlayIH类就可以了

public class GamePlayIH implements InvocationHandler {

//被代理者
Class cls = null;
//被代理的实例
Object obj = null;
public GamePlayIH(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
Object result = method.invoke(this.obj, args);
if(method.getName().equalsIgnoreCase("login")){
System.out.println("有人登陆了我的账号");
}
return result;
}
}


看运行结果

/*
开始时间: 2016-8-28 10:12
登录名为zhangsan的用户张三登陆成功

有人登陆了我的账号

张三 在打怪
张三 又生了一级
结束时间: 2016-8-28 10:14
*/


ok,这其实就是AOP编程。

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP编程并没有使用什么新的技术,但是它对我们的设计、编码都有非常大的影响,对于日志、事务、权限等都可以在系统设计阶段不用考虑,而在设计后通过AOP的方式切过去。既然动态代理是如此的诱人,我们来看一下它的通用类图

UML图



很简单,两条独立发展的线路。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。

见代码

//抽象主题——被代理类要实现的方法
public interface Subject{
//业务逻辑
public void doSomething(String str);
}


public class RealSubject implements Subject{
//业务操作
public void doSomething(String str){
System.out.println("do someThing!---->" + str);
}
}


//动态代理的Handler类

public class MyInvocationHandler implements InvocationHandler {

//被代理的对象
private Object target = null;
public MyInvocationHandler(Object _obj){
this.target = _obj;
}
//代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 执行被代理的方法
return method.invoke(this.target, args);
}

}


//动态代理类

public class DynamicProxy <T>{
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h){
if(true){
(new BeforeAdvice()).exec();
}
return (T)Proxy.newProxyInstance(loader, interfaces, h);

}
}


//通知接口及实现
public interface IAdvice {
public void exec();
}

public class BeforeAdvice implements IAdvice{
public void exec(){
System.out.println("我是前置通知,我被执行了");
}
}


//Client类
public class Client {
public static void main(String[] args) {
//定义一个主题
Subject subject = new RealSubject();
//定义一个Handler
MyInvocationHandler handler = new MyInvocationHandler(subject);
//定义一个主题的代理
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader()
, subject.getClass().getInterfaces(), handler);
proxy.doSomething("Finish");
}
}
/*
我是前置通知,我被执行了
do someThing!---->Finish
*/


ok,所有的程序都看完了,我们再来看看程序是怎么实现的。在DynamicProxy类中,我们有这样的方法:

this.obj = Proxy.newProxyInstance(c.getClassLoader, c.getInterfaces(), new MyInvocationHandler(_obj);


该方法是重新生成了一个对象,为什么要重新生成?你要使用代理呀,注意c.getInterfaces()这句话,这是非常有意思的一句话,是说查找该类的所有接口,然后实现接口的所有方法,由谁具体负责接管呢?是
new MyInvocationHandler(_Obj)
这个对象。于是我们知道一个类的动态代理类是这样的一个类——由InvocationHandler的实现类实现所有的方法,由其invoke方法接管所有方法的实现。

我们注意到上面的代码还有更进一步的拓展余地,注意看DynamicProxy类,他是一个通用类,不具有业务意思,如果我们再生成一个实现类是不是很有意义呢?

见代码

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


//Client
public class client {
public static void main(String[] args) throws InterruptedException{
NetDeal netDeal = new NetDeal();
netDeal.excute("surround", "1:0");
netDeal.block();
}
}
/*
我是前置通知,我被执行了
do someThing!---->Finish
*/


很明显拓展以后变得更简单了?可能有人会问,这样与静态代理还有什么区别?都是需要实现一个代理类,有区别!注意看父类,动态代理的主要意图就是解决我们常说的”审计“问题,在不改变我们已有代码的情况下增强或控制对象的行为。

注意!要实现动态代理的首要条件是:被代理类必须实现一个接口。当然,现在很多技术如CGLIB可以试下不需要接口也可以实现动态代理。

好了,以上的动态代理是一个通用的代理框架。如果你想设计自己的AOP框架,完全可以在此基础上拓展~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息