原创作者: chinajavawolf   阅读:888次   评论:0条   更新时间:2011-05-26    
本人翻译目的是用来学习Tapestry5的,共享出来希望大家批评指正。计划持续翻译。
chinajavawolf  
Tapestry IoC 装饰器
 
装饰是一个非常流行的设计模式的名字。使用装饰,一个现有对象的行为可以被扩展而不需要改变对象的实现。
 
代替的是,一个新的对象被放置在现有对象的周围。所有其他的都能看到这个新对象,术语称为拦截器。这个拦截器实现了与被装饰的根基(underlying)对象同样的接口。
 
一个共通的例子是Java I/O库。抽象的InputStream基类有一个非常简单的API用来从流中读字节(和一些其他内容)。InputStream的子类提供了广泛的选择,比如缓存,加密或解密,连同对通过流读到的数据来源的控制。所有这些涉及到的都被装入到不同的InputStream实现中了,并且所有可以被连接一起在在一种管道内的,使用共同的InputStream API。
 
Tapestry IoC使用一个类似的方法,一个或更多个拦截器对象,所有都实现服务接口,串接在一起。这个服务的代理(负责即时深产服务实现的实例)是在管道的末端,核心服务实现在另一个上。
 
对于服务接口中的每一个方法,拦截器对象可以执行某些操作在核心服务实现上的同一方法重新调用之前或之后。这是另一个设计模式:委托模式(delegation)。一个拦截器可以捕获根基(underlying)实现抛出的异常然后对他们作出反应。一个非常聪明的拦截器可以在抛出异常时重新尝试一个方法,或者可以“缓和”一个检查的异常通过包裹它在一个运行时异常内。
 
装饰器经常被用在横切关系的上下文内,比如l日志或事务管理。这个方法是一种切面导向设计。
 
这一种横切关系是延迟初始化的服务。在HiveMind中,服务仅在需要时被创建,当一个服务接口的方法被第一次调用时。这个关系通过Tapestry IoC框架自身被支持,但类似的关系容易实现为装饰器。
 
鉴于流行的AspectJ框架改变你类的编译字节码(称为过程“织入”),通过Tapestry IoC,这个方法包裹你现有的代码在新对象中。这些包裹的对象经常在运行时被动态的创建。
 
在一个单独得服务上有多个装饰器也是很普通的。在这种情况下,拦截器对象的整个堆栈将被创建,每个都委派给下一个。Tapestry IoC提供装饰器发生的控制顺序。
 
装饰通过服务装饰方法被控制。通常,一个可再用的服务存在的日常工作是创建和实例化一个新对象。
 
服务装饰方法
 
  1. package org.example.myapp.services;   
  2.     
  3. import org.apache.tapestry.ioc.services.LoggingDecorator;   
  4.     
  5. public class MyAppModule   
  6. {   
  7.  public static Indexer build()   
  8.  {   
  9.     return new IndexerImpl();   
  10.  }   
  11.     
  12.  public static <T> T decorateIndexer(Class<T> serviceInterface, T delegate,    
  13.     String serviceId, Log serviceLog,   
  14.        
  15.     @InjectService("LoggingDecorator")   
  16.     LoggingDecorator decorator)   
  17.  {   
  18.     return decorator.build(serviceInterface, delegate, serviceId, serviceLog);   
  19.  }    
  20. }   
 
decorateIndexer()方法是一个服务装饰器方法因为它以单词“decorate”开头。在这个简单的案例中,只用myapp.Indexer服务将被装饰,即使如果有其他服务在这个模块或其他的当中。这是因为名称匹配("decorateIndexer" 和 "buildIndexer"),但我们将很快看到标注如何可以被用来为装饰定位很多服务。
 
这里我们使用参数化类型(<T>),以加强委派对象传递在(那将是核心服务实现,或某些其他拦截器)必须实现的服务接口内,并且那个装饰器方法必须返回该服务接口实例的行为。
 
可以被提供给装饰器方法的值与给构造器方法的完全一样,增加一个:根基服务将被传递在内作为一个java.lang.Object类型对象。为了这个目的,一个装饰器方法必须有一个java.lang.Object类型参数。
 
在上面的例子中,装饰器方法接收核心服务实现,service接口为Indexer服务,Log接口为Indexer服务,然后一个拦截器工厂产生日志拦截器。
 
“heavy lifting”通过工厂被提供,将创建一个新的拦截器在委派给核心服务实现之前记录方法进入。这个拦截器也将记录方法参数,返回值,甚至记录异常。
 
方法返回值是一个新的拦截器。你可以返回null如果你的装饰器方法决定不再装饰这个提供的服务。
 
当然,绝不阻止你从结合building与decorating在服务构建器方法内。
  1. package org.example.myapp.services;   
  2.     
  3. import org.apache.tapestry.ioc.services.LoggingDecorator;   
  4.     
  5. public class MyAppModule   
  6. {   
  7.  public static Indexer build(Class serviceInterface, Log serviceLog,   
  8.     @InjectService("LoggingDecorator")   
  9.     LoggingInterceptorFactory decorator)   
  10.  {   
  11.     return decorator.build(serviceInterface, serviceLog, new IndexerImpl());   
  12.  }    
  13. }   
 
但是我们也将看到,它可能有一个单独的装饰器方法通过使用标注工作在很多不同服务上。
 
确定Targetting Multiple Services
 
通过使用@Match标注,你可以标识哪个服务被装饰。
 
指定在Match标注内的值是一个或多个样式。这些样式被用来匹配服务。在一个样式内,一个"*"在一个字符串开头或末尾匹配零或多个字符。
 
例如,瞄准所有在你模块中的服务。
 
  1. @Match("*")   
  2. public static <T> T decorateLogging(Class<T> serviceInterface, T delegate,    
  3.    String serviceId, Log serviceLog,   
  4.    @InjectService("LoggingDecorator")   
  5.    LoggingDecorator decorator)   
  6. {   
  7.    return decorator.build(serviceInterface, delegate, serviceId, serviceLog);   
  8. }    
 
你可以通过@Match使用多个样式,在一个方案内,装饰器将被应用给任何匹配样式的服务。例如,如果你只想为你的数据访问和业务逻辑服务进行记录。你应该用@Match("Data*", "*Logic")(当然,这都基于你如何命名你的服务了)
 
就像例子中显示的,一个简单的“块”匹配被支持,可以使用一个星号('*')在匹配的字符串开头或末尾以匹配多个字符,忽略大小写差异。
 
因而,@Match(*)是危险的,因为它将匹配你所有模块中所有服务。
 
注:它不会装饰TapestryIOCModule服务。
 
注:另外一个匹配服务的方法: 基于服务接口的继承或基于现场的标注在这个服务接口上的特殊类。这一点没有实现,但可轻易完成在装饰方法内(如果它决定该服务不需要装饰将返回null)
 
装饰器排序
 
万一有多个装饰器应用在一个单独的服务上,你可以在装饰器上应用附加的标注@Order来控制顺序。
 
这个标注允许对装饰器指定多个顺序约束,相对其它装饰器的顺序。
 
例如,你总是希望第一个应用的是日志装饰器,所以:
 
 
  1. @Match("*")   
  2.  @Order("before:*")   
  3.  public static <T> T decorateLogging(Class<T> serviceInterface, T delegate,    
  4.     String serviceId, Log serviceLog,   
  5.     @InjectService("LoggingDecorator")   
  6.     LoggingDecorator decorator)   
  7.  {   
  8.     return decorator.build(serviceInterface, delegate, serviceId, serviceLog);   
  9.  }      
 
"before:*"指出这个装饰器应该在任何模块的任何装饰器之前出现。
 
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

文章信息

Global site tag (gtag.js) - Google Analytics