动态代理模式.docx

上传人:b****3 文档编号:6238253 上传时间:2023-05-09 格式:DOCX 页数:19 大小:59.94KB
下载 相关 举报
动态代理模式.docx_第1页
第1页 / 共19页
动态代理模式.docx_第2页
第2页 / 共19页
动态代理模式.docx_第3页
第3页 / 共19页
动态代理模式.docx_第4页
第4页 / 共19页
动态代理模式.docx_第5页
第5页 / 共19页
动态代理模式.docx_第6页
第6页 / 共19页
动态代理模式.docx_第7页
第7页 / 共19页
动态代理模式.docx_第8页
第8页 / 共19页
动态代理模式.docx_第9页
第9页 / 共19页
动态代理模式.docx_第10页
第10页 / 共19页
动态代理模式.docx_第11页
第11页 / 共19页
动态代理模式.docx_第12页
第12页 / 共19页
动态代理模式.docx_第13页
第13页 / 共19页
动态代理模式.docx_第14页
第14页 / 共19页
动态代理模式.docx_第15页
第15页 / 共19页
动态代理模式.docx_第16页
第16页 / 共19页
动态代理模式.docx_第17页
第17页 / 共19页
动态代理模式.docx_第18页
第18页 / 共19页
动态代理模式.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

动态代理模式.docx

《动态代理模式.docx》由会员分享,可在线阅读,更多相关《动态代理模式.docx(19页珍藏版)》请在冰点文库上搜索。

动态代理模式.docx

动态代理模式

packagecom.bjsxt.proxy;

importjava.util.Random;

 

publicclassTankimplementsMoveable{

@Override

publicvoidmove(){

System.out.println("TankMoving...");

try{

Thread.sleep(newRandom().nextInt(10000));

//表明tank正在移动中

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

想知道看此段代码运行了多长时间。

方法里面运行的时间。

一个类里面有另外一个类的对象,这叫做聚合

一个用继承实现此功能,一个用聚合实现此功能。

聚合好,继承不灵活

记录日志、记录时间、记录权限的控制

用继承的方式会无限制的迭加下去。

类爆炸现象!

代理之间互相的组合!

因为共同实现的是Movable接口!

关键是实现同一接口!

这是静态代理!

先日志、后时间还是先时时间,还是日志

代理的类根据需求还可能无限膨胀下去。

动态代理解决类太多的问题!

实现动态的编译:

/JDK6ComplierAPI,CGLib,ASM

代理的总代理

深入java虚拟机----二进制代码的实现。

被代理的类都实现了一种结果!

继承也能实现,但是不推荐使用!

1实现

packagepiler.test;

importjava.io.File;

importjava.io.FileWriter;

importjava.lang.reflect.Constructor;

import.URL;

import.URLClassLoader;

importjavax.tools.JavaCompiler;

importjavax.tools.StandardJavaFileManager;

importjavax.tools.ToolProvider;

importjavax.tools.JavaCompiler.CompilationTask;

importcom.bjsxt.proxy.Moveable;

importcom.bjsxt.proxy.Tank;

publicclassTest1{

publicstaticvoidmain(String[]args)throwsException{

Stringrt="\r\n";

Stringsrc=

"packagecom.bjsxt.proxy;"+rt+

"publicclassTankTimeProxyimplementsMoveable{"+rt+

"publicTankTimeProxy(Moveablet){"+rt+

"super();"+rt+

"this.t=t;"+rt+

"}"+rt+

"Moveablet;"+rt+

"@Override"+rt+

"publicvoidmove(){"+rt+

"longstart=System.currentTimeMillis();"+rt+

"System.out.println(\"starttime:

\"+start);"+rt+

"t.move();"+rt+

"longend=System.currentTimeMillis();"+rt+

"System.out.println(\"time:

\"+(end-start));"+rt+

"}"+rt+

"}";

System.out.println(System.getProperty("user.dir"));//D:

\Documents\GalileoSr2\Proxy

StringfileName=System.getProperty("user.dir")

+"/src/com/bjsxt/proxy/TankTimeProxy.java";

Filef=newFile(fileName);

FileWriterfw=newFileWriter(f);

fw.write(src);

fw.flush();

fw.close();

//compile

JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();

System.out.println(compiler.getClass().getName());//com.sun.tools.javac.api.JavacTool

StandardJavaFileManagerfileMgr=compiler.getStandardFileManager(null,null,null);

Iterableunits=fileMgr.getJavaFileObjects(fileName);

CompilationTaskt=compiler.getTask(null,fileMgr,null,null,null,units);

t.call();

fileMgr.close();

//loadintomemoryandcreateaninstance

URL[]urls=newURL[]{newURL("file:

/"+System.getProperty("user.dir")+"/src")};

URLClassLoaderul=newURLClassLoader(urls);

Classc=ul.loadClass("com.bjsxt.proxy.TankTimeProxy");

System.out.println(c);//classcom.bjsxt.proxy.TankTimeProxy

Constructorctr=c.getConstructor(Moveable.class);

Moveablem=(Moveable)ctr.newInstance(newTank());

m.move();

}

}

上面只是实现了movable接口的动态代理

现在可以实现任意接口的动态代理:

把接口也传进去

只要传任何接口,能够实现任意接口的对象!

Java中通过动态代理类实现。

//可以对任意的对象、任意的接口方法,实现任意的代理

2代理模式、动态代理和面向方面

分类:

模式2006-01-1122:

524423人阅读评论(5)收藏举报

                                                 代理模式、动态代理和面向方面

 

   代理的意思很好理解,它借鉴了我们日常所用的代理的意思:

就是本来该自己亲自去做的某件事,由于某种原因不能直接做,而只能请人代替你做,这个被你请来做事的人就是代理。

比如过春节要回家,由于你要上班,没时间去买票,就得票务中介代你购买,这就是一种代理模式。

这个情景可以形象的描述如下:

class:

火车站

{

       卖票:

      {……}

}

   火车站是卖票的地方,我们假设只能在火车站买到票。

卖票的动作实质是火车站类完成的。

Class:

票务中介

{

       卖票:

       {

             收中介费;

            火车站.卖票;

}

}

   顾客找票务中介买票的时候,调用票务中介.卖票。

票务中介其实做了两件事,一是去火车站买票,二是不能白帮你卖票,肯定要收中介费。

而你得到的好处是不用直接去火车站买票,节省了买票的时间用来上班。

   以上我们简单模拟了代理模式的情景和为什么要使用代理模式,下面我们以一个例子来具体分析一下JAVA中的代理模式。

   假设有一个信息管理系统,用些用户有浏览信息的权限,有些用户有浏览、添加和修改信息的权限,还有些用户有除了上述的权限,还有删除信息的权限,那么我们最容易想到的做法如下:

publicclassViewAction

{

       //由userId计算权限

       ……

       Stringpermission=……;

      if(permission.equals(Constants.VIEW))

       {

             System.out.println(“Youcouldviewtheinformation……”);

             ……

}

}

   其他的动作都和浏览信息的动作差不多。

我们来看这样的类,很容易看出它的一些缺点来:

第一、它把权限计算和动作执行都放在一个类里,两者的功能相互混在一起,容易造成思路的混乱,而且修改维护和测试都不好;一句话来说,它不满足单一职责原则。

第二是客户调用的时候依赖具体的类,造成扩展和运行期内的调用的困难,不满足依赖颠倒原则。

   既然有这么多的问题,我们有必要对该类进行重新设计。

其实大家早已想到,这个类应该使用代理模式。

是啊,和我们买火车票的动作一样,动作类不能直接执行那个动作,而是要先检查权限,然后才能执行;先检查权限,后执行的那各类其实就是一个代理类,修改后的代码如下:

publicinterfaceAction

{

       publicvoiddoAction();

}

  首先是设计一个接口,用来满足依赖颠倒原则。

PublicclassViewActionimplementsAction

{

       publicvoiddoAction()

       {

              //做View的动作

             System.out.println(“Youcouldviewtheinformation……”);

             ……

}

}

   这个类跟火车站一样,是动作的真实执行者。

PublicclassProxyViewActionimplementsAction

{

       privateActionaction=newViewAction();

       publicvoiddoAction()

       {

              //调用权限类的方法取得用户权限

             if(Permission.getPermission(userId).equals(Constants.VIEW))

              {

                    action.doAction();

}

}

}

   这是代理类,很容易理解。

在我们的ProxyViewAction类中,除了做了客户真正想要做的动作:

doAction()以外,还进行了额外的动作检查用户的权限。

而作核心动作doAction()是在一个干干净净的类:

ViewAction中进行,这个类只做核心动作,对其他的不关心,满足了单一职责原则。

   客户端通过调用代理类来执行动作,而代理类一是将权限判断和动作的执行分离开来,满足了单一职责原则;二是实现了一个接口,从而满足了依赖颠倒原则。

比第一个思路好了很多。

   代理又被称为委派,说的是代理类并不真正的执行那个核心动作,而是委派给另外一个类去执行,如ProxyView类中,ProxyView类并没有真正执行doAction()方法,而是交给ViewAction类去执行。

   我们再来看代理类ProxyViewAction,可以看到它不仅依赖于接口Action,而且依赖于具体的实现ViewAction。

这样对我们的系统扩展很不利,比如我们有Add动作、Delete动作、Modify动作等等,我们需要对每一个动作都写一个代理类,而这些代理类都做同样的事情,先进行权限判断,然后再委派。

所以我们需要对这些代理再进行一次抽象,让它只依赖接口Action,而不依赖于具体的实现。

   要实现这样的想法,我们需要将代理类中的具体实现提走,让代理的使用者在运行期提供具体的实现类,即所谓的依赖注入,如下:

PublicclassProxyActionimplementsAction

{

       privateActionaction;

       publicProxyAction(Actionaction)

       {

             this.action=action;

}

       publicvoiddoAction()

       {

              //调用权限类的方法取得用户权限

             if(Permission.getPermission(userId).equals(action.getClass().getName()))

              {

                    action.doAction();

}

}

}

   这样,我们就将所有实现了Action接口的实现使用一个代理类来代理它们。

除了ViewAction类能用,以后扩展的AddAction、      ModifyAction、DeleteAction类等等,都可以使用一个代理类:

ProxyAction。

   而我们的客户端类似如下:

Actionaction=ProxyAction(newViewAction);

Action.doAction();

   通过对代理类的依赖注入,我们使得代理类初步有了一定扩展性。

但是我们还要看到,这个代理类依赖于某一个确定的接口。

这仍然不能满足我们的实际要求,如我们的系统的权限控制一般是整个系统级的,这样系统级的权限控制,我们很难在整个系统里抽象出一个统一的接口,可能会有多个接口,按照上面的代理模式,我们需要对每一个接口写一个代理类,同样,这些类的功能都是一样的。

这显然不是一个好地解决办法。

   基于上面的原因,我们需要解决一个系统在没有统一的接口的情况下,对一些零散的对象的某一些动作使用代理模式的问题。

JAVAAPI为我们引入了动态代理或动态委派的技术。

   动态代理的核心是InvocationHandler接口,要使用动态代理就必须实现该接口。

这个接口的委派任务是在invoke(Objectproxy,Methodm,Object[]args)方法里面实现的:

//在调用核心功能之前作一些动作

……

//调用核心功能

m.invoke(obj,args);

//在调用核心功能以后做一些动作

……

   我们可以看到动态代理其实用的是反射机制来调用核心功能的:

m.invoke(obj,args);正是这种反射机制的使用使得我们调用核心功能更加灵活,而不用依赖于某一个具体的接口,而是依赖于Object对象。

   下面我们来具体看看动态代理或动态委派如何使用:

publicclassProxyActionimplementsInvocationHandler{

privateObjectaction;

publicProxyAction(Objectaction)

{

      this.action=action;

}

publicstaticObjectgetInstance(Objectaction)

{

       returnProxy.newProxyInstance(action.getClass().getClassLoader(),

action.getClass().getInterfaces(),newProxyAction(action));

}

 

publicObjectinvoke(Objectproxy,Methodm,Object[]args)

             throwsThrowable{

       

       Objectresult;

 

      try{

                   //在委派之前作动作,如权限判断等

          System.out.println("beforemethod"+m.getName());

                    //进行委派

          result=m.invoke(action,args);

 

      }catch(InvocationTargetExceptione){

 

          throwe.getTargetException();

 

      }catch(Exceptione){

 

          thrownewRuntimeException("unexpectedinvocationexception:

"

 

                 +e.getMessage());

 

      }finally{

                    //在委派之后做动作

          System.out.println("aftermethod"+m.getName());

 

      }

 

      returnresult;

 

 

}

 

}

 

   这个代理类,首先是实现了InvocationHandler接口;然后在getInstance()方法里得到了代理类的实例;在invoke()方法里实现代理功能,也很简单。

   下面我们来看客户端:

Actionaction=(Action)ProxyAction.getInstance(newViewAction());

Action.doAction();

   我们可以看到代理类对接口的依赖也转移到了客户端上,这样,代理类不依赖于某个接口。

对于同样的代理类ProxyAction,我们也可以有如下的客户端调用:

Engineengine=(Engine)ProxyAction.getInstance(newEngineImpl());

Engine.execute();

   只要engineImpl类实现了Engine接口,就可以像上面那样使用。

   现在我们可以看到,动态代理的确是拥有相当的灵活性。

但我们同时也看到了,这个代理类写起来比较麻烦,而且也差不多每次都写这样千篇一律的东西,只有委派前的动作和委派后的动作在不同的代理里有着不同,其他的东西都需要照写。

如果这样的代理类写多了,也会有一些冗余代理。

需要我们进一步优化,这里我们使用模板方法模式来对这个代理类进行优化,如下:

publicabstractclassBaseProxyimplementsInvocationHandler{

privateObjectobj;

protectedBaseProxy(Objectobj)

{

      this.obj=obj;

}

publicstaticObjectgetInstance(Objectobj,InvocationHandlerinstance)

{

       returnProxy.newProxyInstance(obj.getClass().getClassLoader(),

obj.getClass().getInterfaces(),instance);

}

 

publicObjectinvoke(Objectproxy,Methodm,Object[]args)

             throwsThrowable{

       //TODOAuto-generatedmethodstub

       Objectresult;

 

      try{

 

          System.out.println("beforemethod"+m.getName());

          this.doBegin();

 

          result=m.invoke(obj,args);

 

      }catch(InvocationTargetExceptione){

 

          throwe.getTargetException();

 

      }catch(Exceptione){

 

          thrownewRuntimeException("unexpectedinvocationexception:

"

 

                 +e.getMessage());

 

      }finally{

 

          System.out.println("aftermethod"+m.getName());

          this.doAfter();

 

      }

 

      returnresult;

 

 

}

publicabstractvoiddoBegin();

publicabstractvoiddoAfter();

 

}

   这样,代理的实现类只需要关注实现委派前的动作和委派后的动作就行,如下:

publicclassProxyImplextendsBaseProxy{

protectedProxyImpl(Objecto)

{

      super(o);

}

publicstaticObjectgetInstance(Objectfoo)

{

       returngetInstanc

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2