Seam中的两个核心概念是context(上下文思想)和component(组件)思想。组件是有状态的对象,通常是EJB,组件的实例会和上下文绑定,在此上下文中具有一个名字。Bijection(双向注入)可以将内部的组件名(实例变量名)别名为上下文相关的名字,允许seam动态组装组件树,还可以重新组装。
一. seam上下文
Stateless context | Event(request)context | Page Context | Conversation Context | Session Context | Business Process Context | Application Context |
无状态上下文 | 事件上下文 | 页面上下文 | 业务会话上下文 | Session上下文 | 业务流程上下文 | 应用上下文 |
没有状态的组件主要是(无状态session组件)都放在无状态上下文中 | 最窄的有状态上下文 与JSF请求的生命周期相关联的事件上下文是事件上下文最重要的实例 | 允许将状态与一个渲染页面的实例相关联 | 对于用户来说,一个业务回话解决一个单一问题。 可以确保不同业务会话的状态不会相互干扰 | 保存与用户登录session相关联的状态 | 保存了长时间运行的业务流程相关的状态。 可以跨多个用户的交互,在多个用户之间可以良好共享。 | 保存静态信息很有用。如配置数据等 |
二:查找上下文中的组件实例
在上下文中,通常seam组件会被绑定到 context variables(上下文变量)
在上下文中,seam组件实例是通过上下文变量名字来识别的。
1. 在特定范围内访问被命名的组件实例。
User user=(User)Contexts.getSessionContext().get(“user”);
Contexts.getSessionContext().set(“user”,users);
通常是通过注射(injection)来从上下文获得组件,并且通过反射(outjection)把组件从实例返回上下文。
2. 通过调用Contexts.lookupInStatefulContexts()来执行优先级的搜索seam组件
EJB stateless Session Bean | EJB stateful Session Bean | EJB entity beans | javaBeans |
无状态Session bean | 有状态Session bean | 实体Bean |
|
无法在多次调用之间保存状态 | 既可以在bean的多次调用之间保存状态,而且可以在多次请求之间保存状态。 |
|
|
通常在不同的seam上下文中,操作其他组件的状态 | 默认情况下,有状态Session Bean会被绑定到Conversation Context。不会绑定到page或者stateless context中 | 默认情况下,Entity Bean 被绑定到Conversation Context。永远不会绑定到无状态Context中 | 默认情况下,Java Beans 是绑定到Event Context的 |
每次请求都产生一个新的实例,可以并发访问。 | 不由数据库保存的状态通常保存在有状态的Session Bean的实例中,该实例会被保存到会话上下文中 |
|
|
可以作为JSF的action listener,但不能为JSF组件的显示提供属性 | 经常被作为JSF action listener 使用 也可以作为JSF显示或者form提交的backing bean,提供属性供组件访问 | 不作为JSF的action listener使用,经常作为JSF组件的显示或者form提交的后台bean,提供属性功能。特别是,当Entity Bean 作为后台Bean的时候,它会和一个无状态Session Bean扮演着action listener,来实现CRUD之类的功能。 |
|
可以使用Component.getInstance()或者@In(create=true)实例化 | 可以使用Component.getInstance()或者@In(create=true)实例化 不可以直接使用JNDI 或者new 操作实例化 | 可以使用Component.getInstance()或者@In(create=true)实例化 或者直接使用new 操作来实例化 | 可以使用Component.getInstance()或者@In(create=true)实例化 或者直接使用new 操作来实例化 |
必须注册EJB拦截器,可以通过注解 | 必须注册EJB拦截器,可以通过注解 | 不需要拦截,因为双向注入和上下文划分不起作用 | Seam可以完全控制组件的初始化,不需要特别配置 |
三:定义组件范围。(defining the component scope)
我们可以使用@Scope注解来覆盖默认组件范围(上下文)。这可以让我们定义组件实例被Seam初始化后绑定到具体的上下文。
STATELESS
The stateless psuedo-context.
The method context. Each call to a session bean or JavaBean component puts a new method context onto the stack of method contexts associated with the current thread. The context is destroyed (and the stack popped) when the method returns.
The event (request) context. Spans a server request, from restore view to render response.
The page context. Begins during the invoke application phase prior to rendering a page, and lasts until the end of any invoke application phase of a faces request originating from that page. Non-faces requests do not propagate the page scope.
The conversation context. Spans multiple requests from the same browser window, demarcated by @Begin and @End methods. A conversation context is propagated by any faces request, or by any request that specifies a conversation id as a request parameter. The conversation context is not available during the restore view phase.
The session context. (A servlet login session.)
The application context (Servlet context.)
The business process context. Spans multiple conversations with multiple users, demarcated by the start and end states of the business process definition.
四:具有多个角色的组件(components with multiple roles)
有些组件可以具有多个角色。我们可以把相同的组件绑定到不同的上下文变量中。
@Name(“user”)
@Entity
@Scope(CONVERSATION)
@Role(name=”currentUser”,scope=SESSION)
Public class User{
…}
五:双向注入
1. 依赖注入(Dependency injection)允许一个组件通过容器“注入”另一个组件到一个setter方法或者实例变量的方式,来获得被“注入”组件的引用(reference)。
依赖注入发生在组件创建的时候,在此后在实例的整个生命周期中不再改变。
依赖注入比较适合无状态组件。
2. 双向注入(bijection)
A. contextual(上下文相关的) 双向注入用来针对不同的上下文来组装有状态的组件(在较大范围的上下文中的组件,可以引用较小范围的上下文中的组件)
B. bidirectional(双向的)双向注入的组件,被触发后,值从上下文变量中注射到组件属性中,也可以从组件属性反向注入回上下文
C. dynamic(动态的)因为上下文变量的值随着时间不断变化,而且因为seam组件是由状态的,双向注入在每次组件被调用的时候都发生。
六.Lifecycle methods(生命周期方法)
Session Bean 和实体Bean ,Seam组件支持所有通用的EJB3.0生命周期回调(@PostConstruct,@PreDestroy,等等)。
JavaBean组件的生命周期回调
@Create 方法在Seam 实例化一个组件后被调用。 一个组件只能定义一个
@Destroy 方法在Seam组件被绑定的上下文结束时被调用。一个组件只能有一个
有状态Session Bean组件必须定义一个无参并注解为@Remove的方法,这个方法在上下文结束时被Seam调用
@Startup,可以用在任何Application或者Session范围的组件上。因为这个注解,在上下文开始的时候立即初始化组件,而不是被客户访问的时候才创建。
七.Factory和Manager组件
Factory component pattern(工厂组件模式)让Seam 组件作为非组件对象的构造器。
当上下文变量被引用,但是没有值被绑定到它是,会调用一个factory method(工厂方法)。我们通过@Factory注解来定义工厂方法。工厂方法把一个值绑定到上述上下文变量,并且决定被绑定的值的范围
方法一:有返回值,seam会把它绑定到上下文里:
@Factory(scope=CONVERSATION)
Public List<Customer> getCustomerList(){
Return …;}
方法二:返回void,它自己把值绑定到上下文变量中
@DataModel List<Customer> customerList;
@Factory(“customerList”)
Public void initCustomerList(){
customerList=…;}
两种情况下,当我们引用customerList变量,而其值为null时,工厂方法被调用,然后对这个值生命周期的其他部分就无法操纵了。
Manager component pattern(管理者组件模式)
在这种情况下,有一个Seam组件绑定到上下文变量,它管理着上下文变量的值,对客户端不可见
管理者组件可以是任何组件,它需要一个@Unwrap方法。该方法返回对客户端可见的值,每次上下文变量被引用的时候都会被调用。
@Name(“customerList”)
@Scope(CONVERSATION)
Public class CustomerListManager
{
…
@Unwrap
Public List<Customer> getCustomerList(){
Return …;
}
}