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可定义、配置、实例化部件。可以认为SEAM是轻量级的框架,因为不强制你使用容器指定的接口,使用特殊的编程模型,让你的部件存在于容器中,这部件只是POJO,特殊的地方是让容器或上下文去控制实例出的对象。所以归类为元容器再准确。
在实例化部件后,SEAM用方法拦截的方式为之附加企业服务。
SEAM的主要强于Spring等其它被管理的容器的优点在于对待部件的上下文,等同于部件本身。
第二章建立了一个应用来了解Seam in Action,相信已产生了大量的关于部件的疑问。我相信这些问题在本章能解决。为了了解部件,要用自上而下的开发,向Open 18 应用中加入成员注册。
首先用seam-gen建立一个新实体。支持view 和action bean部件。随后,SEAM通过实例类中的JPA annotations来管理数据库。你会学到
view, action bean 部件,和entity部件之间如何协作。在学习这些之前,首先要了解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是一个保存着变量名的容器。SEAM分出多个scope,或是SEAM所谓的context.上下文,就是指在这个范围内,你可以找到并使用某一变量。
更准确在说,SEAM容器使用上下文变量。但是你很快就会发现,SEAM容器中真正的主角是部件。当应用访问部件实例的上下文时,会发生很多有趣的事。
从现在起,我们用context variable指SEAM容器某一特定上下文的变量。
注:我们经常混用scope and context,因为我们把它们当成一回事儿。
我首先简介一下SEAM的上下文,来说明一下其与传统上的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应用中,你用不同的上下文以控制变量陪伴业务的时间长度。application, session, and request,这三个Java Servlet API我们已很熟悉了,但只有这三个稍显不足。
几个粗粒度的范围之间的大间隙,也是应用程序应当存在的空间。每个servlet scope需要使用不同的API来存取变量,使代码变得复杂了。
为解决这些问题,SEAM引入了上下文命名容器,使用单一接口来操作所有类型的变量,同时也引入了一些上下文来补上粗粒度的范围间的空子。
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.
建立一个统一的上下文模型,SEAM升级了Java web开发环境。让上下文更自然地对应。
注意stateless 和unspecified不是真正的上下文,只是为了处理变量查找。
Stateless:每次变量名被解析时,实例化一次。对应于Spring的原型scope.
Event:对应servlet request scope,Restore View phase时开始,直到Render Response phase结束或重定向发生。
Page:始于JSF Render Response phase,被每个JSF postback附带,直到得定向发生或被导航到另一页面。这一机制的存储机制是JSF component tree。
Conversation:Restore View phase直到Render Response phase阶段结束。重定向也不会结束。如果被转换到long-running conversation,可跨越多个请求。对于non-JSF postback requests,由特殊的请求参数沿继续。对于JSF postback,则是通过JSF部件。
Session:对应servlet session scope.访问session-scoped的部件实例是线性化的。
Application:对应servlet application scope。
Business process:对应多个用户的多个会话。起始、终止于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的新的有状态的上下文
SEAM为提供有状态上下文用尽心思。当用户与程序交互时,状态被保存并可跟踪。在传统WEB应用,长期的状态保留在HTTP session,即状态上下文。
不管怎样,SEAM鼓励保存长期状态于上下文,其生命周期最好伴随用户的交互。为了支持这个,SEAM提供了两个新的上下文。conversation and business process,这依照的是用例,而不是假想的HTTP session scope边界。
SEAM同时将JSF’s view root attributes当做页上下文。将其当做是有状态上下文。
增加新的有状态上下文很重要,可以减轻服务器的负担,同时减少了共享状态可能产生的BUG。但最重要的还是防止了HTTP session的烂用。
让我们来看看每个上下文的目的和持续期。
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
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将其认作头等上下文变量,并通过SEAM page context暴露它们。页上下文可以在JSF生命周期的一个postback中从Render Response phase传数据,至少可以到其后续的Invoke Application phase。如果没有重定向,则随后到达Render Response phase,这个周期会随着UI部件树的恢复而持续多次(这是postback的结果),只在重画阶段,由导航规则来终止。
如果你用过MyFaces Tomahawk component的
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).
对话和商业过程范围,为是了管理长期的过程。其边界由annotations或页描述符来声明。大多使用的
Session scope可由会话替代。business process是conversation scope的变种,在数据库的支持下,可以在多个用户间传递状态。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强化的servlet contexts
对于特定的上下文,SEAM甚至使用Java Servlet API作为底层的存储机制。通过使用这些scopes,可以定位原生容器的缺陷。
如事件上下文封装了servlet request scope。这种抽象象生成事件一样发出WEB请求,
Java Servlet API被从Seam的内核中抽取出来。这让SEAM支持事件结构。对于典型的WEB开发,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.
在一个逻辑请求期间,有数次,变量需要被保存,如页面被请求、重画。当饱含一个或多个中间的转向时,逻辑请求不同于servlet请求。一个例子是Redirect-After-Post模式。不幸的是,在这各情况下,因为没有重定向,请求范围是无用的。JSF的Redirect-After-Post pattern,在Invoke Application 阶段,所有的请求范围的数据会被丢弃。最常丢失的是JSF状态信息。SEAM的会话范围传播上下文变量贯通整个请求,这是SEAM词汇中的临时会话。其FacesMessages部件可用来保证JSF状态信息在重定向中保留下来。这样问题就解决了。
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.
保持部件同步
在保护session-scoped部件免于同步访问的同时,SEAM强化了session上下 文。多个请求同时被同一个servlet处理,(如FacesServlet)。这些请求位于不同的线程,但由同一个servlet实例服务。如果两个请求的应用逻辑访问同一个session-scoped的变量,则会产生冲突。这种情况违反了线程安全性。为了避免,需要增加同步关键词到要访问的变量。SEAM为解决这一问题而自动同步sessionscoped变量。
你可以将这一方式应用到其它范围,只要在类定义中加入@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.
记住上下文容器的重要方面是通过统一接口访问所有上下文变量,不用考虑底层的存储机制。
你会在4.7中学到上下文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.
部件意味很多事。部件的定义有很多种。我说部件就是可以插在一个结构中从而形成更大结构的一块。
到目前为止,我们假定部件相当于JSF的被管理的BEAN,其实含义可以更广。部件可以是一个指令集合,存在一个容器中,用于建立一个对象,其生命周期受容器管理。
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
部件是一个指令集,是一个建立对象的蓝图。其补充了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被另一个Spring beans注入。如你所见,成为一个部件给了这个类一些特权。
SEAM部件具有如下特性:
元数据附属于实例的建立
生命周期方法
初始化属性值或对象参考
SEAM从部件的定义中建立部件实例,当你的应用访问部件,真正操作的是部件的实例。
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.
一旦一个部件实例建立后,使用部件名,被作为一个属性存储在其代表的上下文中,成了所谓的上下文变量。一个部件的实例就是一个JAVA对象,带着一个异常。附有拦截器来让SEAM管理其生命周期。
一旦受控,SEAM可以透明地组织其行为。即面向切面的编程。在这种模式下,方法调用不再是简单的方法调用,可以少付出而多收获。
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来处理对象。 这些依赖注入、管理事务、增强的安全限制、激发生命周期方法,通过部件处理触发的事件,简言之,具有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.
另一个特点是部件是由SEAM容器管理的。当请求中带有部件名时,容器呈现出部件实例。当请求到来是,SEAM首先去找已存在的实例,如果没有找到,就建立一个,并将其返回给调用者。
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来建立实例。这不表示你不可以,但为了得到所有AOP的强大能力,你最好让SEAM为你建立实例。从这个角度看,SEAM容器是部件实例的工厂。
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中,部件间的转化比其它轻量级的框架如Spring更多。这是因为上下文对于SEAM是如此重要。部件是伴随其存在的上下文的生命周期发生或消亡的。
Spring的容器实例的建立方式与SEAM类似,但差别是Spring主要使用单例的bean。其生命周期与应用一致。SEAM有趣的地方是对象可以在任一时点建立。
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.
在每次被调用时,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容器才能提供的能力,如容器管理的事务,安全及免受底层类型的的影响。当然最重要的特点还是其上下文相关,也就是有@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.
下表是各类的默认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进行重新指定。
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.
一个全面的例子
向Open 18应用中加入会员注册,首先我们要增加一个记录会员细节的实体类。我们用JPA实体类,名为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.
运行seam new-entity命令,并用如下 指定。
Entity class name: Golfer
Master page name: golferList
Detail page name: golfer
会生成一个Golfer JPA实体类,包含一个属性的基本集,一个球员的列表页golferList.xhtml,还有相应的页控制器(GolferList),一个显示球员细节页面(golfer.xhtml),还有相当的页控制器(GolferHome)。实际支持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是对应表的。不管什么时候,实体类都要有这个对应的表。
Hibernate会处理相关的事情。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的子类。其它注释现在不熟悉不要紧,因为这里这个类只是做为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,部件会在注册的表单面被调用产生一个新的球员的实例,
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不要用得过多,因为实例类是整个项目中最通用的,多个团队所命的名字很可能会有冲突。
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.
成员实体用的是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.
其它的属性不会出现在Golfer or the Member中,因为这些域不会被保存。我们不用transient来弄乱实体类,而是将这些域放到可重用的JavaBean---PasswordBean,其也包含一个业务方法来校验密码是否一致。这个类被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发布目录,运行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.
这是一个action bean部件,为UI命令部件提供动作方法,这就完全替代了JSF管理bean。
唯一的方法register(),将由register.xhtml调用,也是由new-action命令生成的。虽然现在还只是一个框架,但已足够强大。
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.
为了保险起见,我们应对目前的进展做个测试。幸运的是seam-gen已经帮我们做了测试框架。
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命令同时也为我们生成了集成测试类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匿名内部类用于模拟JSF生命周期。经历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目标test查找以Test.xml结尾的文件,将其加载到TestNG去运行。
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中设置日志级别,src/test/readme.txt中讲了在Eclipse中使用集成测试的用法。
为了校验action bean部件的行为,SEAM鼓励集成测试而非单元测试。如果你的action bean部件直接使用ORM or JSF,则集成测试是有必要的。你可以SEAM建立一个分层良好的应用,允许你在每一层建立单元测试,SEAM本身是一个快速开发,所以集成测试才是最有用的。
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现在还只是一个架子,但足以建立JSF模板来重画或注册表单。应用test-driven development (TDD)原则,我们会在真的需要时再完善register(),而不是现在。
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.
现在要设置JSF以访问SEAM部件。哈,其实什么都不用做。任何SEAM部件可以直接从JSF访问。
不用写XML,Golfer and PasswordBean可以作为支持bean,RegisterAction可以提供动作方法。所有需要做的就是写一个JSF去使用它们。
让我们改进一下seam-gen生成的注册视图,来注册新成员。
从JSF解析EL表达式
在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}绑定。
对于这个形式,直接解析成registerAction部件和register方法。SEAM也备有Golfer实体类,绑定到的上下文变量newGolfer。JavaBean类PasswordBean的实例,绑定到了上下文变量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}是双车道,(其实就是SEAM的特点之一:双向注入,我也管这个注入、注出)。既显示值也取得值。
This JSF template takes advantage of several UI components not yet covered. The
type properties to and from string values. The
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.
有几个功能比较实用的这类控件。
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让我们节约了很多代码,但register()还是要我们自己实现的。
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.
在部件有能力产生实例前,部件必须首先被容器发现。即使发现了,如果其它条件不满足,不是不能产生实例。一旦加载了,就可以按需要在部件启动时或被请求调用时建立实例。
每次实例建立,其life-cycle callback方法会在实例向请求返回值前被调用。当部件最终毁弃时或生命范围结束时,他还有最后机会做清理工作。
让我们从初生开始看看。
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发现部件是在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配置有很多种,这是因为JAVA缺少统一的语法来处理这些。这种情况在annotations出现后得到解决。
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只认规范的实体,所以目录结构要规范。
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.
带好标识,SEAM找部件能快些,不然要找遍整个类路径,费时并且容易出错。使用类路径标记,SEAM就明确地知道去哪里找。
有可能即使有规范的路径,有@Name annotation,也有部件描述符,SEAM仍不当部件的。
下面来说说安装条件下的前提条件。
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.
什么时候安装部件
当扫描到@Name,默认会将其当成部件。虽说自动发现部件是一个很强的机制,但你会因为类变成了部件而失去弹性,
这就是为什么@Install出现的原因。其告诉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.
先决条件不满足,也不是就不能用作部件了。你可以让其在满足其它部件描述符时进级。有些@Install(false)最开始置为否,就是等你在必要的时候启动。
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.
有时,如在JSF规范或应用服务器环境,对于同一个API,你需要实现不同的逻辑。
为了让部件清楚地处理各种环境,可以用@Install annotation来明确有做出限定。
在本例中,你建立一个接口和两个实现,由@Install annotation来处理最终使用哪个的问题。
You can create a component for the Sun JSF implementation:
可以为Sun JSF实现这样写:
@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
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值表达式。但你可以用一对@做成的替代标记。然后,在components.properties文件中使用环境指定值。
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:
还有一种玩儿法,就是你可以定义,让部件只在开发阶段可用。
这就是将部件带上DEBUG标签,SEAM的DEBUG模式由org.jboss.seam.core.init部件控制。你可以这样加上标志位。
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部件有高优先级,等到了工厂环境时,DEBUG部件就被禁掉了。
下面来看看SEAM如何来处理优先级问题。
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.
所有部件默认用的优先级是0,很容易覆盖掉。如果两部件有同一级别的优先级,则会抛出异常。
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.
给部件多个角色。
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:
多个角色可以让你同时,在一个范围中,有多个同一部件的实例。假定在注册时,新用户想参考另一用户的信息,则Golfer部件会有两个名字,newGolfer and golferExample。如果用户点击了lookup按钮,则会调用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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。