




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
-.z.package.bjs**y;importjava.util.Random;publicclassTankimplementsMoveable{Overridepublicvoidmove(){ System.out.println("TankMoving...");try{ Thread.sleep(newRandom().ne*tInt(10000));//说明tank正在移动中 }catch(InterruptedE*ceptione){ e.printStackTrace(); } }}想知道看此段代码运行了多长时间。方法里面运行的时间。一个类里面有另外一个类的对象,这叫做聚合一个用继承实现此功能,一个用聚合实现此功能。聚合好,继承不灵活记录日志、记录时间、记录权限的控制用继承的方式会无限制的迭加下去。类爆炸现象!!!代理之间互相的组合!因为共同实现的是Movable接口!!关键是实现同一接口!这是静态代理!先日志、后时间还是先时时间,还是日志代理的类根据需求还可能无限膨胀下去。动态代理解决类太多的问题!实现动态的编译:/JDK6plierAPI,CGLib,ASM代理的总代理深入java虚拟机----二进制代码的实现。被代理的类都实现了一种结果!!继承也能实现,但是不推荐使用!!1实现package.bjs*t.piler.test;importjava.io.File;importjava.io.FileWriter;importjava.lang.reflect.Constructor;.URL;.URLClassLoader;importjava*.tools.Javapiler;importjava*.tools.StandardJavaFileManager;importjava*.tools.ToolProvider;importjava*.tools.Javapiler.pilationTask;import.bjs**y.Moveable;import.bjs**y.Tank;publicclassTest1{ publicstaticvoidmain(String[]args)throwsE*ception{ Stringrt="\r\n"; Stringsrc= "package.bjs**y;"+rt+ "publicclassTankTimePro*yimplementsMoveable{"+rt+ "publicTankTimePro*y(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\Pro*y StringfileName=System.getProperty("user.dir") +"/src//bjs*t/pro*y/TankTimePro*y.java"; Filef=newFile(fileName); FileWriterfw=newFileWriter(f); fw.write(src); fw.flush(); fw.close(); //pile Javapilerpiler=ToolProvider.getSystemJavapiler(); System.out.println(piler.getClass().getName());//.sun.tools.javac.api.JavacTool StandardJavaFileManagerfileMgr=piler.getStandardFileManager(null,null,null); Iterableunits=fileMgr.getJavaFileObjects(fileName); pilationTaskt=piler.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(".bjs**y.TankTimePro*y"); System.out.println(c);//class.bjs**y.TankTimePro*y 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……〞);
……}}
这个类跟火车站一样,是动作的真实执行者。PublicclassPro*yViewActionimplementsAction{
privateActionaction=newViewAction();
publicvoiddoAction()
{
//调用权限类的方法取得用户权限
if(Permission.getPermission(userId).equals(Constants.VIEW))
{
action.doAction();}}}
这是代理类,很容易理解。在我们的Pro*yViewAction类中,除了做了客户真正想要做的动作:doAction()以外,还进展了额外的动作检查用户的权限。而作核心动作doAction()是在一个干干净净的类:ViewAction中进展,这个类只做核心动作,对其他的不关心,满足了单一职责原则。
客户端通过调用代理类来执行动作,而代理类一是将权限判断和动作的执行别离开来,满足了单一职责原则;二是实现了一个接口,从而满足了依赖颠倒原则。比第一个思路好了很多。
代理又被称为委派,说的是代理类并不真正的执行那个核心动作,而是委派给另外一个类去执行,如Pro*yView类中,Pro*yView类并没有真正执行doAction()方法,而是交给ViewAction类去执行。
我们再来看代理类Pro*yViewAction,可以看到它不仅依赖于接口Action,而且依赖于具体的实现ViewAction。这样对我们的系统扩展很不利,比方我们有Add动作、Delete动作、Modify动作等等,我们需要对每一个动作都写一个代理类,而这些代理类都做同样的事情,先进展权限判断,然后再委派。所以我们需要对这些代理再进展一次抽象,让它只依赖接口Action,而不依赖于具体的实现。
要实现这样的想法,我们需要将代理类中的具体实现提走,让代理的使用者在运行期提供具体的实现类,即所谓的依赖注入,如下:PublicclassPro*yActionimplementsAction{
privateActionaction;
publicPro*yAction(Actionaction)
{
this.action=action;}
publicvoiddoAction()
{
//调用权限类的方法取得用户权限
if(Permission.getPermission(userId).equals(action.getClass().getName()))
{
action.doAction();}}}
这样,我们就将所有实现了Action接口的实现使用一个代理类来代理它们。除了ViewAction类能用,以后扩展的AddAction、
ModifyAction、DeleteAction类等等,都可以使用一个代理类:Pro*yAction。
而我们的客户端类似如下:Actionaction=Pro*yAction(newViewAction);Action.doAction();
通过对代理类的依赖注入,我们使得代理类初步有了一定扩展性。但是我们还要看到,这个代理类依赖于*一个确定的接口。这仍然不能满足我们的实际要求,如我们的系统的权限控制一般是整个系统级的,这样系统级的权限控制,我们很难在整个系统里抽象出一个统一的接口,可能会有多个接口,按照上面的代理模式,我们需要对每一个接口写一个代理类,同样,这些类的功能都是一样的。这显然不是一个好地解决方法。
基于上面的原因,我们需要解决一个系统在没有统一的接口的情况下,对一些零散的对象的*一些动作使用代理模式的问题。JAVAAPI为我们引入了动态代理或动态委派的技术。
动态代理的核心是InvocationHandler接口,要使用动态代理就必须实现该接口。这个接口的委派任务是在invoke(Objectpro*y,Methodm,Object[]args)方法里面实现的://在调用核心功能之前作一些动作……//调用核心功能m.invoke(obj,args);//在调用核心功能以后做一些动作……
我们可以看到动态代理其实用的是反射机制来调用核心功能的:m.invoke(obj,args);正是这种反射机制的使用使得我们调用核心功能更加灵活,而不用依赖于*一个具体的接口,而是依赖于Object对象。
下面我们来具体看看动态代理或动态委派如何使用:publicclassPro*yActionimplementsInvocationHandler{privateObjectaction;publicPro*yAction(Objectaction){
this.action=action;}publicstaticObjectgetInstance(Objectaction){
returnPro*y.newPro*yInstance(action.getClass().getClassLoader(),action.getClass().getInterfaces(),newPro*yAction(action));}publicObjectinvoke(Objectpro*y,Methodm,Object[]args)
throwsThrowable{
Objectresult;
try{
//在委派之前作动作,如权限判断等
System.out.println("beforemethod"+m.getName());
//进展委派
result=m.invoke(action,args);
}catch(InvocationTargetE*ceptione){
throwe.getTargetE*ception();
}catch(E*ceptione){
thrownewRuntimeE*ception("une*pectedinvocatione*ception:"
+e.getMessage());
}finally{
//在委派之后做动作
System.out.println("aftermethod"+m.getName());
}
returnresult;}}
这个代理类,首先是实现了InvocationHandler接口;然后在getInstance〔〕方法里得到了代理类的实例;在invoke〔〕方法里实现代理功能,也很简单。
下面我们来看客户端:Actionaction=(Action)Pro*yAction.getInstance(newViewAction());Action.doAction();
我们可以看到代理类对接口的依赖也转移到了客户端上,这样,代理类不依赖于*个接口。对于同样的代理类Pro*yAction,我们也可以有如下的客户端调用:Engineengine=(Engine)Pro*yAction.getInstance(newEngineImpl());Engine.e*ecute();
只要engineImpl类实现了Engine接口,就可以像上面那样使用。
现在我们可以看到,动态代理确实是拥有相当的灵活性。但我们同时也看到了,这个代理类写起来比拟麻烦,而且也差不多每次都写这样千篇一律的东西,只有委派前的动作和委派后的动作在不同的代理里有着不同,其他的东西都需要照写。如果这样的代理类写多了,也会有一些冗余代理。需要我们进一步优化,这里我们使用模板方法模式来对这个代理类进展优化,如下:publicabstractclassBasePro*yimplementsInvocationHandler{privateObjectobj;protectedBasePro*y(Objectobj){
this.obj=obj;}publicstaticObjectgetInstance(Objectobj,InvocationHandlerinstance){
returnPro*y.newPro*yInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),instance);}publicObjectinvoke(Objectpro*y,Methodm,Object[]args)
throwsThrowable{
//TODOAuto-generatedmethodstub
Objectresult;
try{
System.out.println("beforemethod"+m.getName());
this.doBegin();
result=m.invoke(obj,args);
}catch(InvocationTargetE*ceptione){
throwe.getTargetE*ception();
}catch(E*ceptione){
thrownewRuntimeE*ception("une*pectedinvocatione*ception:"
+e.getMessage());
}finally{
System.out.println("aftermethod"+m.getName());
this.doAfter();
}
returnresult;}publicabstractvoiddoBegin();publicabstractvoiddoAfter();}
这样,代理的实现类只需要关注实现委派前的动作和委派后的动作就行,如下:publicclassPro*yImple*tendsBasePro*y{protectedPro*yImpl(Objecto){
super(o);}publicstaticObjectgetInstance(Objectfoo){
returngetInstance(foo,newPro*yImpl(foo));}//委派前的动作publicvoiddoBegin(){
//TODOAuto-generatedmethodstub
System.out.println("begindoing....haha");}//委派后的动作publicvoiddoAfter(){
//TODOAuto-generatedmethodstub
System.out.println("afterdoing.....yeah");}}
从上面的代码,我们可以看出代理实现类确实是简单多了,只关注了委派前和委派后的动作,这是我们作为一个代理真正需要关心的。
至此,代理模式和动态代理已经告一段落。我们将动态代理引申一点说开去,来作为这篇文章的蛇足。
这个话题就是面向方面的编程,或者说AOP。我们看上面的Pro*yImpl类,它的两个方法doBegin()和doAfter(),这是做核心动作之前和之后的两个截取段。正是这两个截取段,却是我们AOP的根底。在OOP里,doBegin(),核心动作,doAfter()这三个动作在多个类里始终在一起,但他们所要完成的逻辑却是不同的,如doBegin()可能做的是权限,在所有的类里它都做权限;而在每个类里核心动作却各不相同;doAfter()可能做的是日志,在所有的类里它都做日志。正是因为在所有的类里,doBegin()或doAfter()都做的是同样的逻辑,因此我们需要将它们提取出来,单独分析、设计和编码,这就是我们的AOP的思想。
这样说来,我们的动态代理就能作为实现AOP的根底了。好了,就说这么多,关于AOP技术,我们可以去关注关于这方面的知识。分享到:上一篇:Servlet和JSP的协调运行——通过调整Servlet和JSP来提高你的企业应用的运行性能下一篇:扩展Struts〔译文〕3三言两语话动态代理2005-09-0123:28byFantasySoft,1724visits,收藏,编辑
在之前的一篇关于Decorator模式的Post中,曾经提到了动态代理(DynamicPro*y)简化了Decorator模式的实现。作为例子的代码很容易理解,但这个简化的背后仍包含着很多值得去开掘的内容。
首先我们来明确一下动态代理的定义:一个动态代理类在运行期implements一组interface,使得interface实现类的方法调用被分派至其他的类(另外的interface实现类或者任意的类)的方法。讲得更通俗一些,要了解动态代理,我们就要知道什么东西动态了,代理了什么?首先,一个Pro*y代理了一组interface的方法。注意,代理的是interface,而不是Class,也不是abstractClass;其次,Pro*y具有的型别由绑定的interface所决定的,动态就表达在此。也许看着这样的定义,还是会一头雾水,则我们画幅图来看看吧。从图中,我们可以看到DynamicPro*y并没有实现Resource这个接口,但是包含了Resource接口实现类的实例;在DynamicPro*y的create方法中,通过调用Pro*y.newPro*yInstance创立一个Pro*y,并将该Pro*y与Resource接口绑定,最后将Pro*y显式类型转换成Resource接口类型并返回,这样调用者就可以通过Pro*y调用interface定义的方法了;由于Pro*y与Resource接口绑定了,对Resource接口的方法调用,都会交由Pro*y的invoke方法去处理。而invoke方法会根据不同的方法,或给以全新的实现,或直接将方法调用交给Pro*y中包含的Resource接口实现类的实例去处理。综合上面所说的,作为一个DynamicPro*y,它必须满足以下三个条件:
1、实现了InvocationHandler接口,实现接口中定义的invoke方法;
2、包含接口实现类的实例;
3、通过Pro*y.newPro*yInstance方法实现Pro*y与接口之间的绑定。
以下代码给出了一个简单的DynamicPro*y实现:publicinterface
Resource
{
publicvoid
operationA();
publicvoid
operationB();
}publicclass
ConcreteResource
implements
Resource
{
publicvoid
operationA()
{
System.out.println("Operation
A.");
}publicvoid
operationB()
{
System.out.println("Operation
B.");
}}publicclass
DynamicPro*y
implements
InvocationHandler
{
private
Resource
resource;
public
DynamicPro*y()
{
resource
=
new
ConcreteResource();
}public
Resource
create()
{
Resource
returnResource
=
null;
returnResource
=
(Resource)
Pro*y.newPro*yInstance(Resource.class.getClassLoader(),
new
Class[]{
Resource.class
},
this);
return
returnResource;
}public
Object
invoke(Object
obj,
Method
method,
Object[]
args)
{
Object
o
=
null;
try
{
if
(method.getName().equals("operationA"))
{
System.out.println("OperationA
in
Pro*y");
}
else
{
o
=
method.invoke(obj,
args);
}
}
catch
(E*ception
e)
{
e.printStackTrace();
}return
o;
}}publicclass
Test
{
publicstaticvoid
main(String[]
args)
{
DynamicPro*y
pro*y
=
new
DynamicPro*y();
Resource
resource
=
pro*y.create();
resource.operationA();
}}Categories:ThoughtWare,PracticalJava,AllAboutSoftAddyourment6条回复#1楼duan*p[未注册用户]2007-03-0510:45代码错了回复引用#2楼duan*p[未注册用户]2007-03-0510:51修改了一下DynamicPro*y类publicclassDynamicPro*yimplementsInvocationHandler{privateResourceresource;publicResourcecreate(){this.resource=newConcreteResource();return(Resource)Pro*y.newPro*yInstance(resource.getClass().getClassLoader(),resource.getClass().getInterfaces(),this);}publicObjectinvoke(Objectobj,Methodmethod,Object[]args)throwsThrowable{Objecto=null;try{if(method.getName().equals("operationA")){System.out.println("OperationAinPro*y");}else{o=method.invoke(resource,args);}}catch(E*ceptione){e.printStackTrace();}returno;}}HYPERLINK".blogs./perhaps/archive/2005/09/01/228302.html
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 信息安全在领导实践中的重要性试题及答案
- 采石场股份转让与环保治理一体化协议
- 仓储物流型厂房租赁安全管理与信息化协议
- 茶叶企业品牌授权及产品开发合同
- 厕所改造工程保修合同范本
- 跨境电商园区车位租赁及物流配套协议
- 2025医疗机构合同管理制度
- 集中式风电项目总体规划
- 数据湖与数据库的关系试题及答案
- 加强计算机二级ACCESS知识点与2025年试题及答案
- 可感染人类的高致病性病原微生物菌(毒)种或样本运输管理规定
- 2022年全民健康生活方式行动工作计划
- PVDF乳液与悬浮聚合工艺
- 高三物理一轮复习策略及建议.PPT
- MME 新型磨粉机设计外文文献翻译、中英文翻译、外文翻译
- 光伏发电项目并网调试方案
- 面试考核评分表
- 地沟更换管线专项施工方案完整
- 公司组织架构图模板可编辑
- 麦克维尔螺杆冷水机组维修保养手册
- 《音乐乐理常识大全》ppt课件
评论
0/150
提交评论