| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| <html> |
| <head> |
| <title>上下文和依赖关系注入以及 JSF 2.x 入门指南 - NetBeans IDE 教程</title> |
| <meta http-equiv="content-type" content="text/html; charset=UTF-8"> |
| <meta name="description" content="A demonstration of how to set up a JSF 2.0 project with CDI support in NetBeans IDE"> |
| <meta name="keywords" content="NetBeans, IDE, integrated development environment, JSF 2.0, JavaServer Faces, |
| Contexts and Dependency Injection, CDI, Web Beans"> |
| |
| <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>上下文和依赖关系注入以及 JSF 2.x 入门</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><strong>CDI 和 JSF 2.0 入门指南</strong> |
| |
| <ul style="margin: 5px 0 0 -2em"> |
| <li><a href="#creating">创建支持 CDI 的 Java Web 项目</a></li> |
| <li><a href="#named">从 JSF 的表达式语言访问 Bean</a></li> |
| <li><a href="#upgrading">升级到 EJB</a></li> |
| <li><a href="#seealso">另请参见</a></li> |
| </ul></li> |
| |
| <li><a href="cdi-inject.html">使用 CDI 中的注入和限定符</a></li> |
| <li><a href="cdi-validate.html">应用 @Alternative Bean 和生命周期标注</a></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/16/getting-started-with-jsf-2-0-and-cdi-in-jee-6-part-1/">JSF 2.0 和 JEE 6 中的 CDI 入门</a>。本教程演示如何使用 IDE 设置支持 JSF 2.0 和 CDI 的 Java Web 项目。本教程还继续演示如何连接 CDI 受管 Bean 和 Facelets 页,并在末尾提供了 CDI 与 EJB 技术集成的简短示例。</p> |
| |
| <p>NetBeans IDE 为上下文和依赖关系注入提供了内置支持,包括在项目创建时构建 <code>beans.xml</code> CDI 配置文件的选项,为标注提供的编辑器和导航支持,以及用于创建常用 CDI 工件的各种向导。</p> |
| |
| <br style="clear:left;"> |
| |
| <div class="indent"> |
| <p>要学完本教程,您需要具备以下软件和资源。</p> |
| |
| <table> |
| <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> |
| </tbody> |
| </table> |
| |
| <p class="notes"><strong>注:</strong></p> |
| </div> |
| |
| <ul> |
| <li>NetBeans IDE Java 包中还含 GlassFish Server Open Source Edition,后者是与 Java EE 兼容的容器。</li> |
| </ul> |
| |
| |
| <br> |
| <h2 id="creating">创建支持 CDI 的 Java Web 项目</h2> |
| |
| <p>在本练习中,将创建一个启用了 JSF 2.x 且支持 CDI 的 Java Web 项目。</p> |
| |
| <ol> |
| <li>在 IDE 的主工具栏中单击 "New Project"(新建项目)(<img alt=""New Project"(新建项目)按钮" src="../../../images_www/articles/73/javaee/cdi-intro/new-project-btn.png">) 按钮(Ctrl-Shift-N 组合键;在 Mac 上为 ⌘-Shift-N 组合键)。</li> |
| |
| <li>在新建项目向导,选择 "Java Web" 类别,然后选择 "Web Application"(Web 应用程序)。单击 "Next"(下一步)。</li> |
| |
| <li>键入 <code>cdiDemo</code> 作为项目名称,并设置项目位置。单击 "Next"(下一步)。</li> |
| |
| <li>将服务器设置为 GlassFish Server。</li> |
| <li>将 "Java EE Version"(Java EE 版本)设置为 "Java EE 6 Web" 或 "Java EE 7 Web"。 |
| |
| |
| <p class="notes"><strong>注:</strong>所选的 Java EE 版本确定为应用程序启用的 CDI 版本,并且 CDI 1.0 和 CDI 1.1 之间有一些重要的差异。</p> |
| <div class="indent"> |
| <ul> |
| <li>如果指定 Java EE 6 Web 作为 Java EE 版本,请确认选中了 "Enable Contexts and Dependency Injection"(启用上下文和依赖关系注入)选项。如果选中 "Enable Contexts and Dependency Injection"(启用上下文和依赖关系注入)选项,则创建项目模板时,会在项目的 <code>WEB-INF</code> 文件夹中生成 <code>beans.xml</code> 文件。CDI 使用此 <code>beans.xml</code> 文件指示 Java EE 兼容的服务器,此项目是包含 CDI Bean 的模块。Java EE 6 Web 支持 CDI 1.0,并且生成的 <code>beans.xml</code> 文件指定 CDI 1.0 作为版本。</li> |
| |
| <li>如果指定 Java EE 7 Web 作为 Java EE 版本,则默认情况下会启用 CDI 1.1 并且不需要 <tt>beans.xml</tt> 文件。在 Java EE 7 中,不存在 <tt>beans.xml</tt> 时,部署的档案将为<strong>隐式 Bean 档案</strong>。如果您在 IDE 中使用新建文件向导在 Java EE 7 Web 应用程序中手动生成 <code>beans.xml</code> 文件,则默认情况下部署的档案将成为<strong>显式 Bean 档案</strong>,因为 <code>beans.xml</code> 文件指定 CDI 1.1 作为版本并且还将 <tt>bean-discovery-mode</tt> 的属性设置为 <tt>all</tt>。</li> |
| </ul> |
| <p>有关 CDI 档案类型的详细信息,请参见 Java EE 7 教程中的<a href="http://docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm">打包 CDI 应用程序</a>。</p> |
| </div> |
| <img alt="启用新建 Web 应用程序向导中提供的 CDI 选项" class="margin-around b-all" src="../../../images_www/articles/74/javaee/cdi-intro/new-web-application1.png" title="在选中时为项目生成 beans.xml 文件的 CDI 选项"></li> |
| |
| <li>单击 "Next"(下一步)。</li> |
| |
| <li>在 "Frameworks"(框架)面板中,选择 "JavaServer Faces" 选项。</li> |
| <li>单击 "Configuration"(配置)标签,并确认将 Facelets 选作 "Preferred Page Language"(首选页面语言)。单击 "Finish"(完成)。 |
| |
| <p>单击 "Finish"(完成),此时 IDE 生成 Web 应用程序项目并在编辑器中打开 <code>index.xhtml</code> 欢迎页。</p></li> |
| |
| <li>在 "Projects"(项目)窗口中,展开 "Libraries"(库)> "GlassFish Server" 节点,可以看到自动添加了 <code>weld-osgi-bundle.jar</code> 库。GlassFish Server 包含 Weld,这是 JBoss 的 JSR-299 CDI 规范的实现。 <br /> <img alt="显示在 "Projects"(项目)窗口中的新项目" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-intro/projects-window1.png" title="新项目包含 CDI 的 beans.xml 文件和 GlassFish 库,该库包括 Weld JAR 文件"> |
| |
| <p>如果在创建项目时指定 Java EE 6 Web 作为 Java EE 版本,则会注意到 "Web Pages"(Web 页)> "WEB-INF" 文件夹包含 <code>beans.xml</code> 文件。此文件当前为空,但可用于将 Bean 相关的 XML 信息指定为标注的备用选项。</p> |
| </li> |
| </ol> |
| |
| <h2 id="named">从 JSF 的表达式语言访问 Bean</h2> |
| |
| <p>本练习演示如何使用 EL 语法将 CDI 受管 Bean 连接到 Facelets 页。</p> |
| |
| <ol> |
| <li>在 "Projects"(项目)窗口中,右键单击 "Source Packages"(源包)节点并选择 "New"(新建)> "Java Class"(Java 类)。</li> |
| |
| <li>在新建 Java 类向导中,将类命名为 <strong>MessageServerBean</strong>,并键入 <strong>exercise1</strong> 作为包。(新包在完成向导时创建。)单击 "Finish"(完成)。<br> <img alt="新建 Java 类向导" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-intro/new-java-class.png" title="使用 Java 类向导创建新 Java 类" width="580"> |
| |
| <p>新类和包生成,并在编辑器中打开此类。</p></li> |
| |
| <li>使用 <code>@Named</code> 和 <code>@Dependent</code> 标注对此类进行标注,并创建一个返回字符串的方法。 |
| |
| <pre class="examplecode"> |
| package exercise1; |
| |
| <strong>import javax.enterprise.context.Dependent; |
| import javax.inject.Named;</strong> |
| |
| <strong>@Dependent |
| @Named</strong> |
| public class MessageServerBean { |
| |
| <strong>public String getMessage() { |
| return "Hello World!"; |
| }</strong> |
| }</pre> |
| <p class="tips">键入 <code>@Dependent</code> 和 <code>@Named</code> 标注时,按 Ctrl-空格键可调用编辑器的代码完成支持,以及 Javadoc 文档。如果使用编辑器的代码完成功能应用标注(例如,选择相应的标注,然后按 Enter),<code>import</code> 语句将自动添加到文件中。在 Javadoc 弹出式窗口中,也可以单击 "Show documentation in external web browser"(在外部 Web 浏览器中显示文档)(<img alt=""Show documentation in external web browser"(在外部 Web 浏览器中显示文档)按钮" src="../../../images_www/articles/73/javaee/cdi-intro/external-web-browser-btn.png">) 按钮以在单独的窗口中显示 Javadoc 全图。</p> |
| |
| <p class="notes"><strong>注:</strong><tt>@Dependent</tt> 标注定义受管 Bean 的范围。在 <strong>implicit bean archive</strong>(隐式 Bean 档案)中,仅当指定了范围时,受管 Bean 才可发现并且只能由容器管理。如果在创建项目时指定 Java EE 7 Web 作为 Java EE 版本并且未创建 <tt>beans.xml</tt>,则会将本教程中的应用程序打包为隐式 Bean 档案。有关指定受管 Bean 的范围的详细信息,请参见 Java EE 7 教程中的<a href="http://docs.oracle.com/javaee/7/tutorial/doc/jsf-configure001.htm">使用标注配置受管 Bean</a>。</p> |
| </li> |
| |
| <li>保存文件(Ctrl-S;在 Mac 上为 ⌘-S)。根据 CDI 的定义,通过添加 <code>@Named</code> 标注,<code>MessageServerBean</code> 类成为<em>受管 Bean</em>。</li> |
| |
| <li>在编辑器中切换至 <code>index.xhtml</code> Facelets 页(按 Ctrl-Tab 组合键),然后在 <code><h:body></code> 标记中添加以下内容。 |
| |
| <pre class="examplecode"> |
| <h:body> |
| Hello from Facelets |
| <strong><br/> |
| Message is: #{messageServerBean.message} |
| <br/> |
| Message Server Bean is: #{messageServerBean}</strong> |
| </h:body></pre> |
| |
| <span class="tips">可以在 EL 表达式中按 Ctrl-空格键以使用代码完成建议。编辑器的代码完成列出了受管 Bean 及其属性。因为 <code>@Named</code> 标注将 <code>MessageServerBean</code> 类转换成 CDI 受管 Bean,该 CDI 受管 Bean 与作为 JSF 受管 Bean 时一样,可以在 EL 语法中访问。</span> <br> <img alt="新建 Java 类向导" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-intro/facelets-el-completion.png" title="使用 Java 类向导创建新 Java 类"></li> |
| |
| <li>在 IDE 的主工具栏中单击 "Run Project"(运行项目)(<img alt=""Run Project"(运行项目)按钮" src="../../../images_www/articles/73/javaee/cdi-common/run-project-btn.png">) 按钮。编译该项目并将其部署到 GlassFish,并在浏览器中打开应用程序欢迎页 (<code>index.xhtml</code>)。您将看到来自该页上显示的 <code>MessageServerBean</code> 的 "Hello World!" 消息。 <br> <img alt="显示在浏览器中的欢迎页" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-intro/browser-output1.png" title="应用程序欢迎页显示 MessageServerBean 详细信息"></li> |
| |
| <li>返回至消息 Bean 并将消息更改为其他内容(例如,"Hello Weld!")。保存文件(Ctrl-S 组合键;在 Mac 上为 ⌘-S 组合键),然后刷新浏览器。将自动显示新消息。因为有了 IDE 的“在保存时部署”功能,保存的任何更改都会自动进行编辑并重新部署到服务器。<br><br> 从此页第三行,您可以看到类名为 <code>exercise1.MessageServerBean</code>。请注意,Bean 只是一个 POJO(Plain Old Java Object,简单传统 Java 对象)。即使您现在使用 Java EE 进行开发,事务、拦截器以及重复出现的所有“重型”功能等层中也不会包含复杂的类分层结构。</li> |
| </ol> |
| |
| <div class="indent"> |
| <h3>这是怎么回事?</h3> |
| |
| <p>部署应用程序后,服务器将查找 CDI 受管 Bean。在 Java EE 7 应用程序中,默认情况下将扫描路径上的类是否有 CDI 标注。在 Java EE 6 应用程序中,如果模块包含 <code>beans.xml</code> 文件,则将扫描类是否有 CDI 标注。在 CDI 模块中,所有 Bean 会在 Weld 中注册,并使用 <code>@Named</code> 标注将 Bean 与注入点匹配。当呈现 <code>index.xhtml</code> 页时,JSF 会尝试使用 JSF 中注册的表达式解析器来解析本页中的 <code>messageServerBean</code> 值。其中一个解析器是 Weld EL 解析器,它以名称 <code>messageServerBean</code> 注册了 <code>MessageServerBean</code> 类。本可以使用 <code>@Named</code> 标注指定一个不同的名称,但是我们并没有这样做,因此它是以默认名称注册的,且类名的首字母为小写。Weld 解析器返回此 Bean 的实例以响应来自 JSF 的请求。Bean 命名仅在使用 EL 表达式时需要,且不应作为注入机制使用,因为 CDI 提供了按类类型和限定符标注的类型安全的注入。</p> |
| </div> |
| |
| |
| <br> |
| <h2 id="upgrading">升级到 EJB</h2> |
| |
| <p>由于有 EJB 3.1,即使现在使用的是 Java EE 堆栈,也只需进行小幅改动,即可轻松将 Bean 部署为 EJB。</p> |
| |
| <ol> |
| <li>打开 <code>MessageServerBean</code>,并在类级别添加 <code>javax.ejb.Stateless</code> 标注,然后将字符串更改为 "Hello EJB!"。 |
| |
| <pre class="examplecode"> |
| package exercise1; |
| |
| <strong>import javax.ejb.Stateless;</strong> |
| import javax.enterprise.context.Dependent; |
| import javax.inject.Named; |
| |
| /** |
| * |
| * @author nbuser |
| */ |
| @Dependent |
| @Named |
| <strong>@Stateless</strong> |
| public class MessageServerBean { |
| |
| public String getMessage() { |
| return "<strong>Hello EJB!</strong>"; |
| } |
| }</pre></li> |
| |
| <li>保存文件(Ctrl-S 组合键;在 Mac 上为 ⌘-S 组合键),然后转到浏览器并刷新。将看到类似于以下内容的输出: <br> <img alt="显示在浏览器中的 EJB 详细信息" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-intro/browser-output-ejb1.png" title="使用 @Stateless 标注将 MessageServerBean 转换为 EJB"> <br> 太奇妙了,只需一个标注即可将 POJO 转换为功能完善的 EJB。保存更改并刷新页面以后,即可显示更改。通过执行此操作,不需要创建任何古怪的项目配置、本地接口或深奥的部署描述符。</li> |
| </ol> |
| |
| <div class="indent"> |
| <h3>不同的 EJB 类型</h3> |
| |
| <p>还可以尝试使用 <code>@Stateful</code> 标注。或者,您可以尝试对 singleton 实例使用新的 <code>@Singleton</code> 标注。如果执行此操作,会注意到其中存在两个标注:<code>javax.ejb.Singleton</code> 和 <code>javax.inject.Singleton</code>。为什么存在两个 singletons 标注?如果是在非 EJB 环境中使用 CDI,通过 CDI singleton (<code>javax.inject.Singleton</code>) 可以在 EJB 外定义 singleton 实例。EJB singleton (<code>javax.ejb.Singleton</code>) 提供了 EJB 的所有功能,例如事务管理。因此,您可以根据需要以及是否使用的是 EJB 环境来进行选择。</p> |
| </div> |
| |
| |
| <div class="feedback-box"> |
| <a href="/about/contact_form.html?to=3&subject=Feedback:%20Getting%20Started%20with%20CDI%20and%20JSF%202.0">发送有关此教程的反馈意见</a> |
| </div> |
| |
| <br style="clear:both;"> |
| |
| |
| <h2 id="seealso">另请参见</h2> |
| |
| <p>本系列的下一部分重点介绍 CDI 注入,并详细讲解在 Java EE 环境中使用 CDI 管理依赖关系。</p> |
| |
| <ul> |
| <li><a href="cdi-inject.html">使用 CDI 中的注入和限定符</a></li> |
| </ul> |
| |
| <p>有关 CDI 和 JSF 2.0 的详细信息,请参见以下资源。</p> |
| |
| <div class="indent"> |
| <h3>上下文和依赖关系注入</h3> |
| |
| <ul> |
| <li><a href="cdi-validate.html">应用 @Alternative Bean 和生命周期标注</a></li> |
| <li><a href="cdi-events.html">使用 CDI 中的事件</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://docs.oracle.com/javaee/7/tutorial/doc/cdi-basic.htm">Java EE 6 教程:面向 Java EE 的上下文和依赖关系注入简介</a></li> |
| <li><a href="http://jcp.org/en/jsr/detail?id=299">JSR 299:上下文和依赖关系注入规范</a></li> |
| </ul> |
| |
| <h3>JavaServer Faces 2.0</h3> |
| |
| <ul> |
| <li><a href="../web/jsf20-intro.html">JavaServer Faces 2.x 简介</a></li> |
| <li><a href="../web/jsf20-crud.html">通过数据库生成 JavaServer Faces 2.x CRUD 应用程序</a></li> |
| <li><a href="../../samples/scrum-toys.html">Scrum 玩具 - JSF 2.0 完整样例应用程序</a></li> |
| <li><a href="http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html">JavaServer Faces 技术</a>(官方主页)</li> |
| <li><a href="http://docs.oracle.com/javaee/7/tutorial/doc/jsf-page.htm">Java EE 7 教程:在 Web 页中使用 JavaServer Faces 技术</a></li> |
| <li><a href="http://jcp.org/en/jsr/summary?id=314">JSR 314:JavaServer Faces 2.0 的规范</a></li> |
| </ul> |
| </div> |
| </body> |
| </html> |