溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SEAM IN ACTION 第4章

發(fā)布時(shí)間:2020-08-10 18:19:36 來源:ITPUB博客 閱讀:112 作者:crazyscissors 欄目:編程語言


4、Components and contexts

This chapter covers
■ Defining Seam components using annotations
■ Hooking into component life-cycle events
■ Using EJB session beans as Seam components
■ Accessing instances of Seam components


This chapter introduces the components and contexts that Seam manages. If you’ve
worked with the Spring Framework, the idea of declaring managed objects should be
familiar to you. In Seam, however, you replace all uses of the word bean with the word
component. Like Spring, Seam boasts similar capabilities to define, configure, and
instantiate components. In one regard, you can think of Seam as a lightweight container.
It doesn’t force you to code to container-specific interfaces, require you to
adopt a special programming model, or mandate that your components even live in
a container. Instead, components are just plain old Java objects (POJOs). What makes
Seam unique is that it leverages existing containers and contexts to host the objects
it instantiates, so it’s more accurately classified as a meta-container. After obtaining
an instance of a component, Seam decorates it with enterprise services that are
applied transparently through the use of method interceptors. The main advantage
that Seam has over other managed containers such as Spring is that Seam treats a
component’s context with equal importance as the component itself. Thus, the focus of
this chapter is not just components, but rather contextual components.

Chapter 2 provided the opportunity to get an application up and running and
observe Seam in Action. I am sure those exercises, as well as references from the previous
chapter, have spawned loads of questions about components. I can assure you that your
questions will be addressed in this chapter. To learn about Seam components, you’re
going to use top-down development to add member registration to the Open 18 application.
You’ll first use seam-gen to create a new entity and the supporting view and
action bean component. Hibernate then takes care of adding the corresponding table
to the database when the application starts based on the information in the JPA annotations
on the entity class. You then study how the view, the action bean component,
and the entity interact with one another. Before doing all that, though, you must
understand Seam’s very essence: the contextual container.


與Spring框架類似,SEAM中bean都改叫部件了。SEAM可定義、配置、實(shí)例化部件??梢哉J(rèn)為SEAM是輕量級的框架,因?yàn)椴粡?qiáng)制你使用容器指定的接口,使用特殊的編程模型,讓你的部件存在于容器中,這部件只是POJO,特殊的地方是讓容器或上下文去控制實(shí)例出的對象。所以歸類為元容器再準(zhǔn)確。
在實(shí)例化部件后,SEAM用方法攔截的方式為之附加企業(yè)服務(wù)。
SEAM的主要強(qiáng)于Spring等其它被管理的容器的優(yōu)點(diǎn)在于對待部件的上下文,等同于部件本身。

第二章建立了一個(gè)應(yīng)用來了解Seam in Action,相信已產(chǎn)生了大量的關(guān)于部件的疑問。我相信這些問題在本章能解決。為了了解部件,要用自上而下的開發(fā),向Open 18 應(yīng)用中加入成員注冊。
首先用seam-gen建立一個(gè)新實(shí)體。支持view 和action bean部件。隨后,SEAM通過實(shí)例類中的JPA annotations來管理數(shù)據(jù)庫。你會學(xué)到
view, action bean 部件,和entity部件之間如何協(xié)作。在學(xué)習(xí)這些之前,首先要了解SEAM的根本概念:上下文容器。

4.1 Seam’s contextual naming container
At its core, Seam is a container that holds names, or rather, variable names. But Seam
doesn’t just let all of these variable names clump together at the bottom of the barrel.
Instead, Seam divides container into compartments and disperses the variables into each
one accordingly. Each compartment represents a scope, or in Seam terminology, a context.
A context defines where a variable name can be found and for how long it hangs around.
To be precise, the Seam container holds context variables. A context variable can
hold a reference to any type of object. But, as you’ll soon discover, the real divas of the
Seam container are the components. When the application interacts with a context
variable holding a reference to a component instance, lots of exciting things happen.
From this point forward, when I use the term context variable, I’m referring to a variable
in the Seam container that stores a value in a distinct context.
NOTE In the text, I’ll often switch between the terms scope and context. Don’t let
this confuse you; these two terms are interchangeable. Technically, the
context is the bucket and the scope is the marker that identifies the
bucket, but that’s really splitting hairs.
Before advancing with your lesson on Seam components and getting the lowdown on
where they hang out, I first need to briefly introduce you to Seam’s contexts and show
you what sets them apart from the traditional contexts in the Java Servlet API.

上下文命名容器
SEAM是一個(gè)保存著變量名的容器。SEAM分出多個(gè)scope,或是SEAM所謂的context.上下文,就是指在這個(gè)范圍內(nèi),你可以找到并使用某一變量。
更準(zhǔn)確在說,SEAM容器使用上下文變量。但是你很快就會發(fā)現(xiàn),SEAM容器中真正的主角是部件。當(dāng)應(yīng)用訪問部件實(shí)例的上下文時(shí),會發(fā)生很多有趣的事。
從現(xiàn)在起,我們用context variable指SEAM容器某一特定上下文的變量。

注:我們經(jīng)?;煊胹cope and context,因?yàn)槲覀儼阉鼈儺?dāng)成一回事兒。
我首先簡介一下SEAM的上下文,來說明一下其與傳統(tǒng)上的Java Servlet API的contexts有什么不同。


4.1.1 Seam’s context model
You have a set of contexts for storing variables for the same reason that you have multiple
golf clubs in your bag. In golf, you choose a club depending on how far you want
the ball to go. In a web application, you choose a context depending on how long you
want a variable to stick around. You’re likely familiar with the three scopes defined in
the Java Servlet API: application, session, and request. The problem with this abridged
set of scopes is that they are too few. It’s like trying to play a round of golf with a driver,
a five-iron, and a putter. You can make it work, but there are times when you’re going
to have to make each club do something for which it wasn’t designed.

The vast chasms that lie between the coarse-grained servlet scopes have claimed
the lives of many applications. In addition, each servlet scope requires that you use a
different API to access its variables, letting unnecessary complexity slip into the code.
The Seam developers solved these two obstacles by introducing the contextual naming
container, which provides a single interface to access all variables, regardless of
the context in which they are stored, and introduces several new contexts that fill in
the gaps between the existing ones.

在高爾夫球袋中,你會有一整套球桿,一樣道理,為了保存變量,你要有一整套上下文。在高爾夫中,你換球桿以打出不同的距離,在WEB應(yīng)用中,你用不同的上下文以控制變量陪伴業(yè)務(wù)的時(shí)間長度。application, session, and request,這三個(gè)Java Servlet API我們已很熟悉了,但只有這三個(gè)稍顯不足。
幾個(gè)粗粒度的范圍之間的大間隙,也是應(yīng)用程序應(yīng)當(dāng)存在的空間。每個(gè)servlet scope需要使用不同的API來存取變量,使代碼變得復(fù)雜了。
為解決這些問題,SEAM引入了上下文命名容器,使用單一接口來操作所有類型的變量,同時(shí)也引入了一些上下文來補(bǔ)上粗粒度的范圍間的空子。

4.1.2 Unifying the Java servlet contexts
Seam delivers a much needed technology update to the Java web environment by
establishing a unified context model. Seam takes all contexts under the wings of its
container, allowing the existing contexts to fit naturally with the new set of contexts
that it contributes. By controlling the contexts, Seam provides one-stop shopping for
context variables and adds useful enhancements to the existing servlet contexts.

The list of contexts Seam adds to the existing options are the stateless context, the
page context, the conversation context, and the business process context. The complete
set of contexts Seam supports are represented by the names in the Java 5 enum Scope-
Type, which you’ll see used in a couple of Seam annotations later in the chapter. Table
4.1 identifies these contexts, the associated name in the enum type, and a brief description
of the context’s life span. Note that the stateless and unspecified scopes aren’t real
contexts, but rather directives that instruct Seam how to handle a variable lookup.

建立一個(gè)統(tǒng)一的上下文模型,SEAM升級了Java web開發(fā)環(huán)境。讓上下文更自然地對應(yīng)。
注意stateless 和unspecified不是真正的上下文,只是為了處理變量查找。

Stateless:每次變量名被解析時(shí),實(shí)例化一次。對應(yīng)于Spring的原型scope.
Event:對應(yīng)servlet request scope,Restore View phase時(shí)開始,直到Render Response phase結(jié)束或重定向發(fā)生。
Page:始于JSF Render Response phase,被每個(gè)JSF postback附帶,直到得定向發(fā)生或被導(dǎo)航到另一頁面。這一機(jī)制的存儲機(jī)制是JSF component tree。
Conversation:Restore View phase直到Render Response phase階段結(jié)束。重定向也不會結(jié)束。如果被轉(zhuǎn)換到long-running conversation,可跨越多個(gè)請求。對于non-JSF postback requests,由特殊的請求參數(shù)沿繼續(xù)。對于JSF postback,則是通過JSF部件。
Session:對應(yīng)servlet session scope.訪問session-scoped的部件實(shí)例是線性化的。
Application:對應(yīng)servlet application scope。
Business process:對應(yīng)多個(gè)用戶的多個(gè)會話。起始、終止于business process定義文件指定的位置。

Let’s briefly explore the storing contexts and the relevance of each, starting with the
stateful contexts contributed by Seam.


4.1.3 Seam’s new stateful contexts
Seam makes a big deal about providing stateful contexts. As the user interacts with the
application, state is accumulated and that state needs to be tracked. In traditional web
applications, long-term state would be stored in the HTTP session, the de facto stateful
context. However, Seam encourages you to store long-term state in a context whose lifetime
aligns better with a user’s interaction. In support of this recommendation, Seam’s
stateful context stack includes two new contexts, conversation and business process,
that model a use case, rather than being fixed to predetermined boundaries like the
HTTP session scope. Seam also exposes JSF’s view root attributes as the page context,
solidifying them as a legitimate stateful context. Having these new stateful contexts is
important because they help reduce load on the server while also staving off bugs
caused by inadvertent sharing of state. But what’s most important about Seam’s array of
stateful contexts is that they prevent misuse of the HTTP session. Let’s consider the purpose
and duration of each context.

SEAM的新的有狀態(tài)的上下文
SEAM為提供有狀態(tài)上下文用盡心思。當(dāng)用戶與程序交互時(shí),狀態(tài)被保存并可跟蹤。在傳統(tǒng)WEB應(yīng)用,長期的狀態(tài)保留在HTTP session,即狀態(tài)上下文。
不管怎樣,SEAM鼓勵保存長期狀態(tài)于上下文,其生命周期最好伴隨用戶的交互。為了支持這個(gè),SEAM提供了兩個(gè)新的上下文。conversation and business process,這依照的是用例,而不是假想的HTTP session scope邊界。
SEAM同時(shí)將JSF’s view root attributes當(dāng)做頁上下文。將其當(dāng)做是有狀態(tài)上下文。
增加新的有狀態(tài)上下文很重要,可以減輕服務(wù)器的負(fù)擔(dān),同時(shí)減少了共享狀態(tài)可能產(chǎn)生的BUG。但最重要的還是防止了HTTP session的爛用。
讓我們來看看每個(gè)上下文的目的和持續(xù)期。

JSF has always supported a page scope, which is an unofficial classification of the attributes
stored in the view root of the JSF UI component tree. Seam recognizes these attributes
as first-class context variables and exposes them via the Seam page context. The
page context is capable of propagating data from the Render Response phase of the JSF
life cycle through at least the ensuing Invoke Application phase on a postback, then on
to the Render Response phase if the same view is rendered again without a redirect. This
cycle continues for as many times as the same UI component tree is restored (as a result
of a postback), and is only terminated by a navigation event that occurs prior to the Render
Response phase. You may have used this scope in a less formal way if you have ever
included the component tag from the MyFaces Tomahawk component
set1 in your application. The benefit of using Seam’s page context is that you don’t tie
the state logic to the view.

JSF也支持page scope,沒有官方指定,保存在UI部件樹的view root。SEAM將其認(rèn)作頭等上下文變量,并通過SEAM page context暴露它們。頁上下文可以在JSF生命周期的一個(gè)postback中從Render Response phase傳數(shù)據(jù),至少可以到其后續(xù)的Invoke Application phase。如果沒有重定向,則隨后到達(dá)Render Response phase,這個(gè)周期會隨著UI部件樹的恢復(fù)而持續(xù)多次(這是postback的結(jié)果),只在重畫階段,由導(dǎo)航規(guī)則來終止。
如果你用過MyFaces Tomahawk component的部件標(biāo)簽,則也許用過這種scope的非正規(guī)方式。使用SEAM上下文的好處在于不用將狀態(tài)邏輯綁定到view上。

The conversation and business process scopes are for managing long-running processes.
Their boundaries are controlled declaratively using annotations or page
descriptor tags. A conversation is a drop-in replacement for most uses of the session
scope. The business process is a variation on the conversation scope, but can pass state
between multiple users of the application, backed by persistence storage. You’ll learn
more about conversations in chapter 7 and business processes in chapter 14 (online).

對話和商業(yè)過程范圍,為是了管理長期的過程。其邊界由annotations或頁描述符來聲明。大多使用的
Session scope可由會話替代。business process是conversation scope的變種,在數(shù)據(jù)庫的支持下,可以在多個(gè)用戶間傳遞狀態(tài)。conversations在第7章,business processes在第14章。

4.1.4 Seam’s enhanced servlet contexts
Seam doesn’t turn its back on the traditional Java servlet contexts—it just fixes them.
Seam even uses the Java Servlet API as the underlying storage mechanism for these
particular contexts, though not blindly. By taking control of these scopes, Seam is
able to generalize their purpose and address flaws in how they are handled by the
native container.
For instance, the event context wraps the servlet request scope. This abstraction
generalizes a web request as an event so that the Java Servlet API is abstracted from
Seam’s core. This generalization opens the door for Seam to support the event construct
as defined in alternate environments. For typical web development, the event
context and request scope are one and the same.

SEAM強(qiáng)化的servlet contexts
對于特定的上下文,SEAM甚至使用Java Servlet API作為底層的存儲機(jī)制。通過使用這些scopes,可以定位原生容器的缺陷。
如事件上下文封裝了servlet request scope。這種抽象象生成事件一樣發(fā)出WEB請求,
Java Servlet API被從Seam的內(nèi)核中抽取出來。這讓SEAM支持事件結(jié)構(gòu)。對于典型的WEB開發(fā),event context 和 request scope是等同的。


There are times when variables need to be retained throughout a logical
request—defined as the time between when a page is requested and when it is rendered.
A logical request differs from a servlet request when it involves one or more interim redirects.
An example is the Redirect-After-Post pattern.2 Unfortunately, the request scope
is useless in this case since it doesn’t survive a redirect. Developers who have used the
Redirect-After-Post pattern on a JSF postback know that it causes all request-scoped data
prepared in the Invoke Application phase to be dropped. The data that is most often
missed is the JSF status messages. So what does Seam do to help? In the absence of a longrunning
conversation, which you’ll learn about in chapter 7, Seam’s conversation scope
propagates context variables across a logical request—what Seam terms a temporary
conversation. A temporary conversation covers the purpose of a Ruby on Rails flash
hash. Seam’s conversation-scoped FacesMessages component can be used, for
instance, to ensure that JSF status messages survive redirects. Problem solved.


在一個(gè)邏輯請求期間,有數(shù)次,變量需要被保存,如頁面被請求、重畫。當(dāng)飽含一個(gè)或多個(gè)中間的轉(zhuǎn)向時(shí),邏輯請求不同于servlet請求。一個(gè)例子是Redirect-After-Post模式。不幸的是,在這各情況下,因?yàn)闆]有重定向,請求范圍是無用的。JSF的Redirect-After-Post pattern,在Invoke Application 階段,所有的請求范圍的數(shù)據(jù)會被丟棄。最常丟失的是JSF狀態(tài)信息。SEAM的會話范圍傳播上下文變量貫通整個(gè)請求,這是SEAM詞匯中的臨時(shí)會話。其FacesMessages部件可用來保證JSF狀態(tài)信息在重定向中保留下來。這樣問題就解決了。


KEEPING COMPONENTS @SYNCHRONIZED
Seam improves the session context as well by protecting session-scoped components
from concurrent access. Multiple requests scheduled to be handled by the same
servlet (i.e., FacesServlet) may arrive at the server at the same time. These requests
run in different threads but are serviced by the same servlet instance. If the application
logic executed by both requests accesses the same session-scoped variable, it
may result in the object referenced by that variable being altered in conflicting ways.
This scenario is said to violate thread safety. To avoid it, you’d need to add the synchronized
keyword to the region of code accessing the variable. Seam addresses this
long-standing pitfall in web-based applications by automatically synchronizing sessionscoped
variables for you, and doing so with optimal efficiency. You can apply this synchronization
logic to components in other scopes by adding the @Synchronized annotation
to the class definition, summarized in table 4.2. This annotation allows the
timeout period of the synchronization to be tuned using the timeout attribute.


保持部件同步
在保護(hù)session-scoped部件免于同步訪問的同時(shí),SEAM強(qiáng)化了session上下 文。多個(gè)請求同時(shí)被同一個(gè)servlet處理,(如FacesServlet)。這些請求位于不同的線程,但由同一個(gè)servlet實(shí)例服務(wù)。如果兩個(gè)請求的應(yīng)用邏輯訪問同一個(gè)session-scoped的變量,則會產(chǎn)生沖突。這種情況違反了線程安全性。為了避免,需要增加同步關(guān)鍵詞到要訪問的變量。SEAM為解決這一問題而自動同步sessionscoped變量。
你可以將這一方式應(yīng)用到其它范圍,只要在類定義中加入@Synchronized聲明。


The important point to remember about the contextual container is that it provides
access to all context variables through a consistent interface, regardless of the underlying
storage mechanism. You’ll learn how to use the context API in section 4.7. With
contexts covered, let’s turn the focus of our discussion to the components associated
with them.

記住上下文容器的重要方面是通過統(tǒng)一接口訪問所有上下文變量,不用考慮底層的存儲機(jī)制。
你會在4.7中學(xué)到上下文API,

4.2 Sorting out components
The term component has been used to mean many things. In my attempts to describe it
to you, I found it difficult to locate a universal definition, likely because one doesn’t
exist. In theory, a component is supposedly a module that can be plugged into an
application in the same way that one Lego piece is attached to another Lego piece to
form a larger structure. As a person who makes a living developing software, I’m sure
you’ll agree that software components are a bit more complicated than Legos.
Definitions and intentions don’t matter anyway. What matters is what the word
means to you as a software developer. Up to now, we’ve assumed that a component is
equivalent to a JSF managed bean. Although a Seam component can stand in for a JSF
managed bean, the definition of a component is broader. A component is a set of
instructions, stored in a container, that is used to create objects whose life cycle is managed
by the container. After taking a deeper, but brief dive into this somewhat abstract
term, I promise that this component jargon will make sense. It’s all in the naming.

部件意味很多事。部件的定義有很多種。我說部件就是可以插在一個(gè)結(jié)構(gòu)中從而形成更大結(jié)構(gòu)的一塊。
到目前為止,我們假定部件相當(dāng)于JSF的被管理的BEAN,其實(shí)含義可以更廣。部件可以是一個(gè)指令集合,存在一個(gè)容器中,用于建立一個(gè)對象,其生命周期受容器管理。

4.2.1 Components vs. component instances
A component is a set of instructions, or a blueprint, for creating an object. It supplements
the Java class definition. Each component is assigned a name, which is used to
address the component. Table 4.3 lists several containers and how the components
they manage are declared.
When a class becomes a component, it gains access to whatever services the container
has to provide. For instance, methods on EJB session beans are automatically
wrapped in transactions; servlet components and JSF managed beans have access to

部件是一個(gè)指令集,是一個(gè)建立對象的藍(lán)圖。其補(bǔ)充了JAVA類的定義。


web-tier resource injections; Spring beans are injected with other Spring beans when
instantiated. As you can see, being a component gives a class special privileges.
Great, so now you know what a component is. But since this book is about Seam,
let’s focus on Seam components. A Seam component holds
■ Metadata pertaining to the creation of an instance
■ Life-cycle methods
■ Initial property values or object references


Seam creates component instances from the
component definition, as figure 4.1 illustrates.
When your application interacts with
a component, what it’s really invoking is an
instance of that component.


web-tier資源注入;Spring beans被另一個(gè)Spring beans注入。如你所見,成為一個(gè)部件給了這個(gè)類一些特權(quán)。
SEAM部件具有如下特性:
元數(shù)據(jù)附屬于實(shí)例的建立
生命周期方法
初始化屬性值或?qū)ο髤⒖?/p>


SEAM從部件的定義中建立部件實(shí)例,當(dāng)你的應(yīng)用訪問部件,真正操作的是部件的實(shí)例。

Once an instance of a component is created, it’s stored as an attribute in its designated
context under the name of the component, forming what is known as a context
variable. An instance of a component is just a Java object, with one exception. It is
strung with interceptors that allow Seam to keep tabs on it and manage its life cycle.
Once in control, Seam is able to transparently weave behavior into the object when it
is invoked. You may recognize this technique as Aspect-Oriented Programming
(AOP). The idea of AOP is to handle cross-cutting concerns that would otherwise
appear as boilerplate code or tie the code to a particular environment. With AOP at
work, a method call isn’t just a method call. More goes on around each invocation,
and that means you get more for less work.

一旦一個(gè)部件實(shí)例建立后,使用部件名,被作為一個(gè)屬性存儲在其代表的上下文中,成了所謂的上下文變量。一個(gè)部件的實(shí)例就是一個(gè)JAVA對象,帶著一個(gè)異常。附有攔截器來讓SEAM管理其生命周期。
一旦受控,SEAM可以透明地組織其行為。即面向切面的編程。在這種模式下,方法調(diào)用不再是簡單的方法調(diào)用,可以少付出而多收獲。


Seam determines how to handle the object based on the instructions provided in
annotations. The behavior that Seam applies includes injecting dependencies, managing
transactions, enforcing security constraints, invoking life-cycle methods, and handling
events triggered by the component, to mention a few. That should sound similar
to how EJB works as it inspired this design.

SEAM基于annotations來處理對象。 這些依賴注入、管理事務(wù)、增強(qiáng)的安全限制、激發(fā)生命周期方法,通過部件處理觸發(fā)的事件,簡言之,具有EJB的靈魂。


4.2.2 Seam manages components
There’s another important characteristic of a component: a component is managed by
the Seam container. The container hands out an instance of a component when the
name assigned to the component is requested, as shown in figure 4.2. When this request
comes in, Seam first tries to locate an existing instance. If one can’t be found, Seam will
create one (if asked to do so). The instance is then returned to the requester.

另一個(gè)特點(diǎn)是部件是由SEAM容器管理的。當(dāng)請求中帶有部件名時(shí),容器呈現(xiàn)出部件實(shí)例。當(dāng)請求到來是,SEAM首先去找已存在的實(shí)例,如果沒有找到,就建立一個(gè),并將其返回給調(diào)用者。

With Seam in control, you no longer have to create instances by instantiating the Java
class explicitly using the Java new operator. That isn’t to say that you can’t—but to get
all of the enhancements that Seam applies to the object via AOP (which happens during
the newInstance() routine in figure 4.2), you must allow Seam to create the instance
for you. In that regard, the Seam container is a factory for component instances, which
uses the component definitions as the schematics for how to create those instances.

在SEAM控制的情況下,你不用再用NEW來建立實(shí)例。這不表示你不可以,但為了得到所有AOP的強(qiáng)大能力,你最好讓SEAM為你建立實(shí)例。從這個(gè)角度看,SEAM容器是部件實(shí)例的工廠。


The translation from component to component instance happens more often in a
Seam application than it does in other lightweight containers such as Spring. That’s
because context is so important in Seam. In Seam, component instances come and go
along with the life cycle of the contexts in which they are stored. As you learned earlier,
Seam’s contexts have varying life spans (one with no life span at all). More often
than not, components in Seam are associated with stateful contexts, which means they
don’t invariably hang around for the lifetime of the application.

Instance creation takes place in the Spring container just as it does in Seam, but
you typically don’t give it much thought. That’s because Spring primarily uses singleton
beans, whose lifetime is tied to that of the application. What’s so interesting about
Seam is that it’s perfectly natural to create an object and inject dependencies into it at
an arbitrary point in time, rather than when the application starts.


SEAM中,部件間的轉(zhuǎn)化比其它輕量級的框架如Spring更多。這是因?yàn)樯舷挛膶τ赟EAM是如此重要。部件是伴隨其存在的上下文的生命周期發(fā)生或消亡的。
Spring的容器實(shí)例的建立方式與SEAM類似,但差別是Spring主要使用單例的bean。其生命周期與應(yīng)用一致。SEAM有趣的地方是對象可以在任一時(shí)點(diǎn)建立。


NOTE Spring does provide prototype beans that are created each time they’re
referenced, but they are arguably more difficult to use than Seam’s contextual
components.
We haven’t yet addressed how Seam components are defined. To be more concise,
how do the components get into the Seam container? Read on to find out.

在每次被調(diào)用時(shí),Spring并不提供原型bean,比SEAM的上下文部件要難用。

4.3 Defining components using annotations
In Seam, you can define components in one of two ways: you can use either annotations
or XML. The goal of Seam is to reduce as much XML coding as possible. Therefore,
annotations are the preferred mechanism for defining a Seam component. Two common
alternatives are the XML-based Seam component descriptor, covered in chapter 5,
and Seam’s pluggable container mechanism—the integration that allows Spring beans
to serve as Seam components—which is explored in chapter 15 (online). This chapter
focuses on the annotation approach. The annotations that dictate how a component is
defined are listed in table 4.4. As the chapter develops, I’ll introduce you to each one
in detail.


用annotations來定義部件
在SEAM中,可用兩種方法定義部件,XML或annotations?;蛲扑]使用annotations。


This section concentrates on @Name and @Scope, which together form an integral component
definition. The remaining annotations are auxiliary and affect how the component
is processed or behaves at runtime.

@Name and @Scope是最主要的,一起使用。其它的則都是輔助的。

4.3.1 Giving a component a @Name
It all starts with a @Name. The most fundamental way of creating a Seam component is
by adding the @Name annotation to the class declaration. This annotation is summarized
in table 4.5. Given that every Seam component must be assigned a name, you
must provide one using the value attribute of the @Name annotation.

You can place a @Name annotation on any class that you’d like to dress up as a Seam
component. Keep in mind, though, that annotations are obviously only useful for
classes that you can modify. See the accompanying sidebar describing the syntax of
annotations if you’re unfamiliar with how to use them.

The coolest part of Seam is its ability to normalize the nonsemantic differences
among components’ native types. The list of candidates for a Seam component
includes


■ JavaBean (POJO)
– JavaBean
– Groovy class (Groovy Bean)
– Spring bean3
■ EJB component
– Stateless session bean
– Stateful session bean
– Message-driven bean
■ JPA entity class (treated differently than JavaBean components)
Seam decorates JavaBean components with functionality equivalent to what is provided
by the EJB container, such as container-managed transaction management and
security, shielding the rest of the application from being affected by the underlying
type. What sets components in Seam apart from those in other containers is the attention
to the context of a component instance—the scope of its existence.

SEAM為JavaBean部件加上了EJB容器才能提供的能力,如容器管理的事務(wù),安全及免受底層類型的的影響。當(dāng)然最重要的特點(diǎn)還是其上下文相關(guān),也就是有@Scope。

4.3.2 Putting a component in @Scope
The @Name annotation is only half of the component story in Seam. The component
instance has to be put somewhere once it’s created. That’s where the @Scope annotation
comes in. The @Scope annotation dictates the contextual scope in which an
instance of the component will be stored after it’s instantiated by the Seam container.
You can, of course, put the component instance anywhere you want using a manual
assignment. The @Scope annotation just determines the default scope where Seam
stores the instance. Table 4.6 lists the scope that is used for each type of component if
one is not specified in the component definition.

下表是各類的默認(rèn)Scope。

You can override these default scope assignments by adding the @Scope annotation,
summarized in table 4.7, to the class definition.

Let’s consider an example of how to put the @Name and @Scope annotations
together to develop a new module for the Open 18 application.

你可以對這些Scope進(jìn)行重新指定。

4.4 A comprehensive component example
To add member registration to the Open 18 application, we first need to create an
entity that holds a member’s details. Thus, we’re going to make a JPA entity class our
first Seam component. Because members who register with the Open 18 application
are golfers, we’ll name the corresponding entity Golfer.


一個(gè)全面的例子
向Open 18應(yīng)用中加入會員注冊,首先我們要增加一個(gè)記錄會員細(xì)節(jié)的實(shí)體類。我們用JPA實(shí)體類,名為Golfer。


4.4.1 Creating the entity components
To create the Golfer entity, navigate to the Seam distribution directory and run the
seam new-entity command using the following responses:
Entity class name: Golfer
Master page name: golferList
Detail page name: golfer
The new-entity command generates the Golfer JPA entity class containing a base set
of properties, a page to list the golfers (golferList.xhtml) and corresponding page
controller (GolferList), and a page to display the details of a golfer (golfer.xhtml)
and corresponding page controller (GolferHome). The action beans components that
support the CRUD operations are covered in depth in chapter 10. For now, let’s focus
on using the Golfer entity class for the registration page.


運(yùn)行seam new-entity命令,并用如下 指定。
Entity class name: Golfer
Master page name: golferList
Detail page name: golfer
會生成一個(gè)Golfer JPA實(shí)體類,包含一個(gè)屬性的基本集,一個(gè)球員的列表頁golferList.xhtml,還有相應(yīng)的頁控制器(GolferList),一個(gè)顯示球員細(xì)節(jié)頁面(golfer.xhtml),還有相當(dāng)?shù)捻摽刂破?GolferHome)。實(shí)際支持CRUD的beans部件第10章再講。

The @Entity annotation added to the class declaration marks this class a JPA entity
and the @Table annotation customizes the database table mapping. Whenever you
add a new entity to the application, you also need to add a corresponding table to the
database. Fortunately, Hibernate takes care of this task for you when the application is
deployed as long as the value of the Hibernate property hibernate.hbm2ddl.auto in
the resources/META-INF/persistence-dev-war.xml descriptor is update. Note that this
is a change from the default value of validate set by seam-gen. Hibernate will also
add additional table columns for any new entity properties that it detects.


@Table是對應(yīng)表的。不管什么時(shí)候,實(shí)體類都要有這個(gè)對應(yīng)的表。
Hibernate會處理相關(guān)的事情。hibernate.hbm2ddl.auto值為update。


I’ve decided to enhance the Golfer class, shown in listing 4.1, by making it a subclass
of Member, shown in listing 4.2. The use of entity inheritance sets the stage for a
more flexible and realistic application. However, don’t concern yourself too much
with the JPA annotations, such as @PrimaryKeyJoinColumn, if they aren’t familiar to
you, because the primary focus here is on using this class as a form “backing” bean in
a JSF page. In order for that to happen, it needs to be declared as a Seam component.


我要加增Golfer,讓其成為Member的子類。其它注釋現(xiàn)在不熟悉不要緊,因?yàn)檫@里這個(gè)類只是做為JSF頁面的支持bean。


To make Golfer a Seam component, you simply add the @Name and @Scope annotations
alongside the JPA annotations, shown in bold in listing 4.1. The component
name newGolfer has been chosen since the component will be called on to instantiate
a fresh instance of a golfer for use in the registration form. The @Scope annotation is
present to explicitly bind the component to the event scope for demonstration, overriding
the default scope assignment for entity classes, which is the conversation scope.
Several bean properties have been added to support the use case, which map to columns
in the GOLFER table. Also note the use of the Hibernate Validator annotations
which, as you learned in the previous chapter, help enforce validations in the UI.


使用名newGolfer,部件會在注冊的表單面被調(diào)用產(chǎn)生一個(gè)新的球員的實(shí)例,

AUTHOR
NOTE


An alternative to adding @Name and @Scope to a JPA entity class is to
declare the component in the Seam component descriptor using XML,
which you’ll learn about in the next chapter. For now, appreciate that the
use of annotations keeps things simple by eliminating XML configuration.
Given that annotations are merely class metadata, they don’t affect
the execution of the code (unless consulted using reflection). I confess
that I prefer to limit the use of the @Name annotation to action beans and
business components. Entity classes are the most frequently shared components,
so conflicts can occur between teams over how to define the
Seam annotations. Besides, entity classes instantiated by the persistence
manager aren’t decorated with Seam interceptors. The primary use of a
Seam entity component is to serve as a prototype—a new, transient (not
yet persisted) instance. The prototype typically requires additional configuration
that can only be defined in the component descriptor.


我本人是感覺@Name不要用得過多,因?yàn)閷?shí)例類是整個(gè)項(xiàng)目中最通用的,多個(gè)團(tuán)隊(duì)所命的名字很可能會有沖突。

Member is an abstract entity class that holds the username, passwordHash, and
emailAddress inherited by the Golfer entity. The Member entity, shown in listing 4.2,
uses a joined-inheritance strategy. This design makes it possible to have different types
of members that are represented in separate tables. For the purpose of this registration
example, we assume that a golfer is the only type of member. Again, don’t get
bogged down in this design if you’re new to JPA. Appreciate that the goal here is to
establish a JavaBean that can be used to capture data from the registration form.

成員實(shí)體用的是joined-inheritance策略,這樣可以用分開的表表示不同類型的成員。本例,我們假定球員是唯一成員類型。


The registration form needs to capture a plain-text password from the user as well as a
password confirmation. Corresponding properties aren’t found on either the Golfer or
the Member entity since these fields aren’t to be persisted. Rather than dirtying the entity
classes with transient fields, we’ll put these fields on a reusable JavaBean, PasswordBean,
defined in listing 4.3. The PasswordBean also contains a business method for verifying
that the two passwords entered are equivalent. This class is created under the src/model
directory of the seam-gen project along with the entity classes.

其它的屬性不會出現(xiàn)在Golfer or the Member中,因?yàn)檫@些域不會被保存。我們不用transient來弄亂實(shí)體類,而是將這些域放到可重用的JavaBean---PasswordBean,其也包含一個(gè)業(yè)務(wù)方法來校驗(yàn)密碼是否一致。這個(gè)類被seam gen建立在src/model目錄

To give you a true appreciation of how easy Seam is making your life, I want to now
show you how @Name and @Scope provide everything necessary to design a JSF form
and action bean component to process the form submission. No XML is required.


4.4.2 Preparing an action bean component
Return once again to the Seam distribution directory. Execute the command seam
new-action to create the RegisterAction component using the following responses:
Seam component name: registerAction
Bean class name: RegisterAction
Action method name: register
Page name: register


在SEAM發(fā)布目錄,運(yùn)行seam new-action,用這些名字建立RegisterAction部件,


This command generates the RegisterAction JavaBean class shown in listing 4.4. The
@Name annotation above this class makes it a Seam component. Since the @Scope annotation
is excluded, and this is a regular JavaBean, instances of it are bound to the
event context. (The Seam annotations @In and @Logger are described later in this
chapter.) This component will serve as an action bean component—a component that
provides action methods used by UI command components. A Seam component used
for this purpose completely replaces the need for a JSF managed bean.

The RegisterAction component contains a single method, register(), that will
be used as the target of the form on the register.xhtml page, also generated by the
new-action command. Although the register() method is just a stub, it will suffice
for now. You’ll develop the RegisterAction component and register.xhtml page further
as you progress through the chapter.

這是一個(gè)action bean部件,為UI命令部件提供動作方法,這就完全替代了JSF管理bean。
唯一的方法register(),將由register.xhtml調(diào)用,也是由new-action命令生成的。雖然現(xiàn)在還只是一個(gè)框架,但已足夠強(qiáng)大。


Before taking another step down the development path, we need to safeguard ourselves
by creating a test. Fortunately, seam-gen has already done the legwork for us.

為了保險(xiǎn)起見,我們應(yīng)對目前的進(jìn)展做個(gè)測試。幸運(yùn)的是seam-gen已經(jīng)幫我們做了測試框架。


4.4.3 Integration testing components
To practice good agile development techniques, you always want to create a test either
before or while you’re developing a new component. Conveniently, the new-action
command also generated an integration test class, RegisterActionTest, in the src/test
directory. The test class, shown in listing 4.5, has been renamed to RegisterGolfer-
IntegrationTest to better represent its function as an integration test.

new-action命令同時(shí)也為我們生成了集成測試類RegisterActionTest,在src/test目錄。被改名為
RegisterGolfer-IntegrationTest以更好地代表其用途。

The test class in listing 4.5 extends SeamTest, which bootstraps the Embedded JBoss to
provide a Java EE–compliant environment in which to test your components. The
FacesRequest anonymous inner class is used to emulate the JSF life cycle, shown here
passing through the Invoke Application phase. seam-gen projects use the testing framework
TestNG. A TestNG configuration file, RegisterActionTest.xml, is created along
with this class to configure the test runner. A modified version that takes into account
the renamed test class is shown here:

FacesRequest匿名內(nèi)部類用于模擬JSF生命周期。經(jīng)歷Invoke Application phase。使用TestNG框架。配置文件RegisterActionTest.xml也一起建立起來。


The Ant target named test in the project’s build.xml file looks for files ending in
Test.xml and feeds them into the TestNG test runner to execute. You should be able to
run ant test from the root of the project to verify that the test passes, producing the
output shown here:

ANT目標(biāo)test查找以Test.xml結(jié)尾的文件,將其加載到TestNG去運(yùn)行。

You can adjust the log levels used during a test run by editing the Log4j configuration
bootstrap/log4j.xml. The file src/test/readme.txt contains instructions on how to run
a Seam integration test from Eclipse (it requires that you have Embedded JBoss on the
test classpath).
NOTE The Embedded JBoss bundled with Seam 2.0 only works with a Java 5 runtime
(not a Java 6 or 7 runtime). Until a version of Seam is released with
a Java 6–compatible Embedded JBoss container, you must run tests using
Java 5.

可以在bootstrap/log4j.xml中設(shè)置日志級別,src/test/readme.txt中講了在Eclipse中使用集成測試的用法。

為了校驗(yàn)action bean部件的行為,SEAM鼓勵集成測試而非單元測試。如果你的action bean部件直接使用ORM or JSF,則集成測試是有必要的。你可以SEAM建立一個(gè)分層良好的應(yīng)用,允許你在每一層建立單元測試,SEAM本身是一個(gè)快速開發(fā),所以集成測試才是最有用的。


The action bean component RegisterAction is just a stub at this point, but it’s good
enough to turn to the task of creating the JSF template that renders the registration
form. Using test-driven development (TDD) principles, we’ll complete the implementation
of the register() method when we need it—not a minute sooner.


RegisterAction現(xiàn)在還只是一個(gè)架子,但足以建立JSF模板來重畫或注冊表單。應(yīng)用test-driven development (TDD)原則,我們會在真的需要時(shí)再完善register(),而不是現(xiàn)在。


4.4.4 Hooking components into JSF
Now we need to set up JSF so that it can access the Seam components. Guess what?
There’s nothing to do! Believe it or not, any Seam component is accessible to JSF as is
(see the accompanying sidebar). The @Name annotation can be compared to defining
a JSF managed bean in the faces-config.xml descriptor, except that the resulting component
is far more capable. While you may look back and see that you’ve entered
quite a bit of code, you haven’t had to write a single line of XML. And there’s no need
to mess with glue code, either. Golfer and PasswordBean can serve as backing beans,
and RegisterAction can provide the action method for the registration page. All you
need to do is write a JSF view to use them. Let’s enhance the registration view generated
by seam-gen to capture the input necessary to register a new member.

現(xiàn)在要設(shè)置JSF以訪問SEAM部件。哈,其實(shí)什么都不用做。任何SEAM部件可以直接從JSF訪問。
不用寫XML,Golfer and PasswordBean可以作為支持bean,RegisterAction可以提供動作方法。所有需要做的就是寫一個(gè)JSF去使用它們。
讓我們改進(jìn)一下seam-gen生成的注冊視圖,來注冊新成員。


從JSF解析EL表達(dá)式
在faces-config.xml中注冊解析器。例如:#{passwordBean.password}被解析成passwordBean部件的getPassword()方法。


JSF VIEWS, SEAM-STYLE
The register.xhtml page was created with a basic JSF form when you ran the new-action
command, but we need to add input fields to it. The augmented form is shown in listing
4.6. The register() method on the RegisterAction component serves as the form’s
action, as defined by the method-binding expression #{registerAction.register} in
the action attribute of the UI command button. This method-binding expression is
derived by combining the component name of the action bean component, register-
Action, with the name of the action method, register (minus the parentheses). Seam
also prepares an instance of the Golfer entity class, binding it to the context variable
newGolfer, and an instance of the PasswordBean JavaBean class, binding it to the context
variable passwordBean, which are both used to capture data from the input fields.


RegisterAction部件的register()方法用作表單的action,在UI命令按鈕的#{registerAction.register}綁定。
對于這個(gè)形式,直接解析成registerAction部件和register方法。SEAM也備有Golfer實(shí)體類,綁定到的上下文變量newGolfer。JavaBean類PasswordBean的實(shí)例,綁定到了上下文變量passwordBean。他們都從錄入域得到值。

This form should appear familiar to you since the markup, particularly ,
was covered in the previous chapter. Let’s focus on how the form data is exchanged with
our components. Value-binding expressions that take the form #{newGolfer.
username} are a two-way street. They’re used to output a component property to the
screen as well as capture a value to be assigned to the property when the form is submitted.
This form captures data from the user and assigns the values to the properties
of the Seam components bound to the newGolfer and passwordBean context variables.

#{newGolfer.username}是雙車道,(其實(shí)就是SEAM的特點(diǎn)之一:雙向注入,我也管這個(gè)注入、注出)。既顯示值也取得值。


This JSF template takes advantage of several UI components not yet covered. The
and Seam UI component tags translate Java 5 enum
type properties to and from string values. The component tag from
RichFaces lets the user select a date using a pop-up calendar. The
Seam UI component tag sets which button is activated when the user presses
the Enter key. This overrides the default browser behavior of associating the first
submit button in the form with the Enter key, which in this case would be the Cancel
button. For a complete list of component tags that Seam adds to JSF, consult the Seam
reference documentation.


有幾個(gè)功能比較實(shí)用的這類控件。


As you can see, annotations and Seam UI component tags dramatically reduce the
amount of work necessary to pull together a JSF application. While we still need to
provide an implementation for the register() action method, the @Name annotation
is the only link needed to get JSF working with your Seam components.
A component lives a busy life outside of these moments in the limelight. In the
next section, you’ll get a glimpse behind the scenes of the life of a component: how
it’s discovered, selected, groomed, and managed by the Seam container.


SEAM讓我們節(jié)約了很多代碼,但register()還是要我們自己實(shí)現(xiàn)的。


4.5 A component’s life
Before a component definition can be used to spawn component instances, the definition
of the component must be discovered by the Seam container. Even upon discovery,
the component may not be loaded into the Seam container if its prerequisites
aren’t satisfied. Once loaded, Seam will create an instance from the definition immediately
if it’s a startup component or wait for it to be requested if not. Regardless of
when instance creation occurs, its life-cycle callback methods are invoked before the
instance is returned to the requester. Finally, when the component is destroyed or
goes out of scope, it has one last opportunity to perform work before being cast away.
That’s a component’s life; let’s start from the birth.

在部件有能力產(chǎn)生實(shí)例前,部件必須首先被容器發(fā)現(xiàn)。即使發(fā)現(xiàn)了,如果其它條件不滿足,不是不能產(chǎn)生實(shí)例。一旦加載了,就可以按需要在部件啟動時(shí)或被請求調(diào)用時(shí)建立實(shí)例。
每次實(shí)例建立,其life-cycle callback方法會在實(shí)例向請求返回值前被調(diào)用。當(dāng)部件最終毀棄時(shí)或生命范圍結(jié)束時(shí),他還有最后機(jī)會做清理工作。
讓我們從初生開始看看。


4.5.1 Loading component definitions
In order for the components to get into the container, Seam has to find them. This
happens during the Seam initialization process. The means by which Seam is bootstrapped
is covered in the previous chapter. During initialization, a deployment scanner
scours the classpath looking for classes that host the @Name annotation. In
addition to Java classes, Seam accepts both compiled and noncompiled Groovy
classes. Seam also looks for classes that are identified as components in the XML-based
component descriptor and loads them into the container. The component descriptor
is covered in depth in the next chapter.

裝載部件定義
SEAM發(fā)現(xiàn)部件是在SEAM初始化階段。找@Name annotation,除此之外,還接受編譯或沒編譯過的Groovy類。也去查看基于XM的部件描述符。

For each class declared as a component, Seam creates a component definition and
stashes it away in the application scope. The name of the attribute under which the
component definition is stored is derived by appending .component to the component
name (e.g., registerAction.component). For your purposes, you’ll always address the
component by its component name (e.g., registerAction).


Many XML configurations were devised because the Java language lacked a common
syntax for adding class metadata that is detectable by the classloader. That changed
when annotations were introduced. The component scanner frees you from having to
declare every Seam component in an XML descriptor because it’s capable of seeking out
classes that host the @Name annotation. The result is that you have one less XML file to
juggle (and no unnecessary layer of abstraction).

XML配置有很多種,這是因?yàn)镴AVA缺少統(tǒng)一的語法來處理這些。這種情況在annotations出現(xiàn)后得到解決。


Ah, but there’s a catch! Seam only considers qualified classpath entries (class directories
and JAR files). A classpath entry is considered qualified if it contains a seam.properties
file at its root or the META-INF directory contains a component descriptor (i.e.,
components.xml). In the next chapter, you’ll discover that the seam.properties file has
another use: to initialize the properties of Seam components.
Figure 4.3 shows the presence of the seam.properties file at
the root of classpath for the open18.jar. If you have Seam
components deployed and they aren’t being picked up, the
first thing to verify is that a seam.properties file is present on
the classpath where your Seam components reside.

SEAM只認(rèn)規(guī)范的實(shí)體,所以目錄結(jié)構(gòu)要規(guī)范。


Requiring the presence of a marker file is a JVM classloader
optimization that works to pare down the number of
classpath entries that must be scanned for components.
Though it may seem annoying to have to ensure that a
marker file is present, this annoyance pays off in that it helps
Seam figure out which classpath entries are relevant. Without
this optimization, Seam would go looking all over the
classpath for components, possibly even stepping into the
application server classpath, an expensive and potentially
error-prone operation. By using the classpath markers, Seam knows exactly where
to look.
It is possible that even though a class is in a qualified classpath entry and has a
@Name annotation, or it’s declared as a component in the component descriptor, it still
won’t be recognized as a Seam component. The next section details how to define
prerequisites on a class that make its installation conditional.

帶好標(biāo)識,SEAM找部件能快些,不然要找遍整個(gè)類路徑,費(fèi)時(shí)并且容易出錯。使用類路徑標(biāo)記,SEAM就明確地知道去哪里找。
有可能即使有規(guī)范的路徑,有@Name annotation,也有部件描述符,SEAM仍不當(dāng)部件的。
下面來說說安裝條件下的前提條件。

4.5.2 When to @Install a component
When the component scanner finds a class annotated with @Name, the default behavior
is to make it a component. While the automatic discovery of components is a powerful
mechanism, you lose a degree of flexibility over which classes are turned into components.
That’s where the @Install annotation comes into play. This @Install annotation,
summarized in table 4.8, tells Seam the conditions under which to honor a
component declaration. It can also be used to allow a second definition of the same
component to override the first. Both cases will be considered in detail.
You have a wide range of prerequisites for controlling the condition under which a
component is installed. The most clear-cut is the value attribute on the @Install
annotation, which is a boolean that can be used to switch the component on or off.

什么時(shí)候安裝部件
當(dāng)掃描到@Name,默認(rèn)會將其當(dāng)成部件。雖說自動發(fā)現(xiàn)部件是一個(gè)很強(qiáng)的機(jī)制,但你會因?yàn)轭愖兂闪瞬考椥裕?br />這就是為什么@Install出現(xiàn)的原因。其告訴SEAM可成為部件的條件。
value屬性是最直接的,決定著是與不是的問題。


You can further control whether the component is installed by enforcing any of the
following prerequisites:
■ The presence of other component definitions, looked up by component name
■ The presence of other component definitions, looked up by class name
■ Classes available on the classpath
■ A weighted precedence value (selects one definition over another for the same
component name and precedence combination)
■ The Seam debug mode setting

這是另外一些先決條件


If the prerequisites are not satisfied, that doesn’t mean that its future as a component
is entirely bleak, though. You can still place it back into the ranks of the other components
by declaring it in the component descriptor. Several built-in Seam components
are declared using @Install(false), allowing you to enable them as needed. A sampling
of components include
■ Seam managed persistence context
■ jBPM session factory
■ POJO cache
■ Asynchronous dispatcher (Quartz, EJB 3, Spring)
■ Non-JTA transaction manager
■ JMS topic publisher
■ Spring context loader
Aside from limiting the set of component definitions, conditional installation can be
useful for selecting between alternate implementations of a component.


先決條件不滿足,也不是就不能用作部件了。你可以讓其在滿足其它部件描述符時(shí)進(jìn)級。有些@Install(false)最開始置為否,就是等你在必要的時(shí)候啟動。

ALTERNATE IMPLEMENTATIONS
There are times when you need to perform different logic to support different implementations
of the same API, such as the JSF specification or application server environment.
To keep your component clean, void of conditional logic that checks for the
presence of an implementation class, you may choose to separate the logic for each
implementation into different components and have the appropriate component
selected by Seam according to the prerequisites defined in the @Install annotation.
To make use of the @Install annotation in this case, you create two implementation
classes and one interface. Then you give the two implementations the same component
name, and let the @Install annotation handle which one will be configured based on
the presence of a particular JSF implementation class.

有時(shí),如在JSF規(guī)范或應(yīng)用服務(wù)器環(huán)境,對于同一個(gè)API,你需要實(shí)現(xiàn)不同的邏輯。
為了讓部件清楚地處理各種環(huán)境,可以用@Install annotation來明確有做出限定。
在本例中,你建立一個(gè)接口和兩個(gè)實(shí)現(xiàn),由@Install annotation來處理最終使用哪個(gè)的問題。

You can create a component for the Sun JSF implementation:

可以為Sun JSF實(shí)現(xiàn)這樣寫:


@Name("jsfAdapter")
@Install(classDependencies = "com.sun.faces.context.FacesContextImpl")
public class SunJsfAdapter implements JsfAdapter {...}

and another for the MyFaces JSF implementation:


為MyFaces JSF這樣寫:
@Name("jsfAdapter")
@Install(classDependencies =


"org.apache.myfaces.context.servlet.ServletFacesContextImpl")
public class MyFacesJsfAdapter implements JsfAdapter {...}

You can then request the component named jsfAdapter from the Seam container
and Seam will return the appropriate implementation for you depending on which
FacesContext implementation class is available on the classpath.
How many frameworks completely overlook this type of functionality, forcing you
to devise your own solution? Conditional installation is a fundamental part of defining
components.

NOTE Seam doesn’t allow EL value expressions to be used in the value attribute
of the @Install annotation. However, you can put a replacement token
(a name surround by a pair of @ symbols) in the installed attribute on
the element and then have your build supply an environment-
specific value for that token in the components.properties file.
You’ll learn how to use replacement tokens in the next chapter.

SEAM不許在@Install annotation的值屬性中使用EL值表達(dá)式。但你可以用一對@做成的替代標(biāo)記。然后,在components.properties文件中使用環(huán)境指定值。


There is another facet to alternate implementations: you can define components that
should only be available during development mode, possibly ones that override equivalently
named production components.
DEBUG MODE COMPONENTS
Another way to control the installation of a component is to tie it to Seam’s debug
mode flag. You do so by setting the debug attribute on the @Install annotation to
true. Seam’s debug mode is controlled by the debug property on the org.jboss.
seam.core.init component. You enable the debug mode flag by adding the following
declaration to the component descriptor:

還有一種玩兒法,就是你可以定義,讓部件只在開發(fā)階段可用。
這就是將部件帶上DEBUG標(biāo)簽,SEAM的DEBUG模式由org.jboss.seam.core.init部件控制。你可以這樣加上標(biāo)志位。

You’ll learn how to configure built-in Seam components using XML in the next chapter.
For now, let’s focus on the effect of this setting. When it’s set to true, Seam
activates components that are marked with @Install(debug=true). You can use this
flag to swap in components that return canned data or otherwise stub out
back-end logic. In debug mode, the debug component has higher priority. When it
comes time to deploy to a production environment, the debug component is disabled,
and if a non-debug component with the same component name exists, it
becomes activated.
Speaking of priority, one component definition can be selected over another
based on its precedence. A precedence value is required any time you have two components
assigned to the same component name. Let’s see how Seam handles the
curve ball of conflicting component definitions.

在DEBUG模式,DEBUG部件有高優(yōu)先級,等到了工廠環(huán)境時(shí),DEBUG部件就被禁掉了。
下面來看看SEAM如何來處理優(yōu)先級問題。


INSTALLATION PRECEDENCE
Precedence defines which component definition wins when two components try to
occupy the same space—in other words, they have the same component name. A precedence
is an integer value assigned to a component using the precedence attribute
on the @Install annotation. The higher the value, the more clout it has. All built-in
Seam components have a precedence of Install.BUILT_IN (0), so they can easily be
overridden. If a precedence isn’t defined, it defaults to Install.APPLICATION (20).
With precedence in the picture, the rule is that two components can’t be defined with
the same name and precedence value. If this situation occurs, it will cause an exception
to be thrown at startup when the component scanner discovers it.
If all the prerequisites are satisfied, the component gets the gig. It has made it into
the container. A single class can also produce multiple component definitions with
different component names and potentially different scopes. These alternate definitions
are known as component roles.

所有部件默認(rèn)用的優(yōu)先級是0,很容易覆蓋掉。如果兩部件有同一級別的優(yōu)先級,則會拋出異常。

4.5.3 Giving a component multiple @Roles
As you know, a component must be assigned a name. But that doesn’t mean it can’t
be assigned more than one name. Alternate name and scope combinations are
assigned to a component using the @Role annotation, summarized in table 4.9. To
define multiple @Role annotations for a single component, you nest them within the
@Roles annotation.

給部件多個(gè)角色。

The idea behind roles is to allow the same component to be instantiated and managed
by Seam for different purposes. A scope is assigned to a role in order to relieve
the code that uses the role name from making the decision of where to store the new
instance. You’ll often see this technique used in outjection, covered in chapter 6.
Multiple roles also allow you to use multiple instances of the same component class
simultaneously in the same scope. Let’s consider a simple example when such dualism
is needed. The registration form is using an instance of the Golfer component, named
newGolfer, to capture the new member information. Suppose that we want to use an
example query, fed with another instance of the Golfer class, that allows the registering
member to locate the member that referred them to the website. To implement this feature,
the Golfer component needs to be accessed under two different names,
newGolfer and golferExample. When the user clicks the lookup button, the search criteria
get applied to the auxiliary Golfer instance bound to the golferExample context
variable and passed on to the back end to perform the example query. The alternate
name is assigned to the Golfer class using a @Role annotation, shown here in bold:

多個(gè)角色可以讓你同時(shí),在一個(gè)范圍中,有多個(gè)同一部件的實(shí)例。假定在注冊時(shí),新用戶想?yún)⒖剂硪挥脩舻男畔ⅲ瑒tGolfer部件會有兩個(gè)名字,newGolfer and golferExample。如果用戶點(diǎn)擊了lookup按鈕,則會調(diào)用golferExample上下文變量,


Example queries are supported natively in Hibernate but not in JPA. Here’s how an
example query is conducted using Hibernate:

Later in this chapter, you’ll learn how to access a component instance populated from
a UI form in your action bean component. For now, keep in mind that the role lets
you isolate the instance of Golfer used for the example query from the instance used
to back the registration form.
Returning to the component scanner, once it finishes addressing all the component
definitions and role assignments, the Seam container is left with a bunch of component
definitions. But there aren’t yet any component instances. Typically, a
component definition has to wait until its component name is requested in order to
be instantiated. There’s one condition when the instance of the component is created
even though it’s not explicitly requested: if the component is a startup component.


4.5.4 Instantiating components at @Startup
The @Startup annotation, summarized in table 4.10, instructs Seam to take the initiative
of creating an instance of the component when the component’s scope is
initialized. At the time of this writing, only application- and session-scoped components
can be flagged as startup components, though other scopes may be added in
the future.
If you add the @Startup annotation to the class definition of a component, and the
component is scoped to the application context, Seam automatically creates an
instance of the component when the application starts. This eager ins

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI