[weld] bean的生存空间
wuhaixing
2010-04-05
bean的生存空间决定了他的寿命。生存空间还决定了使用者引用的是哪个bean实例。依据CDI规范的定义,scope能决定的是:
(在bean 的世界里,房子不仅决定了bean能活多久,还决定了要嫁给谁。我猜,在那个世界的房价肯定会更高吧!) 比如说,有一个叫CurrentUser的bean住在session scope中,那在相同HttpSession的context中的bean都只认识一个CurrentUser的实例。当这个session中第一次有人需要CurrentUser的时候,container就会创建一个实例放在这个session对应的scope中;当session结束的时候,这个实例也随之消亡。 JPA 实例在这个模型中会觉得不太舒服,因为Entities有自己的生命周期和识别方式,而这些方式和CDI中的方式不是很配。因此,别像对待CDI bean那么对待entities,如果你把entity放在@Dependent之外的scope中,你肯定会遇到麻烦的。如果你要把一个注入的实例交给JPA EntityManager,client proxy会跳起来反对你的。 |
|
wuhaixing
2010-04-05
户型
CDI中的context 模型是可扩展的,创建自己的scope type不是不可能的。首先先创建一个新的scope type annotation: @ScopeType @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface ClusterScoped {} 当然,这是最容易的一步。要让ClusterScoped不是个空架子,还需要定义一个Context对象来实现这个scope所需的功能。这可是个技术活,非常考验功力,要是你还不是框架开发级别的牛人,请勿轻易尝试。在seam以后的版本中,你可能会见到一个叫做business scope的这么个玩意。 可以把scope type annotation放到类前面表明他是住在哪种scope中的bean: @ClusterScoped public class SecondLevelCache { ... } |
|
wuhaixing
2010-04-05
上天安排的scope
CDI 规定了container必须提供的四种scope:
对于使用了CDI的web应用程序:
要在其他的web框架中支持conversation scope,可以创建一个 CDI extension。 request和application scope在下面各种情况下也会处于活动状态:
当应用程序试图访问一个bean时,如果该bean所在的scope没有处于非活动状态的context,container会抛出一个 ContextNotActiveException。 标记为@SessionScoped 或 @ConversationScoped的Managed beans必须是 serializable的,因为container 会一次又一次的 挂起 HTTP session。 |
|
wuhaixing
2010-04-05
conversation scope
其他的三种scope应该是广大的web开发者很容易理解的概念,接下来介绍新出场的conversation scope。 conversation scope 有点像session scope,跨越多个请求保存用户与系统之间的交互状态。与session scope不同的是,conversation scope:
conversation代表一个任务--从用户角度来看是一项完整的工作。conversation context保存用户当前的工作信息。如果用户同时做很多事情,就会有很多conversation。 conversation context在任何JSF 请求中都处于活动状态。大多数conversation在请求结束的时候终止。如果希望conversation能够继续,必须将其提升为long-running conversation。 |
|
wuhaixing
2010-04-05
conversation的界定
在JSF程序中,可以用CDI提供的bean来控制conversation的生命周期。这个bean可以通过注入引用: @Inject Conversation conversation; 要将与当前request关联的conversation提升为long-running conversation,在代码中调用begin()方法,要在当前的request结束时将当前的long-running conversation销毁,调用end()方法。 下面这个例子演示了conversation-scoped的bean如何控制其所在的conversation: @ConversationScoped @Stateful public class OrderBuilder { private Order order; private @Inject Conversation conversation; private @PersistenceContext(type = EXTENDED) EntityManager em; @Produces public Order getOrder() { return order; } public Order createOrder() { order = new Order(); conversation.begin(); return order; } public void addLineItem(Product product, int quantity) { order.add(new LineItem(product, quantity)); } public void saveOrder(Order order) { em.persist(order); conversation.end(); } @Remove public void destroy() {} } 通过使用Conversation API,这个bean能控制自己的生命周期。但有些bean的生命周期完全取决于其他对象。 Conversation传播 任何JSF faces请求(JSF form提交)或redirect 都会自动传播Conversation context。而non-faces请求则不会自动传播,比如,通过链接导航。 将conversation的唯一标识作为request参数可以强制non-faces请求传播conversation。CDI规范将cid作为传播conversation唯一指定request参数名称。conversation的标识可以通过Conversation对象获取,其EL bean名称为conversation。 因此下面的链接会传播conversation: <a href="/addProduct.jsp?cid=#{conversation.id}">Add Product</a> 用JSF 2的link组件可能会更好: <h:link outcome="/addProduct.xhtml value="Add Product"> <f:param name="cid" value="#{conversation.id}"/> </h:link> conversation context能够在跨越redirect传播,因此很容易实现常用的 POST-then-redirect模式,而无需用那些脆弱的方式,比如“flash”对象。container会自动将conversation id作为request参数加到redirect的URL中。 conversation超时 为了节约资源,允许container随时销毁conversation及其保存的状态信息。虽然规范没有要求,CDI的实现通常会引入某种超时机制。当conversation超过一定的时间没有活动时,container就会销毁他。 Conversation对象提供了设置超时时间的方法,这个设置是对container的提示,可以忽略。 conversation.setTimeout(timeoutInMillis); |
|
wuhaixing
2010-04-06
伪空间Singleton
除了4个内置的scope,CDI还提供了两个伪空间。首先出场的是singleton,用@Singleton标明。 @Singleton在 javax.inject 包内,而不像其他scope一样在 javax.enterprise.context包内。 你应该能猜到“singleton”在这里的含义,被标记的bean只会被初始化一次。可这会有个小问题,带有@Singleton标记的bean没有代理,使用者持有的是这个单例实例的直接引用。所以我们得考虑使用者被串行化的情况,比如标记了@SessionScoped 或 @ConversationScoped的bean,或者引用了 @SessionScoped 或@ConversationScoped的bean,或者statuful session bean。 当然,如果这个单例实例是个简单的,不可变的,可串行化的对象,比如string、数字或日期,我们可能还不会那么在意,因为他被串行化仅仅是导致出现重复的实例。如果会使得他不再是真正的Singleton,还不如将他放到默认的scope中。 下面有几种方法可以确保Singleton的bean跟着其使用者一起被串行化后还能保持Singleton的方法:
最后一种办法,也是最好的办法就是不用他,用@ApplicationScoped,container就会让你通过proxy访问bean,并为你解决串行化的问题。 |
|
wuhaixing
2010-04-06
伪空间dependent
终于轮到CDI提供的伪空间dependent了,他是没有显式声明所属scope的bean的默认scope。 比如下面这个bean的scope类型就是 @Dependent: public class Calculator { ... } dependent bean的实例不会由不同的使用者或注入点共享。他的对于绝对依赖于其他对象。随其所属对象的创建而创建,随其所属对象的销毁而销毁。 如果dependent bean在EL表达式中引用,则每次计算这个表达式时都会创建这个bean的实例。这个实例不会在计算任何其他表达式时重用。 如果你需要在JSF页面中通过EL 名称直接访问bean,通常不能将其标记为@Dependent。否则任何通过JSF输入而赋给他的值会立即丢失。因此CDI提供了@Model,可以给bean一个名称,并且相当于同时标记为@RequestScoped。如果你确实需要在JSF页面中访问一个@Dependent的bean,把他注入到另外一个bean中,然后通过getter方法提供给EL。 标记为@Dependent的 Beans 不需要代理对象,其使用者是直接引用他的。 |
|
wuhaixing
2010-04-06
修饰符@New
内置的修饰符@New允许我们获取bean的dependent对象,即使这个bean被标记为其他的scope。这也是CDI给我们提供的又一个便利。 @Inject @New Calculator calculator; 这个类必须是一个有效的managed bean或session bean,但不需要是被启用的bean。 Calculator可以被标记为不同的空间类型,比如: @ConversationScoped public class Calculator { ... } 因此下面这个注入的属性每次都会得到一个不同的Calculator实例: public class PaymentCalc { @Inject Calculator calculator; @Inject @New Calculator newCalculator; } calculator属性注入的是一个conversation-scoped的Calculator实例,而newCalculator属性注入的则是一个新的Calculator实例,其生命周期绑定到其所属的PaymentCalc上。 这个特性对于producer方法尤其有用。 |
相关讨论
相关资源推荐
- jEdit 源码解析之:纯文本编辑器 JEditTextArea 初探
- vscode代码编辑框控件_VS Code、ATOM这些开源文本编辑器的代码实现中有哪些奇技淫巧?...
- linux 自带html编辑器,7个Linux和Ubuntu下的免费CSS编辑器_html/css_WEB-ITnose
- 面向程序员的文本编辑器jEdit第5版发布,支持Scala和Dart
- windows linux 代码编辑器,让 medit 成为你的下一个 Linux 代码编辑器
- linux 代码编辑编译器,安利一款很棒的Linux代码编辑器
- jEdit应用指南【基础篇】
- linux css 工具,Ubuntu/linux 下的8款经典免费的CSS编辑器整理
- linux ubuntu 免费,7个Linux和Ubuntu下的免费CSS编辑器
- Java程序员最喜欢的11款免费IDE编辑器