blob: 1edf31a269c70f59ba70b013064d428ca70164d0 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>应用 @Alternative Bean 和生命周期标注 - NetBeans IDE 教程</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="description" content="This tutorial explores CDI's injection facilities to perform custom validation using NetBeans IDE">
<meta name="keywords" content="NetBeans, IDE, integrated development environment,
Contexts and Dependency Injection, CDI, Web Beans, injection, qualifier">
<link rel="stylesheet" type="text/css" href="../../../netbeans.css">
</head>
<body>
<!--
Copyright (c) 2009, 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-->
<h1>应用 @Alternative Bean 和生命周期标注</h1>
<p><em>撰稿人:Andy Gibson</em></p>
<div class="margin-around">
<div class="feedback-box margin-around float-left" style="margin-right:15px">
<h3>上下文和依赖关系注入</h3>
<ol>
<li><a href="cdi-intro.html">CDI 和 JSF 2.0 入门指南</a></li>
<li><a href="cdi-inject.html">使用 CDI 中的注入和限定符</a></li>
<li><strong>应用 @Alternative Bean 和生命周期标注</strong>
<ul style="margin: 5px 0 0 -2em">
<li><a href="#alternative">处理多个部署</a></li>
<li><a href="#lifecycle">将生命周期标注应用于受管 Bean</a></li>
<li><a href="#seealso">另请参见</a></li>
</ul></li>
<li><a href="cdi-events.html">使用 CDI 中的事件</a></li>
</ol>
</div>
</div>
<img alt="此页上的内容适用于 NetBeans IDE 7.2、7.3、7.4 和 8.0" class="stamp" src="../../../images_www/articles/73/netbeans-stamp-80-74-73.png" title="此页上的内容适用于 NetBeans IDE 7.2、7.3、7.4 和 8.0">
<p><a href="http://jcp.org/en/jsr/detail?id=299">JSR-299</a> 指定的上下文和依赖关系注入 (CDI) 是 Java EE 6 的一个组成部分,提供了一个体系结构,以允许 Java EE 组件(例如 Servlet、企业 Bean 和 JavaBeans)在具有明确定义范围的应用程序生命周期内存在。此外,CDI 服务允许 Java EE 组件(例如 EJB 会话 Bean 和 JavaServer Faces (JSF) 受管 Bean)注入并通过触发和观察事件以松散耦合的方式进行交互。</p>
<p>本教程基于 Andy Gibson 发布的博客,标题为:<a href="http://www.andygibson.net/blog/index.php/2009/12/22/getting-started-with-cdi-part-2-injection/">CDI 入门指南,第 2 部分 - 注入</a>。本教程演示如何使用 <code>@Alternative</code> 标注配置应用程序用于不同的部署,还将演示如何使用受管 Bean 生命周期标注(例如,<code>@PostConstruct</code><code>@PreDestroy</code>)将 CDI 注入和 <a href="http://jcp.org/en/jsr/detail?id=316">Java EE 6 受管 Bean 规范</a>提供的功能结合起来。</p>
<p>NetBeans IDE 为上下文和依赖关系注入提供了内置支持,包括在项目创建时构建 <code>beans.xml</code> CDI 配置文件的选项,为标注提供的编辑器和导航支持,以及用于创建常用 CDI 工件的各种向导。</p>
<br style="clear:left;">
<div class="indent">
<p>要学完本教程,您需要具备以下软件和资源。</p>
<table id="requiredSoftware">
<tbody>
<tr>
<th class="tblheader" scope="col">软件或资源</th>
<th class="tblheader" scope="col">要求的版本</th>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td>
<td class="tbltd1">7.2、7.3、7.4、8.0、Java EE 版本</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">Java 开发工具包 (JDK)</a></td>
<td class="tbltd1">版本 7 或 8</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://glassfish.dev.java.net/">GlassFish Server</a></td>
<td class="tbltd1">Open Source Edition 3.x 或 4.x</td>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo2.zip">cdiDemo2.zip</a></td>
<td class="tbltd1">N/A</td>
</tr>
</tbody>
</table>
<p class="notes"><strong>注:</strong></p>
</div>
<ul>
<li>NetBeans IDE Java 包中还含 GlassFish Server Open Source Edition,后者是与 Java EE 兼容的容器。</li>
<li>可以下载本教程的解决方案样例项目:<a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo3.zip">cdiDemo3.zip</a></li>
</ul>
<br>
<h2 id="alternative">处理多个部署</h2>
<p>CDI 提供 <code>@Alternative</code> 标注,通过该标注可以包含与注入点匹配的多个 Bean 而不会出现多义性错误。换句话说,可以将 <code>@Alternative</code> 标注应用至两个或多个 Bean,然后,根据部署指定要在 CDI 的 <code>beans.xml</code> 配置文件中使用的 Bean。</p>
<p>为演示此情况,请参见下面的方案。我们将 <code>ItemValidator</code> 注入 <code>ItemProcessor</code> 主类。<code>ItemValidator</code><code>DefaultItemValidator</code><code>RelaxedItemValidator</code> 实现。根据部署要求,在大多数情况下我们会使用 <code>DefaultItemValidator</code>,但在特定部署中,还需要 <code>RelaxedItemValidator</code>。为解决此问题,我们对两个 Bean 添加标注,然后通过向应用程序的 <code>beans.xml</code> 文件添加条目,指定给定部署要使用的 Bean。</p>
<div class="indent">
<img alt="此 CDI 图显示了在本练习中创建的对象" class="margin-around" src="../../../images_www/articles/73/javaee/cdi-validate/cdi-diagram-alternative.png" title="在应用程序中使用 CDI 注入对类进行松散耦合">
</div>
<ol>
<li>首先,从 <code>cdiDemo2.zip</code> 文件提取样例启动项目(请参见上面的<a href="#requiredSoftware">所需资源列表</a>)。在 IDE 中打开项目,方法是选择 "File"(文件)> "Open Project"(打开项目)(Ctrl-Shift-O 组合键;在 Mac 上为 ⌘-Shift-O 组合键),然后从计算机上的相应位置选择该项目。</li>
<li>右键单击“项目”窗口中的项目节点,然后选择“属性”。</li>
<li>选择 "Run"(运行)类别,并确认在 "Server"(服务器)下拉列表中选定 GlassFish 实例。 </li>
<li>创建 <code>ItemValidator</code> 接口。<br><br> 单击 "New File"(新建文件)(<img alt="&quot;New File&quot;(新建文件)按钮" src="../../../images_www/articles/73/javaee/cdi-common/new-file-btn.png">) 按钮,或者按 Ctrl-N 组合键(在 Mac 上为 ⌘-N 组合键)以打开文件向导。</li>
<li>选择 "Java" 类别,然后选择 "Java Interface"(Java 接口)。单击 "Next"(下一步)。</li>
<li>键入 <strong>ItemValidator</strong> 作为类名,然后输入 <strong>exercise3</strong> 作为包。</li>
<li>单击 "Finish"(完成)。将会生成新接口并在编辑器中将其打开。</li>
<li>添加名为 <code>isValid()</code> 的方法,以提取 <code>Item</code> 对象并返回 <code>boolean</code> 值。
<pre class="examplecode">
public interface ItemValidator {
<strong>boolean isValid(Item item);</strong>
}</pre>
(使用编辑器的提示为 <code>exercise2.Item</code> 添加 import 语句。)</li>
<li>扩展 <code>ItemProcessor</code> 类以包含新功能。在编辑器中打开 <code>ItemProcessor</code>,并进行以下更改。
<pre class="examplecode">
@Named
@RequestScoped
public class ItemProcessor {
@Inject @Demo
private ItemDao itemDao;
<strong>@Inject
private ItemValidator itemValidator;</strong>
public void execute() {
List&lt;Item&gt; items = itemDao.fetchItems();
for (Item item : items) {
System.out.println(<strong>&quot;Item = &quot; + item + &quot; valid = &quot; + itemValidator.isValid(item)</strong>);
}
}
}</pre>
<p class="tips">使用编辑器的提示为 <code>exercise3.ItemValidator</code> 添加 import 语句。</p></li>
<li>创建一个 <code>ItemValidator</code> 实现,名为 <code>DefaultItemValidator</code>,该实现根据值简单地对 limit 进行测试。
<p>
在 "Projects"(项目)窗口中,右键单击 <code>exercise3</code> 包,并选择 "New"(新建)> "Java Class"(Java 类)。将该类命名为 <strong>DefaultItemValidator</strong>,然后单击 "Finish"(完成)。</p></li>
<li><code>DefaultItemValidator</code> 实现 <code>ItemValidator</code> 并覆盖 <code>isValid()</code> 方法,如下所示。
<pre class="examplecode">
public class DefaultItemValidator <strong>implements ItemValidator</strong> {
<strong>@Override
public boolean isValid(Item item) {
return item.getValue() &lt; item.getLimit();
}</strong>
}</pre>
<p>(使用编辑器的提示为 <code>exercise2.Item</code> 添加 import 语句。)</p></li>
<li>在 IDE 的主工具栏中单击 "Run Project"(运行项目)(<img alt="&quot;Run Project&quot;(运行项目)按钮" src="../../../images_www/articles/73/javaee/cdi-common/run-project-btn.png">) 按钮。编译该项目并将其部署到 GlassFish,然后在浏览器中打开应用程序的欢迎页 (<code>process.xhtml</code>)。</li>
<li>单击页面上显示的 <code>Execute</code> 按钮。切换回 IDE 并检查 GlassFish Server 日志。服务器日志会显示在 "Output"(输出)窗口(Ctrl-4 组合键;在 Mac 上为 ⌘-4 组合键)中 "GlassFish" 标签的下方。然后会看到验证项,并列出唯一一个值小于 limit 的有效项。
<pre class="examplecode">
INFO: Item = exercise2.Item@e857ac [Value=34, Limit=7] valid = false
INFO: Item = exercise2.Item@63124f52 [Value=4, Limit=37] valid = true
INFO: Item = exercise2.Item@4715c34e [Value=24, Limit=19] valid = false
INFO: Item = exercise2.Item@65c95a57 [Value=89, Limit=32] valid = false</pre>
<img alt="&quot;Output&quot;(输出)窗口 - GlassFish Server 日志" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-validate/output-window.png" title="在 &quot;Output&quot;(输出)窗口中查看服务器日志"></li>
<li>现在,请考虑以下情况,假定您必须部署到另一个更松散的站点,且仅当项值大于 limit 的两倍时,才将该项视为无效。您可能需要使用另一个 Bean 为该逻辑实现 <code>ItemValidator</code> 接口。
<p>
创建一个新的 <code>ItemValidator</code> 实现,名为 <code>RelaxedItemValidator</code>。在 "Projects"(项目)窗口中,右键单击 <code>exercise3</code> 包,并选择 "New"(新建)> "Java Class"(Java 类)。将该类命名为 <strong>RelaxedItemValidator</strong>,然后单击 "Finish"(完成)。</p></li>
<li><code>RelaxedItemValidator</code> 实现 <code>ItemValidator</code> 并覆盖 <code>isValid()</code> 方法,如下所示。
<pre class="examplecode">
public class RelaxedItemValidator <strong>implements ItemValidator</strong> {
<strong>@Override
public boolean isValid(Item item) {
return item.getValue() &lt; (item.getLimit() * 2);
}</strong>
}</pre>
<p>(使用编辑器的提示为 <code>exercise2.Item</code> 添加 import 语句。)</p></li>
<li>单击 "Run Project"(运行项目)(<img alt="&quot;Run Project&quot;(运行项目)按钮" src="../../../images_www/articles/73/javaee/cdi-common/run-project-btn.png">) 按钮以运行项目。请注意,项目现在无法部署。</li>
<li>在 "Output"(输出)窗口(Ctrl-4 组合键;在 Mac 上为 ⌘-4 组合键)中查看服务器日志。您会看到一则错误消息,报告 "ambiguous dependency"(依赖关系不明确)问题。出现此错误的原因是,您现在有两个实现同一接口的类。
<pre class="examplecode">
org.glassfish.deployment.common.DeploymentException: Injection point has ambiguous dependencies.
Injection point: field exercise2.ItemProcessor.itemValidator;
Qualifiers: [@javax.enterprise.inject.Default()];
Possible dependencies: [exercise3.RelaxedItemValidator, exercise3.DefaultItemValidator]</pre>
<p>Weld(CDI 实现)无法确定对给定注入点使用 <code>RelaxedItemValidator</code> 还是使用 <code>DefaultItemValidator</code></p>
<p>
如前面所述,唯一的区别在于部署。对于大多数部署,需要使用默认验证器,但对于一个部署,需要使用 "relaxed" 实现。CDI 提供 <code>@Alternative</code> 标注,通过该标注可以包含与一个注入点匹配的多个 Bean 而不会出现多义性错误,且要使用的 Bean 在 <code>beans.xml</code> 中定义。这允许您在同一模块中部署这两个实现,唯一的差别在于 <code>beans.xml</code> 的定义,该定义可以根据不同的部署进行更改。</p></li>
<li><code>@Alternative</code> 标注和相应的 import 语句添加至 <code>RelaxedItemValidator</code><code>DefaultItemValidator</code><br><br> 在编辑器中打开 <code>RelaxedItemValidator</code> 并进行以下更改。
<pre class="examplecode">
<strong>import javax.enterprise.inject.Alternative;</strong>
...
<strong>@Alternative</strong>
public class RelaxedItemValidator implements ItemValidator {
public boolean isValid(Item item) {
return item.getValue() &lt; (item.getLimit() * 2);
}
}</pre>
<p class="tips">键入 <code>Al</code>,然后按 Ctrl-空格组合键以调用代码完成。因为仅过滤了一个选项,将完成 <code>@Alternative</code> 标注,<code>javax.enterprise.inject.Alternative</code> 相应的 import 语句会自动添加到文件顶部。通常情况下,在标注上按 Ctrl-空格组合键还会提供 Javadoc 文档弹出窗口。</p>
<img alt="编辑器中的 Javadoc 文档弹出式窗口" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-validate/code-completion-alternative.png" title="在标注时按 Ctrl-空格组合键可调用 Javadoc 文档">
<p>
切换至 <code>DefaultItemValidator</code>(按 Ctrl-Tab 组合键)并进行以下更改。</p>
<pre class="examplecode">
<strong>import javax.enterprise.inject.Alternative;</strong>
...
<strong>@Alternative</strong>
public class DefaultItemValidator implements ItemValidator {
public boolean isValid(Item item) {
return item.getValue() &lt; item.getLimit();
}
}</pre>
<p>如果现在部署了应用程序,则会收到 "unsatisfied dependency"(不符合要求的依赖关系)错误,因为您定义了两个匹配的 Bean 作为替代项,但是没有在 <code>beans.xml</code> 文件中启用这两个文件中的任何一个。</p></li>
<li>使用 IDE 的 "Go to File"(转至文件)对话框快速打开 <code>beans.xml</code> 文件。从 IDE 的主菜单(Alt-Shift-O;在 Mac 上为 Ctrl-Shift-O)选择 "Navigate"(导航)> "Go to File"(转至文件),然后键入 "<code>beans</code>"。单击 "OK"(确定)。<img alt="&quot;Go to File&quot;(转至文件)对话框" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-validate/go-to-file.png" title="使用 &quot;Go to File&quot;(转至文件)对话框可快速找到项目文件"></li>
<li><code>beans.xml</code> 文件进行如下更改。
<pre class="examplecode">
&lt;beans xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd&quot;&gt;
<strong>&lt;alternatives&gt;
&lt;class&gt;exercise3.RelaxedItemValidator&lt;/class&gt;
&lt;/alternatives&gt;</strong>
&lt;/beans&gt;</pre>
<p>这会通知 CDI 使用 <code>RelaxedItemValidator</code> 进行此部署。可以认为 <code>@Alternative</code> 标注有效禁用了 Bean,使其不能用于注入,但是允许该实现与其他 Bean 一起打包。在 <code>beans.xml</code> 文件中将其添加为替代项可有效地重新启用该 Bean,使其可用于注入。通过将此类型的元数据移动至 <code>beans.xml</code> 文件,可以将不同版本的文件与不同部署一起打包。</p></li>
<li>单击 "Run Project"(运行项目)(<img alt="&quot;Run Project&quot;(运行项目)按钮" src="../../../images_www/articles/73/javaee/cdi-common/run-project-btn.png">) 按钮以运行项目(或者,按 F6 键;在 Mac 上按 fn-F6 组合键)。在浏览器中,单击页面上显示的 "<code>Execute</code>" 按钮。切换回 IDE 并查看 "Output"(输出)窗口(Ctrl-4 组合键,在 Mac 上为 ⌘-4 组合键)中显示的 GlassFish Server 日志。
<pre class="examplecode">
INFO: Item = exercise2.Item@672f0924 [Value=34, Limit=7] valid = false
INFO: Item = exercise2.Item@41014f68 [Value=4, Limit=37] valid = true
INFO: Item = exercise2.Item@3d04562f [Value=24, Limit=19] valid = true
INFO: Item = exercise2.Item@67b646f4 [Value=89, Limit=32] valid = false</pre>
<p>您会看到,当第三项显示为有效而提供的值 (<code>24</code>) 大于给定 limit (<code>19</code>) 时,会使用 <code>RelaxedItemValidator</code> 实现。</p></li>
</ol>
<br>
<h2 id="lifecycle">将生命周期标注应用于受管 Bean</h2>
<p>在此示例中,将 <code>ItemErrorHandler</code> 注入到主 <code>ItemProcessor</code> 类。因为 <code>FileErrorReporter</code><code>ItemErrorHandler</code> 接口的唯一实现,所以会选中它作为接口。要为此类设置生命周期特定的操作,请从受管 Bean 规范(包含在 <a href="http://jcp.org/en/jsr/detail?id=316">JSR 316:Java Platform, Enterprise Edition 6 规范</a>)使用 <code>@PostConstruct</code><code>@PreDestroy</code> 标注。</p>
<div class="indent">
<img alt="此 CDI 图显示了在本练习中创建的对象" class="margin-around" src="../../../images_www/articles/73/javaee/cdi-validate/cdi-diagram-lifecycle.png" title="在应用程序中使用 CDI 注入对类进行松散耦合">
</div>
<p>继续执行本示例,创建 <code>ItemErrorHandler</code> 接口以在发现无效的项时对其进行处理。</p>
<ol>
<li>在 "Projects"(项目)窗口中,右键单击 <code>exercise3</code> 包,然后选择 "New"(新建)> "Java Interface"(Java 接口)。</li>
<li>在 Java 接口向导中,键入 <strong>ItemErrorHandler</strong> 作为类名,然后输入 <strong>exercise3</strong> 作为包。单击 "Finish"(完成)。
<p>将会生成新接口并在编辑器中将其打开。</p></li>
<li>添加名为 <code>handleItem()</code> 的方法,该方法将 <code>Item</code> 对象作为参数。
<pre class="examplecode">
public interface ItemErrorHandler {
<strong>void handleItem(Item item);</strong>
}</pre>
<p>(使用编辑器的提示为 <code>exercise2.Item</code> 添加 import 语句。)</p></li>
<li>首先,使用名为 <code>FileErrorReporter</code> 的伪处理程序(该程序将项详细信息保存至文件)实现 <code>ItemErrorHandler</code>
<p>
在 "Projects"(项目)窗口中,右键单击 <code>exercise3</code> 包,并选择 "New"(新建)> "Java Class"(Java 类)。将该类命名为 <strong>FileErrorReporter</strong>,然后单击 "Finish"(完成)。</p></li>
<li><code>FileErrorReporter</code> 实现 <code>ItemErrorHandler</code> 并覆盖 <code>handleItem()</code> 方法,如下所示。
<pre class="examplecode">
public class FileErrorReporter <strong>implements ItemErrorHandler</strong> {
<strong>@Override
public void handleItem(Item item) {
System.out.println(&quot;Saving &quot; + item + &quot; to file&quot;);
}</strong>
}</pre>
<p>(使用编辑器的提示为 <code>exercise2.Item</code> 添加 import 语句。)</p>
<p>
您需要在开始处理项之前打开文件,并在向文件添加内容的过程中使其保持打开状态,然后在完成处理时关闭文件。您可以手动将 <code>initProcess()</code><code>finishProcess()</code> 方法添加到错误报告程序 Bean,但之后无法向接口添加代码,因为调用程序需要知道这些类特定的方法。您可以将以上这些方法添加到 <code>ItemErrorReporter</code> 接口,但之后必须在实现该接口的每个类中实现这些方法,这就产生了不必要的操作。不过,您可以使用受管 Bean 规范(<a href="http://jcp.org/en/jsr/detail?id=316">JSR 316:Java 平台 Enterprise Edition 6 规范</a>中包含)中的一些生命周期标注,在 Bean 生命周期中的某些时点对 Bean 调用方法。当已经构造了 Bean 且 Bean 的任何依赖关系都已注入时,则调用 <code>@PostConstruct</code> 标注的方法。同样,容器会在处理 Bean 之前调用 <code>@PreDestroy</code> 标注的方法。</p></li>
<li>添加以下带有相应 <code>@PostConstruct</code><code>@PreDestroy</code> 标注的 <code>init()</code><code>release()</code> 方法。
<pre class="examplecode">
public class FileErrorReporter implements ItemErrorHandler {
<strong>@PostConstruct
public void init() {
System.out.println(&quot;Creating file error reporter&quot;);
}
@PreDestroy
public void release() {
System.out.println(&quot;Closing file error reporter&quot;);
}</strong>
@Override
public void handleItem(Item item) {
System.out.println(&quot;Saving &quot; + item + &quot; to file&quot;);
}
}</pre></li>
<li>修复导入。在编辑器中右键单击并选择 "Fix Imports"(修复导入),或者按 Ctrl-Shift-I 组合键(在 Mac 上按 ⌘-Shift-I 组合键)。<code>javax.annotation.PostConstruct</code><code>javax.annotation.PreDestroy</code> 的 Import 语句将添加到文件顶部。</li>
<li>最后,向 <code>ItemProcessor</code> 添加 <code>ItemErrorHandler</code> Bean。
<pre class="examplecode">
@Named
@RequestScoped
public class ItemProcessor {
@Inject @Demo
private ItemDao itemDao;
@Inject
private ItemValidator itemValidator;
<strong>@Inject
private ItemErrorHandler itemErrorHandler;</strong>
public void execute() {
List&lt;Item&gt; items = itemDao.fetchItems();
for (Item item : items) {
<strong>if (!itemValidator.isValid(item)) {
itemErrorHandler.handleItem(item);
}</strong>
}
}
}</pre>
<p>(使用编辑器的提示为 <code>exercise3.ItemErrorHandler</code> 添加 import 语句。)</p>
</li>
<li>单击 "Run Project"(运行项目)(<img alt="&quot;Run Project&quot;(运行项目)按钮" src="../../../images_www/articles/73/javaee/cdi-common/run-project-btn.png">) 按钮以运行项目(或者,按 F6 键;在 Mac 上按 fn-F6 组合键)。在浏览器中,单击页面上显示的 "<code>Execute</code>" 按钮。切换回 IDE 并查看 "Output"(输出)窗口(Ctrl-4 组合键,在 Mac 上为 ⌘-4 组合键)中显示的 GlassFish Server 日志。
<pre class="examplecode">
INFO: Creating file error reporter
INFO: Saving exercise2.Item@6257d812 [Value=34, Limit=7] to file
INFO: Saving exercise2.Item@752ab82e [Value=89, Limit=32] to file
INFO: Closing file error reporter</pre>
</li>
</ol>
<div class="feedback-box">
<a href="/about/contact_form.html?to=3&amp;subject=Feedback:%20Using%20CDI%20Injection%20to%20Perform%20Custom%20Validation">发送有关此教程的反馈意见</a>
</div>
<br style="clear:both;">
<h2 id="seealso">另请参见</h2>
<p>不同的应用程序部署会使用不同的规则来处理无效项,例如拒绝项、向个人发送通知、为其添加标记、或者仅在输出文件中列出它们。此外,我们可能需要结合使用这些项(例如,拒绝订单、向销售代表发送电子邮件以及在文件中列出订单)。处理此类多方面问题的一个最佳方式是使用<em>事件</em>。本系列最后一部分的主题是 CDI 事件:</p>
<ul>
<li><a href="cdi-events.html">使用 CDI 中的事件</a></li>
</ul>
<p>有关 CDI 和 Java EE 的详细信息,请参见以下资源。</p>
<ul>
<li><a href="cdi-intro.html">上下文和依赖关系注入以及 JSF 2.0 入门指南</a></li>
<li><a href="cdi-inject.html">使用 CDI 中的注入和限定符</a></li>
<li><a href="javaee-gettingstarted.html">Java EE 应用程序入门指南</a></li>
<li><a href="http://blogs.oracle.com/enterprisetechtips/entry/using_cdi_and_dependency_injection">企业技术提示:在 JSF 2.0 应用程序中使用面向 Java 的 CDI 和依赖关系注入</a></li>
<li><a href="http://download.oracle.com/javaee/6/tutorial/doc/gjbnr.html">Java EE 6 教程第五部分:面向 Java EE 平台的上下文和依赖关系注入</a></li>
<li><a href="http://jcp.org/en/jsr/detail?id=299">JSR 299:上下文和依赖关系注入规范</a></li>
<li><a href="http://jcp.org/en/jsr/detail?id=316">JSR 316:Java Platform、Enterprise Edition 6 规范</a></li>
</ul>
</body>
</html>