原创作者: chinajavawolf   阅读:950次   评论:0条   更新时间:2011-05-26    
本人翻译目的是用来学习Tapestry5的,共享出来希望大家批评指正。计划持续翻译。
chinajavawolf  
Tapestry IoC 模块
你通过提供一个模块构建器类通知Tapestry关于你的服务和贡献。
 
这个模块构建器是一个简单Java类。一个标注系统和命名约定允许Tapestry决定什么服务被这个模块提供。
 
一个模块构建器定义构建器方法,一个被模块提供给每个服务的方法。
 
服务构建器方法是公用方法。它们通常是静态的。这是一个普通例子:
 
  1. package org.example.myapp.services;   
  2.     
  3. public class MyAppModule   
  4. {   
  5.  public static Indexer build()   
  6.  {   
  7.     return new IndexerImpl();   
  8.  }   
  9. }   
 
任何名字以“build”开头的公用方法(静态或实例)是一个服务构建器方法,在模块内隐含定义了一个服务。
 
这里我们定义一个服务在Indexer服务接口的周围(大概也在org.example.myapp.services包里)。
 
每个服务都有一个唯一的id,用来在整个服务注册库(Registry)内标识它(这个Registry是来自所有模块的所有服务的集合)。如果你不能提供一个明确的服务id,象在这个例子里一样,这个服务id从返回类型提取:这个服务有一个id是“Indexer”。
 
你能够给服务一个明确的id通过添加它到方法名:buildIndexer()。这是有益的,当你不想服务id匹配这个服务接口名(例如,当你有实现同一接口的不同服务时)时,或者当你需要避免方法名冲突时(Java 只允许一个唯一的方法使用一个给定的名字和设置的参数,即使返回类型是不同的,因此如果你有两个不同的服务构建器方法使用同样的参数,你应该给他们明确的服务ids在同一方法名内)。
 
Tapestry IoC是不区分大小写的;稍后我们可以使用“indexer”或“INDEXER”或任何其中的一种变化来查阅这个服务。
 
服务的ids必需是唯一的;如果另一个模块也贡献一个id为“Indexer”(或任何一种变形)的服务,当注册库被创建时一个运行时异常将发生。
 
我们能够扩展这个例子通过增加额外的服务构建器方法,或者通过显示注入依赖。更详细的看这个服务文档
Autobuilding 服务
一个替代方法,并且通常是首选的方法,该方法是经由模块的bind()方法定义一个服务。先前的例子可以被重写成这样:
  1. package org.example.myapp.services;   
  2.     
  3. import org.apache.tapestry.ioc.ServiceBinder;   
  4.     
  5. public class MyAppModule   
  6. {   
  7.  public static void bind(ServiceBinder binder)   
  8.  {   
  9.      binder.bind(Indexer.class, IndexerImpl.class);   
  10.  }   
  11. }   
The service documentation goes into much greater detail about autobuilding of services. In most cases, autobuilding is the preferred approach.
这个服务文档对于autobuilding服务更深入更详细。在大多数情形下,autobuilding是首选方法。
 
Cacheing 服务
 
你将经常发现你自己多次的注入相同服务在你的服务构建器或服务装饰方法上。这可能是相当多余的键入。少的代码就是好的代码,只要一个选择,你可以定义一个构造器给你的模块以接收标注的参数(与使用服务构建器注入一样)。
 
这给你一个机会去存储共同的服务在实例变量里,为稍后在服务构建器方法中使用。
 
  1. public class MyModule   
  2. {      
  3.  private final JobScheduler _scheduler;   
  4.  private final FileSystem _fileSystem;   
  5.     
  6.  public MyModule(JobScheduler scheduler, FileSystem fileSystem)   
  7.  {   
  8.     _scheduler = scheduler;   
  9.     _fileSystem = fileSystem;   
  10.  }   
  11.     
  12.  public Indexer build()   
  13.  {   
  14.     IndexerImpl indexer = new IndexerImpl(_fileSystem);   
  15.          
  16.     _scheduler.scheduleDailyJob(indexer);   
  17.          
  18.     return indexer;   
  19.  }   
  20. }   
 
注意我们已经从静态方法转变到实例方法。因为builder方法不是静态的,MyModule类将被实例化以此来调用这个方法。这个构造器接收两个普通的依赖,他们被存储在实例字段域内可以稍后被用在服务构建器方法buildIndexer()内。
 
这种方法不是必需的,如果你愿意所有你的模块的builder方法都可以是静态的。当你有很多普通的依赖并且希望消除作为给多个模块参数所定义的那些依赖时它被使用。
 
Tapestry IoC自动解决参数类型(例子中的,JobScheduler和FileSystem)对应的实现那个类型的服务。当有不少于一个实现这个服务接口的服务时,你将得到一个错误(但是附加的标注河配置可以被用来确保正确的服务被注入)。
 
对于模块,有两个可以被提供给这个模块实例的附加参数类型被用来查阅资源(优于注入服务)。
 
1.       org.apache.commons.logging.Log:日志对于模块(来自这个模块的类名)。
2.          ObjectLocator:访问其他服务。
 
注意,那个这段域是final的:这很重要。Tapestry IoC是线程安全的,你基本上不用考虑并发问题。但在一个繁忙的应用中,不同的服务可能被不同的线程在同时创建。每个模块构建器类最多被实例化一次,并且这些字段域为final,以保证他们的值可以有效的在多个线程内穿越。可以查阅Brian GoetzJava并发实践,有较完整的关于final字段域,构造器和线程之间关系的探究... 或者就信任我们!
 
应该注意这种方法:在一些情况下,你可以强制这样一种情形,即这个模块的构造器依赖自身。例如,如果你调用一个方法在任何注入的服务上,该服务是定义在来自这个模块构建器的构造器的同一模块内部的服务,那么这个服务的实现将是必需的。
 
Tapestry发现这些情况然后抛出一个运行时异常以防止死循环。
 
自动加载模块
 
当设置注册库时,Tapestry可以自动查找打包在JARs内的模块。这么做是通过搜索一个明确目标的清单(manifest)条目。
 
这个清单的条目名是“Tapestry-Module-Classes”。这个值是一个逗号分隔的模块构建器类的完整类名列表(这允许一个单独的JAR可以包含多个相关的模块)。忽略空格。
 
例如:
  1. Manifest-Version: 1.0  
  2. Tapestry-Module-Classes:org.example.mylib.LibModule, org.example.mylib.internal.InternalModule   
  3.     
如果你使用Maven2,那么获得这些你的JAR的清单条目和配置在你的pom.xml中一样简单。
 
  1. <project>   
  2.  . . .   
  3.  <build>   
  4.     <plugins>   
  5.       <plugin>   
  6.         <groupId>org.apache.maven.plugins</groupId>   
  7.         <artifactId>maven-jar-plugin</artifactId>   
  8.         <configuration>   
  9.           <archive>   
  10.             <manifestEntries>   
  11.               <Tapestry-Module-Classes>org.example.mylib.LibModule,    
  12.                 org.example.mylib.internal.InternalModule</Tapestry-Module-Classes>   
  13.             </manifestEntries>   
  14.           </archive>   
  15.         </configuration>   
  16.       </plugin>   
  17.     </plugins>   
  18.  </build>   
  19.  . . .   
  20. </project>   
 
更详细的内容在Maven Manifest指南内提供。
 
SubModule 标注
 
通常你会需要几个不同的模块一起工作,那么你应该作为一个整体加载他们。
 
办法之一是更新这个清单中的模块ids,表现为先前的扩展。
 
事实上重新做时,这将变得冗长乏味,并且极其脆弱(比如,类或包的重命名)。
 
一个好的替代方法是@SubModule标注
 
这个标住的值是被加工为模块构建器类的附加类的列表,完全就像他们被定义在清单内一样。
 
例如:
  1. @SubModule(   
  2. { InternalTransformModule.class })   
  3. public final class InternalModule   
  4. {   
  5.  . . .  
 
通常,你应该只需要定义一个单独模块在JAR清单内,并且使用@SubModule添加任何附加的模块构建器类。
 
模块构建器实现注意
 
模块构建器类被设计成非常非常简单的实现。
 
另外,保持方法非常简单。使用参数注入获得你需要的依赖的访问。
 
小心继承。Tapestry将留意所有public方法,即使这些方法继承基类。Tapestry眼中只有public方法。
 
通过约定,模块构建器类的名字为模块名和final类名构成。
 
你不用必需定义你的方法为静态的。使用静态方法只是在少数情况是绝对必需的,当构造器是依赖来自同一模块的贡献时(这将引起先有鸡还是先有蛋的争论(chicken-and-egg)情形,通过静态方法将彻底避免)
评论 共 0 条 请登录后发表评论

发表评论

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

文章信息

Global site tag (gtag.js) - Google Analytics