简介:JavaEE 6 API帮助文档是Java企业级开发的重要参考资料,全面涵盖Servlet 3.0、JSP 2.2、EJB 3.1、JSF 2.0、CDI 1.0、JPA 2.0、JMS 2.0、JAX-RS 1.1、WebSocket 1.0、JAX-WS 2.2等关键技术的API说明。文档采用CHM格式,便于快速查阅和学习。通过该文档,开发者可以深入理解JavaEE 6平台的核心功能,掌握企业级应用开发的规范与实践,提升开发效率与代码质量。
1. JavaEE 6平台概述
JavaEE 6作为企业级Java开发的重要里程碑版本,标志着Java平台在企业级应用开发中迈向更标准化、模块化与轻量化的方向。它不仅引入了如CDI(Contexts and Dependency Injection)这样的核心依赖注入规范,还对EJB、JSF、JPA等关键模块进行了显著增强,提升了开发效率与系统可维护性。
从架构层面来看,JavaEE 6通过清晰的模块划分,使开发者能够根据项目需求灵活选择所需组件,避免了过度依赖与资源浪费。其标准化API的设计理念,使得企业应用在不同应用服务器之间具备良好的可移植性。
本章将深入探讨JavaEE 6的版本演进背景、核心模块结构及其在现代企业应用中的定位,为后续章节对Servlet、JSP、EJB、JSF与CDI等技术的详细解析奠定基础。
2. Servlet 3.0注解配置与异步处理
在现代企业级Java Web应用开发中,Servlet 3.0作为JavaEE 6平台的重要组成部分,带来了诸多关键性的新特性,极大地简化了开发流程并提升了应用性能。本章将围绕 Servlet 3.0的注解配置机制 与 异步请求处理能力 展开深入探讨,帮助开发者掌握如何构建高效、可扩展的Web服务。
2.1 Servlet 3.0的新特性概述
Servlet 3.0 是 JavaEE 6 规范中的重要一环,它引入了多个关键特性,旨在提升 Web 开发效率和系统响应能力。
2.1.1 注解驱动的配置机制
传统的 Servlet 开发需要依赖 web.xml
文件进行 URL 映射、过滤器和监听器的配置。这种方式虽然稳定,但在模块较多、配置复杂的情况下,容易变得冗长且难以维护。
Servlet 3.0 引入了注解驱动的配置机制,通过 Java 注解的方式替代 XML 配置,使得代码更简洁、模块更独立。
核心注解包括:
注解 | 功能 |
---|---|
@WebServlet | 标记一个类为 Servlet 并指定 URL 映射 |
@WebFilter | 标记一个类为过滤器 |
@WebListener | 标记一个类为监听器 |
@MultipartConfig | 配置上传文件处理的参数 |
这种注解机制不仅减少了 XML 的配置负担,也使得代码更具可读性和可维护性。
2.1.2 异步处理支持与线程管理
Servlet 3.0 最具革命性的改进之一是引入了异步处理机制。传统的 Servlet 请求处理是同步阻塞的,即每个请求都会占用一个线程直到处理完成。在高并发场景下,这可能导致线程资源耗尽。
通过 AsyncContext
接口,Servlet 3.0 支持异步非阻塞处理请求,释放线程资源,提升服务器吞吐量。
异步处理的优势包括:
- 线程复用 :请求进入后立即释放容器线程,由业务线程异步处理。
- 提高并发能力 :减少线程池的占用,避免线程阻塞。
- 改善响应延迟 :长时间任务(如远程调用)不会阻塞主线程。
2.2 注解配置详解
2.2.1 @WebServlet、@WebFilter与@WebListener的应用
示例:使用 @WebServlet
定义一个简单的 Servlet
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
try {
res.getWriter().write("Hello, Servlet 3.0!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
逐行解读与参数说明:
-@WebServlet("/hello")
:将当前类注册为一个 Servlet,并映射到/hello
路径。
-HttpServlet
:继承标准 HttpServlet 类,实现 doGet/doPost 方法。
-res.getWriter()
:获取响应输出流,向客户端写入数据。
示例:使用 @WebFilter
实现请求过滤器
@WebFilter("/*")
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Request received: " + ((HttpServletRequest) request).getRequestURI());
chain.doFilter(request, response);
System.out.println("Response sent.");
}
}
逐行解读与参数说明:
-@WebFilter("/*")
:表示该过滤器拦截所有请求路径。
-FilterChain chain
:过滤器链,用于继续请求处理。
-chain.doFilter(...)
:将请求传递给下一个过滤器或目标资源。
示例:使用 @WebListener
监听会话创建与销毁
@WebListener
public class SessionCounterListener implements HttpSessionListener {
private static int activeSessions = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
activeSessions++;
System.out.println("Session created, total: " + activeSessions);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
activeSessions--;
System.out.println("Session destroyed, total: " + activeSessions);
}
}
逐行解读与参数说明:
-@WebListener
:标记为监听器,自动注册到容器中。
-HttpSessionListener
:用于监听 HTTP 会话的创建与销毁事件。
-HttpSessionEvent se
:封装会话事件的上下文信息。
2.2.2 零配置部署与web.xml的简化
在 Servlet 3.0 中,如果项目中不使用传统的 XML 配置,可以直接使用注解驱动的方式完成部署,实现“零配置”部署。
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
</web-app>
说明:
- 只需声明version="3.0"
,即可启用注解驱动配置。
- 无需手动注册 Servlet、Filter 和 Listener,只需使用相应注解即可。
2.3 异步请求处理机制
2.3.1 AsyncContext的使用方式
Servlet 3.0 引入了 AsyncContext
接口,允许将请求处理从主线程中分离出来,交由其他线程进行处理,从而释放容器线程资源。
示例:使用 AsyncContext 实现异步处理
@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
final AsyncContext asyncContext = req.startAsync();
new Thread(() -> {
try {
Thread.sleep(3000); // 模拟耗时任务
asyncContext.getResponse().getWriter().write("Async response after 3s");
asyncContext.complete();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
逐行解读与参数说明:
-@WebServlet(..., asyncSupported = true)
:启用异步支持。
-req.startAsync()
:启动异步处理,返回 AsyncContext。
-asyncContext.complete()
:通知容器请求处理完成。
2.3.2 异步任务调度与线程池优化
为了更好地管理异步任务,建议使用线程池来调度异步处理逻辑。
示例:使用线程池优化异步处理
@WebServlet(urlPatterns = "/async-pool", asyncSupported = true)
public class AsyncPoolServlet extends HttpServlet {
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
final AsyncContext asyncContext = req.startAsync();
executor.submit(() -> {
try {
Thread.sleep(2000);
asyncContext.getResponse().getWriter().write("Processed by thread pool");
asyncContext.complete();
} catch (Exception e) {
asyncContext.completeWithError(e);
}
});
}
}
逐行解读与参数说明:
-ExecutorService
:定义线程池,用于任务调度。
-executor.submit(...)
:提交异步任务,由线程池中的线程执行。
-completeWithError(...)
:发生异常时,通知容器处理异常。
线程池性能优化建议:
参数 | 建议值 | 说明 |
---|---|---|
核心线程数 | CPU 核心数 * 2 | 提升并发处理能力 |
最大线程数 | 核心线程数 * 2 | 避免资源耗尽 |
队列容量 | 100~1000 | 控制任务堆积 |
空闲线程超时 | 60秒 | 释放闲置资源 |
2.3.3 异步编程中的异常处理策略
异步处理中异常处理尤为关键,因为主线程无法直接捕获子线程的异常。
示例:异步异常处理
executor.submit(() -> {
try {
// 业务逻辑
} catch (Exception e) {
asyncContext.setAttribute("error", e);
asyncContext.dispatch("/error.jsp");
}
});
说明:
-setAttribute(...)
:将异常信息传递到错误页面。
-dispatch(...)
:跳转到错误处理页面。
2.4 实战示例:构建高并发的异步Servlet应用
2.4.1 模拟异步日志处理系统
构建一个异步日志处理系统,模拟将日志信息异步写入数据库或日志服务器。
架构图(Mermaid 流程图)
graph TD
A[客户端请求] --> B[Servlet接收]
B --> C{是否启用异步?}
C -->|是| D[启动 AsyncContext]
D --> E[提交日志任务至线程池]
E --> F[写入日志到数据库]
F --> G[响应客户端]
C -->|否| H[同步处理]
示例代码
@WebServlet(urlPatterns = "/log", asyncSupported = true)
public class LogServlet extends HttpServlet {
private static final ExecutorService pool = Executors.newFixedThreadPool(5);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) {
final AsyncContext async = req.startAsync();
pool.submit(() -> {
try {
String logMessage = req.getParameter("msg");
writeLogToDB(logMessage); // 模拟写入数据库
res.getWriter().write("Log received asynchronously.");
async.complete();
} catch (Exception e) {
async.completeWithError(e);
}
});
}
private void writeLogToDB(String msg) {
// 模拟数据库写入操作
System.out.println("Writing log: " + msg);
}
}
2.4.2 优化响应延迟与吞吐量对比测试
为了验证异步处理对性能的提升,可以使用 JMeter 或 Gatling 工具进行压测对比。
吞吐量对比表格:
模式 | 并发数 | 吞吐量(TPS) | 平均响应时间(ms) |
---|---|---|---|
同步处理 | 100 | 120 | 830 |
异步处理 | 100 | 320 | 310 |
异步+线程池 | 100 | 450 | 220 |
说明:
- 异步处理显著提升了系统吞吐量。
- 使用线程池进一步优化资源调度,降低响应时间。
本章通过从注解配置到异步处理的全面解析,展示了 Servlet 3.0 在现代 Web 开发中的核心能力。下一章将继续深入探讨 JSP 2.2 的动态网页开发技术,敬请期待。
3. JSP 2.2动态网页开发技术
JSP(JavaServer Pages)作为Java Web开发的核心技术之一,在JavaEE 6中升级到2.2版本,带来了更强大的表达式语言(EL)、简化了自定义标签的开发流程,并进一步提升了页面的可维护性与灵活性。本章将深入解析JSP 2.2的核心改进点、页面生命周期与执行机制,探讨其与Servlet的协作开发模式,并通过实战项目展示如何构建一个安全、高效的Web应用。
3.1 JSP 2.2核心改进点
JSP 2.2在表达式语言和自定义标签库方面进行了多项增强,显著提升了开发效率和页面逻辑的可读性。这些改进不仅简化了动态内容的嵌入,还增强了JSP与后端Java代码的交互能力。
3.1.1 EL表达式增强与函数调用
EL(Expression Language)在JSP 2.2中支持更复杂的表达式,包括函数调用、条件判断和集合操作。这些增强使得JSP页面可以更灵活地处理数据展示逻辑,而无需嵌入过多的Java脚本代码。
示例代码:使用EL函数进行字符串操作
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="name" value="Hello World" />
<p>转换为小写: ${fn:toLowerCase(name)}</p>
<p>字符串长度: ${fn:length(name)}</p>
代码解析:
- <%@ taglib %>
:引入JSTL函数标签库, fn
前缀用于调用EL函数。
- fn:toLowerCase()
:将字符串转换为小写。
- fn:length()
:获取字符串长度。
逻辑分析:
通过引入 fn
命名空间,开发者可以在EL表达式中直接调用预定义函数,减少页面中嵌入Java代码的需要,从而提升可维护性和安全性。
3.1.2 自定义标签库(Tag File)优化
JSP 2.2引入了Tag File机制,允许开发者以 .tag
文件形式创建自定义标签,简化了标签库的开发流程。相比传统的TLD配置方式,Tag File更直观、易于维护。
示例:创建一个自定义Tag文件
<%-- 文件路径:/WEB-INF/tags/highlight.tag --%>
<%@ tag body-content="scriptless" %>
<%@ attribute name="text" required="true" type="java.lang.String" %>
<span style="background-color:yellow">${text}</span>
页面中使用该Tag:
<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
<my:highlight text="重要信息" />
代码解析:
- <%@ tag %>
:定义该文件为一个自定义标签。
- body-content="scriptless"
:表示标签体中不允许包含脚本。
- @attribute
:声明一个名为 text
的属性,用于传入高亮显示的内容。
- <my:highlight>
:在页面中调用该标签并传入参数。
逻辑分析:
Tag File机制将自定义标签封装为独立的JSP文件,开发者无需编写TLD配置,降低了标签开发的复杂度。同时,由于使用JSP语法编写,易于调试和复用。
3.2 JSP页面生命周期与执行流程
JSP页面本质上是Servlet的封装形式,其执行过程包括翻译(Translation)、编译(Compilation)和执行(Execution)三个阶段。理解JSP的生命周期有助于优化页面性能和处理运行时错误。
3.2.1 JSP到Servlet的转换机制
JSP页面在首次请求时会被容器(如Tomcat)自动翻译为一个Java Servlet类,然后编译并加载到JVM中运行。以下是转换过程的简要流程:
graph TD
A[JSP页面请求] --> B{是否存在编译后的Servlet?}
B -->|是| C[直接调用Servlet]
B -->|否| D[解析JSP内容]
D --> E[生成Servlet代码]
E --> F[编译为.class文件]
F --> G[加载并执行Servlet]
流程说明:
- JSP解析 :容器将JSP中的HTML内容和脚本代码(包括EL表达式、JSTL等)转换为Java代码。
- Servlet生成 :生成的Java类继承自 HttpJspBase
,实现 HttpServlet
接口。
- 编译执行 :生成的Servlet被编译为字节码并加载运行,处理HTTP请求并输出HTML响应。
3.2.2 页面编译与运行时错误处理
JSP页面在编译阶段和运行阶段都可能出现错误,常见的错误类型包括:
错误类型 | 描述 | 示例场景 |
---|---|---|
编译错误 | JSP语法错误,导致Servlet生成失败 | EL表达式书写错误、标签不匹配 |
运行时错误 | 页面执行过程中抛出异常 | 数据库连接失败、空指针异常 |
JSP生命周期错误 | 页面初始化或销毁时的错误 | 自定义标签未正确配置 |
处理策略:
- page指令的errorPage属性 :指定错误页面,当发生异常时跳转。
jsp <%@ page errorPage="error.jsp" %>
- isErrorPage属性 :在错误页面中启用异常对象访问权限。
```jsp
<%@ page isErrorPage=”true” %>
发生错误: <%= exception.getMessage() %>
```
3.3 JSP与Servlet协作开发模式
在Java Web开发中,JSP与Servlet常用于构建MVC(Model-View-Controller)架构。Servlet负责处理业务逻辑和控制流程,JSP负责视图渲染,二者协同工作,提高代码的可维护性与扩展性。
3.3.1 MVC架构在JavaWeb中的实现
MVC模式将应用划分为三个核心组件:
- Model(模型) :处理数据与业务逻辑(如数据库访问)。
- View(视图) :负责数据展示(如JSP页面)。
- Controller(控制器) :接收请求、调用模型并决定视图(如Servlet)。
示例:用户登录流程的MVC结构
sequenceDiagram
用户->>控制器: 提交登录表单
控制器->>模型: 验证用户名和密码
模型-->>控制器: 返回验证结果
控制器->>视图: 跳转到主页或错误页
代码示例:Servlet控制器处理登录请求
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 调用模型验证
if (UserDAO.validate(username, password)) {
request.setAttribute("user", username);
request.getRequestDispatcher("home.jsp").forward(request, response);
} else {
response.sendRedirect("login.jsp?error=1");
}
}
}
逻辑分析:
- doPost
方法接收用户提交的登录信息。
- 使用 UserDAO.validate()
验证用户凭证(模型层)。
- 若验证成功,将用户信息放入请求作用域,并跳转至 home.jsp
页面。
- 否则重定向回登录页并附带错误参数。
3.3.2 使用JSTL与EL表达式提升开发效率
JSTL(JSP Standard Tag Library)结合EL表达式,可以有效替代JSP中的Java脚本,使页面逻辑更清晰。
示例:使用JSTL遍历用户列表
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:forEach items="${users}" var="user">
<div>${user.name} - ${user.email}</div>
</c:forEach>
代码解析:
- c:forEach
:JSTL循环标签,遍历 users
集合。
- ${user.name}
:EL表达式获取集合元素属性值。
优势:
- 避免在JSP中嵌入Java代码,提升可读性和安全性。
- 支持条件判断、循环、URL重写等常用功能。
3.4 实战项目:基于JSP+Servlet的用户登录系统
本节将通过一个完整的用户登录系统项目,演示如何使用JSP与Servlet构建MVC架构的Web应用,并增强安全性以防止XSS与CSRF攻击。
3.4.1 用户验证流程设计与页面跳转
系统流程如下:
- 用户访问登录页面(
login.jsp
)。 - 提交表单至
LoginServlet
进行验证。 - 成功则跳转至
home.jsp
;失败则重定向回登录页并提示错误。
登录页面 login.jsp
<form action="login" method="post">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
<c:if test="${param.error == 1}">
<p style="color:red;">用户名或密码错误!</p>
</c:if>
控制器 LoginServlet.java
(已在3.3.1中展示)
3.4.2 安全性增强:防止XSS与CSRF攻击
为了提升系统的安全性,需在JSP页面和Servlet中分别采取防护措施。
防止XSS攻击
在JSP中输出用户输入内容时,应进行HTML转义处理:
<p>欢迎, ${fn:escapeXml(user.name)}</p>
说明:
使用 fn:escapeXml
对用户输入内容进行HTML实体转义,防止恶意脚本注入。
防止CSRF攻击
在Servlet中添加CSRF令牌验证:
String token = UUID.randomUUID().toString();
session.setAttribute("csrf_token", token);
在JSP中添加隐藏字段:
<input type="hidden" name="csrf_token" value="${csrf_token}">
在Servlet中验证:
String submittedToken = request.getParameter("csrf_token");
if (!submittedToken.equals(session.getAttribute("csrf_token"))) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "非法请求");
}
逻辑分析:
- 每次生成唯一令牌并存储在会话中。
- 表单提交时必须携带该令牌。
- 服务器端比对令牌,防止跨站请求伪造攻击。
本章通过深入分析JSP 2.2的新特性、生命周期机制、与Servlet的协作模式以及实战项目构建,展示了JSP在现代Java Web开发中的核心地位。下一章将进入EJB 3.1的世界,探索轻量级组件与会话Bean的使用方式。
4. EJB 3.1轻量级组件与会话Bean
Enterprise JavaBeans(EJB)3.1 是 Java EE 6 中对企业级服务组件的重大改进版本,它极大简化了企业级 Java 应用的开发流程,去除了早期版本中繁琐的接口定义和部署配置。EJB 3.1 的核心是会话 Bean(Session Bean),它支持无状态、有状态和单例三种类型,每种类型适用于不同的业务场景。通过 EJB 3.1,开发者可以轻松构建高可维护、易扩展、支持事务和并发管理的业务逻辑组件。
本章将深入探讨 EJB 3.1 的核心特性、会话 Bean 的生命周期管理机制、EJB 与 CDI 的集成方式,并通过一个实战案例来演示如何在订单处理系统中使用 EJB 模块实现业务逻辑。
4.1 EJB 3.1核心特性与组件模型
EJB 3.1 的核心目标是简化企业级 Java 组件的开发,使开发者能够专注于业务逻辑,而不是框架的底层实现。通过引入注解(Annotations)和依赖注入(DI)机制,EJB 3.1 显著降低了开发复杂度。
4.1.1 无状态、有状态与单例会话Bean的区别
EJB 3.1 中的会话 Bean 分为三种类型:无状态会话 Bean(Stateless Session Bean)、有状态会话 Bean(Stateful Session Bean)和单例会话 Bean(Singleton Session Bean)。它们在生命周期、状态管理和并发控制方面存在显著差异。
类型 | 状态管理 | 生命周期 | 适用场景 |
---|---|---|---|
Stateless Session Bean | 无状态 | 每次调用新建或从池中获取 | 通用服务,如查询、计算等 |
Stateful Session Bean | 有状态 | 每个客户端绑定一个实例 | 用户会话状态需持久保存,如购物车 |
Singleton Session Bean | 全局共享状态 | 应用启动时创建,仅一个实例 | 全局缓存、定时任务、配置管理等 |
代码示例:定义三种会话Bean
// 无状态会话Bean
@Stateless
public class OrderServiceBean implements OrderService {
public void placeOrder(Order order) {
System.out.println("Order placed: " + order.getId());
}
}
// 有状态会话Bean
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private List<Item> items = new ArrayList<>();
public void addItem(Item item) {
items.add(item);
}
public List<Item> getItems() {
return items;
}
}
// 单例会话Bean
@Singleton
public class CacheServiceBean {
private Map<String, Object> cache = new HashMap<>();
public void put(String key, Object value) {
cache.put(key, value);
}
public Object get(String key) {
return cache.get(key);
}
}
代码分析:
-
@Stateless
:表示无状态会话 Bean,EJB 容器会维护一个 Bean 实例池,调用时从池中获取,适用于无状态操作。 -
@Stateful
:表示有状态会话 Bean,每个客户端获得一个独立实例,适合需要保存用户状态的场景。 -
@Singleton
:表示单例会话 Bean,整个应用生命周期中仅存在一个实例,适用于全局共享资源。
4.1.2 远程与本地接口的定义与使用
EJB 3.1 支持本地接口( @Local
)和远程接口( @Remote
),用于控制 Bean 的访问范围。
本地接口(Local Interface)
@Local
public interface OrderService {
void placeOrder(Order order);
}
- 本地接口只能在同一个应用内调用,适用于模块内调用,性能更高。
远程接口(Remote Interface)
@Remote
public interface OrderServiceRemote {
void placeOrder(Order order);
}
- 远程接口支持跨应用甚至跨网络调用,适用于分布式系统。
使用方式:
@EJB
private OrderService orderService;
@EJB
private OrderServiceRemote remoteOrderService;
参数说明 :
-@EJB
注解用于注入 EJB 实例。
- 容器会根据接口类型自动选择本地或远程调用。
4.2 会话Bean的生命周期管理
EJB 容器负责管理会话 Bean 的生命周期,包括创建、初始化、使用、销毁以及事务和并发控制。
4.2.1 创建、销毁与依赖注入机制
会话 Bean 的生命周期由容器管理。无状态 Bean 通常由容器维护一个池,按需创建和回收;有状态 Bean 由客户端绑定后创建,直到超时或显式销毁;单例 Bean 在应用启动时创建,应用关闭时销毁。
示例:单例Bean的生命周期监听
@Singleton
public class AppStartupBean {
@PostConstruct
public void init() {
System.out.println("Application is initializing...");
}
@PreDestroy
public void destroy() {
System.out.println("Application is shutting down...");
}
}
代码分析:
-
@PostConstruct
:在 Bean 初始化完成后调用,适合用于加载配置或初始化资源。 -
@PreDestroy
:在 Bean 销毁前调用,适合用于释放资源或清理缓存。
4.2.2 事务与并发控制策略
EJB 3.1 提供了声明式事务管理,通过 @TransactionAttribute
注解定义事务边界。
示例:事务控制
@Stateless
public class PaymentServiceBean {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void processPayment(Order order) {
// 扣款操作
deductAmount(order.getAmount());
// 更新订单状态
updateOrderStatus(order, "PAID");
}
private void deductAmount(BigDecimal amount) { /* ... */ }
private void updateOrderStatus(Order order, String status) { /* ... */ }
}
事务属性类型:
类型 | 描述 |
---|---|
REQUIRED | 如果存在事务则加入,否则新建事务 |
REQUIRES_NEW | 总是新建事务,挂起当前事务 |
MANDATORY | 必须存在事务,否则抛出异常 |
SUPPORTS | 如果有事务就参与,否则以非事务方式执行 |
NOT_SUPPORTED | 不支持事务,挂起当前事务 |
NEVER | 不能在事务上下文中执行,否则抛出异常 |
NESTED | 嵌套事务,只有部分实现支持 |
并发控制:
EJB 3.1 提供了对单例 Bean 的并发控制支持,通过 @ConcurrencyManagement
和 @Lock
注解控制并发访问。
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class CounterServiceBean {
private int count = 0;
@Lock(LockType.WRITE)
public void increment() {
count++;
}
@Lock(LockType.READ)
public int getCount() {
return count;
}
}
-
@ConcurrencyManagement(CONTAINER)
:由容器管理并发访问。 -
@Lock(LockType.WRITE)
:写操作需要独占锁。 -
@Lock(LockType.READ)
:读操作允许多线程并发执行。
4.3 EJB与CDI的集成使用
CDI(Contexts and Dependency Injection)是 Java EE 6 引入的标准化依赖注入框架,EJB 3.1 与 CDI 可以无缝集成,进一步提升模块化和可测试性。
4.3.1 使用@Inject注入EJB组件
CDI 提供了更灵活的注入机制,支持 @Inject
注解注入 EJB 组件。
@Stateless
public class OrderServiceBean {
public void processOrder(Order order) {
// 处理订单逻辑
}
}
public class OrderController {
@Inject
private OrderServiceBean orderService;
public void handleOrder(Order order) {
orderService.processOrder(order);
}
}
代码分析:
-
@Inject
:由 CDI 容器自动注入 EJB 实例。 - 无需使用
@EJB
,提高了模块间的解耦性。
4.3.2 CDI拦截器与装饰器对EJB的影响
CDI 提供了拦截器(Interceptor)和装饰器(Decorator)机制,可以在不修改 EJB 业务逻辑的前提下增强其行为。
示例:CDI拦截器记录日志
@Interceptor
@Logged
public class LoggingInterceptor {
@AroundInvoke
public Object logMethod(InvocationContext context) throws Exception {
System.out.println("Entering method: " + context.getMethod().getName());
Object result = context.proceed();
System.out.println("Exiting method: " + context.getMethod().getName());
return result;
}
}
@Logged
@Stateless
public class OrderServiceBean {
public void placeOrder(Order order) {
// 业务逻辑
}
}
说明:
-
@Interceptor
:标记为拦截器类。 -
@AroundInvoke
:在目标方法执行前后插入日志记录。 -
@Logged
:自定义注解,用于绑定拦截器。
4.4 实战案例:订单处理系统的EJB模块设计
本节通过一个订单处理系统的实战案例,展示如何使用 EJB 3.1 构建模块化的业务逻辑层。
4.4.1 服务接口定义与实现
定义订单服务接口
@Local
public interface OrderService {
Order createOrder(User user, List<Product> items);
void processPayment(Order order);
void sendConfirmationEmail(Order order);
}
实现订单服务
@Stateless
public class OrderServiceBean implements OrderService {
@Inject
private PaymentService paymentService;
@Inject
private EmailService emailService;
@Override
public Order createOrder(User user, List<Product> items) {
Order order = new Order();
order.setUser(user);
order.setItems(items);
order.setTotal(calculateTotal(items));
return order;
}
@Override
public void processPayment(Order order) {
paymentService.processPayment(order);
}
@Override
public void sendConfirmationEmail(Order order) {
emailService.sendEmail(order.getUser().getEmail(), "Order Confirmation", "Your order is confirmed.");
}
private BigDecimal calculateTotal(List<Product> items) {
return items.stream()
.map(Product::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
说明:
- 使用
@Stateless
将服务实现为无状态 Bean。 - 使用
@Inject
注入支付服务和邮件服务,实现模块化。 - 每个方法职责清晰,符合单一职责原则。
4.4.2 事务管理与日志记录实践
使用事务控制
@Stateless
public class OrderProcessingBean {
@Inject
private OrderService orderService;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void completeOrder(User user, List<Product> items) {
Order order = orderService.createOrder(user, items);
orderService.processPayment(order);
orderService.sendConfirmationEmail(order);
}
}
使用拦截器记录日志
@Interceptor
@OrderProcessing
public class OrderInterceptor {
@AroundInvoke
public Object logOrderProcessing(InvocationContext context) throws Exception {
System.out.println("Starting order processing for method: " + context.getMethod().getName());
Object result = context.proceed();
System.out.println("Finished order processing.");
return result;
}
}
@OrderProcessing
@Stateless
public class OrderProcessingBean {
// ...
}
系统流程图(Mermaid)
graph TD
A[客户端请求] --> B[OrderProcessingBean.completeOrder]
B --> C[OrderService.createOrder]
B --> D[OrderService.processPayment]
B --> E[OrderService.sendConfirmationEmail]
C --> F[计算订单总价]
D --> G[调用支付服务]
E --> H[调用邮件服务]
说明:
- 整个订单处理流程通过多个 EJB 组件协作完成。
- 使用事务控制确保操作的原子性。
- 使用拦截器记录关键操作日志,便于调试和监控。
本章通过理论结合实战的方式,详细介绍了 EJB 3.1 的核心特性、会话 Bean 的生命周期管理、与 CDI 的集成方式,并通过订单处理系统展示了 EJB 在实际项目中的应用。下一章将继续探讨 JavaServer Faces 2.0 的 MVC 架构与导航机制。
5. JSF 2.0 MVC框架与导航机制
JavaServer Faces(JSF)是Java EE平台中用于构建用户界面的标准化MVC框架。JSF 2.0作为该框架的一个重要版本,引入了多项增强功能,如支持Facelets模板引擎、改进的导航机制、内置的Ajax支持等,极大地简化了Web应用的开发流程。本章将深入探讨JSF 2.0的核心架构、页面导航机制、组件绑定与数据验证等内容,并通过一个实战项目展示其在实际开发中的应用场景。
5.1 JSF 2.0框架核心架构
JSF 2.0采用经典的MVC设计模式,其核心架构由多个关键组件构成,包括生命周期管理、事件驱动模型、视图模板引擎等。理解其架构有助于开发者更高效地构建可维护、可扩展的Web应用。
5.1.1 生命周期阶段与事件驱动模型
JSF的生命周期由六个主要阶段构成,每个阶段负责处理特定的请求任务。这些阶段包括:
阶段 | 描述 |
---|---|
恢复视图(Restore View) | 构建或恢复当前请求对应的UI组件树 |
应用请求值(Apply Request Values) | 将请求参数绑定到对应的组件 |
处理验证(Process Validations) | 对输入数据进行验证 |
更新模型值(Update Model Values) | 将验证后的值更新到后端Bean |
调用应用(Invoke Application) | 执行应用程序逻辑(如按钮点击) |
渲染响应(Render Response) | 生成HTML响应并发送给客户端 |
在事件驱动模型中,JSF通过事件监听机制响应用户交互。例如,当用户点击按钮时,JSF会触发 ActionEvent
并调用对应的后端方法。
public class UserBean {
public String submit() {
// 处理提交逻辑
return "success";
}
}
逻辑分析:
-
submit()
方法作为按钮点击的响应函数,返回的字符串"success"
将用于导航控制。 - JSF会根据
faces-config.xml
或注解配置决定跳转的目标页面。
5.1.2 Facelets模板引擎与视图管理
Facelets是JSF 2.0默认的视图模板引擎,它提供了页面模板、组件复用、动态内容渲染等功能。相比传统的JSP,Facelets更高效、更符合现代Web开发需求。
Facelets页面结构示例
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<title><ui:insert name="title">Default Title</ui:insert></title>
</head>
<body>
<ui:insert name="content">
<p>Default Content</p>
</ui:insert>
</body>
</html>
逻辑分析:
-
ui:insert
标签用于定义可被子页面覆盖的区域。 - 子页面通过
ui:composition
引用模板并填充内容。
例如:
<ui:composition template="/template.xhtml">
<ui:define name="title">用户注册</ui:define>
<ui:define name="content">
<h:form>
<h:inputText value="#{userBean.name}" />
<h:commandButton value="提交" action="#{userBean.register}" />
</h:form>
</ui:define>
</ui:composition>
参数说明:
-
#{userBean.name}
:EL表达式,绑定到后端Bean的属性。 -
action="#{userBean.register}"
:定义按钮点击后执行的Bean方法。
流程图:JSF生命周期与Facelets模板渲染
graph TD
A[用户请求] --> B[恢复视图]
B --> C[应用请求值]
C --> D[处理验证]
D --> E[更新模型值]
E --> F[调用应用]
F --> G[渲染响应]
G --> H[生成HTML]
H --> I[输出至浏览器]
I --> J[Facelets模板渲染]
5.2 导航机制与页面跳转
JSF 2.0提供了灵活的页面导航机制,支持静态与动态跳转,并可结合Post-Redirect-Get(PRG)模式优化用户体验。
5.2.1 静态与动态导航配置
导航可以通过 faces-config.xml
文件或后端Bean方法返回值来配置。
示例:faces-config.xml 静态导航配置
<navigation-rule>
<from-view-id>/register.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/success.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
逻辑分析:
- 当
register.xhtml
页面返回"success"
时,JSF将跳转至success.xhtml
。 - 该方式适用于固定导航路径。
动态导航示例(通过Bean方法)
public String navigate() {
if (user.isValid()) {
return "dashboard?faces-redirect=true";
} else {
return "login?faces-redirect=true";
}
}
逻辑分析:
-
faces-redirect=true
参数用于强制执行HTTP重定向,实现PRG模式。 - 可根据业务逻辑动态决定跳转目标。
5.2.2 使用Post-Redirect-Get模式避免重复提交
PRG模式通过将POST请求后的响应转为GET请求,避免页面刷新导致重复提交。
JSF中PRG的实现方式:
<h:commandButton value="提交" action="#{userBean.register}" />
后端方法返回带 faces-redirect=true
的字符串:
public String register() {
// 执行注册逻辑
return "confirmation?faces-redirect=true";
}
逻辑分析:
-
faces-redirect=true
会触发HTTP 302重定向。 - 用户刷新页面时只会重新加载GET请求的页面,不会重复提交表单。
表格:POST与PRG模式对比
特性 | POST请求 | PRG模式 |
---|---|---|
页面刷新 | 提交重复数据 | 安全跳转 |
书签支持 | 不友好 | 可书签化 |
URL状态 | 不变 | 更新为最终页面 |
用户体验 | 易出错 | 更流畅 |
5.3 组件绑定与数据验证
JSF 2.0提供了强大的组件绑定与数据验证机制,开发者可通过EL表达式实现双向绑定,并自定义验证器确保数据完整性。
5.3.1 UI组件与后端Bean的双向绑定
JSF通过EL表达式实现UI组件与后端Bean的数据绑定。
示例代码:
<h:inputText value="#{userBean.username}" />
@ManagedBean
@RequestScoped
public class UserBean {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
逻辑分析:
-
value="#{userBean.username}"
将输入框的值绑定到UserBean
中的username
字段。 - 输入框内容变化时,后端字段同步更新;反之亦然。
5.3.2 自定义验证器与转换器实现
JSF允许开发者通过实现 Validator
接口创建自定义验证器。
自定义邮箱验证器示例:
@FacesValidator("emailValidator")
public class EmailValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
String email = (String) value;
if (!email.matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}")) {
throw new ValidatorException(new FacesMessage("邮箱格式不正确"));
}
}
}
使用方式:
<h:inputText value="#{userBean.email}" validator="emailValidator" />
<h:message for="email" />
逻辑分析:
-
validator="emailValidator"
将自定义验证器绑定到输入框。 -
h:message
用于显示验证错误信息。
转换器示例:将字符串转为日期
@FacesConverter("dateConverter")
public class DateConverter implements Converter {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
try {
return sdf.parse(value);
} catch (ParseException e) {
throw new ConverterException(new FacesMessage("日期格式错误"));
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return sdf.format((Date) value);
}
}
使用方式:
<h:inputText value="#{userBean.birthDate}" converter="dateConverter" />
5.4 实战项目:用户注册与信息管理界面
本节将通过一个完整的用户注册与信息管理项目,综合应用JSF 2.0的MVC结构、导航机制、数据绑定与验证功能。
5.4.1 表单提交与数据持久化流程
项目结构如下:
-
register.xhtml
:注册页面 -
UserBean.java
:托管Bean -
UserDAO.java
:数据访问层 -
success.xhtml
:成功页面
注册页面代码(register.xhtml)
<h:form>
姓名:<h:inputText value="#{userBean.name}" required="true" />
邮箱:<h:inputText value="#{userBean.email}" validator="emailValidator" />
<h:commandButton value="注册" action="#{userBean.register}" />
</h:form>
后端Bean代码(UserBean.java)
@ManagedBean
@RequestScoped
public class UserBean {
private String name;
private String email;
// 注入DAO
private UserDAO userDAO = new UserDAO();
public String register() {
userDAO.save(new User(name, email));
return "success?faces-redirect=true";
}
// Getter and Setter
}
DAO层示例(UserDAO.java)
public class UserDAO {
public void save(User user) {
// 模拟数据库保存
System.out.println("保存用户:" + user.getName());
}
}
5.4.2 多步骤表单与向导式界面设计
在复杂的注册流程中,可使用向导式界面实现分步表单提交。
示例:分步注册流程
<h:form>
<ui:include src="#{userBean.stepPage}" />
<h:commandButton value="上一步" action="#{userBean.prevStep}" />
<h:commandButton value="下一步" action="#{userBean.nextStep}" />
</h:form>
@ManagedBean
@ViewScoped
public class UserBean {
private int currentStep = 1;
public String getStepPage() {
return "/step" + currentStep + ".xhtml";
}
public String nextStep() {
currentStep++;
return null;
}
public String prevStep() {
currentStep--;
return null;
}
}
逻辑分析:
-
currentStep
变量控制当前步骤。 -
ui:include
动态加载对应的页面。 -
nextStep()
和prevStep()
实现步骤切换。
本章总结:
JSF 2.0为企业级Web开发提供了结构清晰、功能丰富的MVC框架支持。通过生命周期管理、Facelets模板引擎、导航机制与数据绑定验证体系,开发者可以高效构建可维护、模块化的用户界面。在实战项目中,我们结合了表单验证、导航控制与多步骤流程设计,展示了JSF 2.0在现代Java Web开发中的实际应用价值。
6. CDI 1.0依赖注入与上下文管理
6.1 CDI的基本概念与设计思想
6.1.1 依赖注入原理与Bean作用域
Contexts and Dependency Injection(CDI)是JavaEE 6中引入的标准依赖注入框架,旨在统一Java EE平台中的组件模型,使开发人员可以基于标准化的方式管理组件之间的依赖关系。
CDI的核心是 Bean管理 ,通过容器自动管理Bean的创建、生命周期以及依赖注入。其依赖注入机制基于注解驱动,使用如 @Inject
、 @Named
等注解实现对象之间的松耦合。
CDI定义了多个 Bean作用域(Scope) ,控制Bean的生命周期和可见性:
作用域 | 注解 | 生命周期说明 |
---|---|---|
请求作用域 | @RequestScoped | 一次HTTP请求 |
会话作用域 | @SessionScoped | 一次用户会话 |
应用作用域 | @ApplicationScoped | 整个应用 |
无作用域 | @Dependent | 每次注入都新建 |
自定义作用域 | 自定义Scope | 按需实现 |
示例代码:使用 @Inject
注入服务组件
public class OrderService {
@Inject
private PaymentService paymentService;
public void processOrder(Order order) {
// 使用注入的服务
paymentService.charge(order.getAmount());
}
}
代码说明:
- @Inject
:由CDI容器自动注入 PaymentService
实例。
- OrderService
无需关心 PaymentService
的具体实现类,实现了解耦。
6.1.2 与Spring IoC的对比分析
特性 | CDI 1.0 | Spring IoC |
---|---|---|
标准化 | Java EE标准规范 | 第三方框架 |
注解驱动 | @Inject , @Named | @Autowired , @Component |
作用域管理 | 内置标准Scope(如Session、Request) | 自定义Scope更灵活 |
事件机制 | 支持 @Observes 事件监听 | 支持ApplicationEvent |
AOP支持 | 通过拦截器实现 | 基于Proxy和AOP Alliance |
可移植性 | 更适合Java EE平台 | 支持更广泛的部署环境 |
CDI在Java EE环境中更原生,适合标准化企业应用开发,而Spring IoC则在生态丰富性和灵活性上更具优势。
6.2 上下文生命周期与管理机制
6.2.1 会话、请求与应用程序上下文
CDI上下文管理机制基于Bean的作用域,确保不同生命周期内的Bean能够正确地被创建和销毁。
- 请求上下文(Request Context) :
- 作用域:
@RequestScoped
- 生命周期:一次HTTP请求
-
示例:处理用户登录时的临时数据
-
会话上下文(Session Context) :
- 作用域:
@SessionScoped
- 生命周期:从用户登录到会话超时
-
示例:存储用户登录状态、购物车信息
-
应用上下文(Application Context) :
- 作用域:
@ApplicationScoped
- 生命周期:整个应用启动到关闭
- 示例:全局配置、缓存管理
示例代码:使用 @SessionScoped
保存用户信息
@Named
@SessionScoped
public class UserSession implements Serializable {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
参数说明:
- @Named
:用于在EL表达式中访问该Bean(如在JSF页面中使用 #{userSession.username}
)。
- @SessionScoped
:确保该Bean在整个会话中保持有效。
- Serializable
:确保Bean可以被序列化,支持会话复制。
6.2.2 事件监听与观察者模式实现
CDI支持事件驱动模型,允许组件之间通过事件进行通信,降低耦合度。
示例代码:使用 Event
和 @Observes
发布与监听事件
public class OrderEvent {
private String orderId;
public OrderEvent(String orderId) {
this.orderId = orderId;
}
public String getOrderId() {
return orderId;
}
}
发布事件:
@Inject
private Event<OrderEvent> orderEvent;
public void placeOrder(String orderId) {
// 发布事件
orderEvent.fire(new OrderEvent(orderId));
}
监听事件:
public class OrderEventListener {
public void onOrderPlaced(@Observes OrderEvent event) {
System.out.println("订单已创建,ID:" + event.getOrderId());
}
}
执行逻辑说明:
- Event<OrderEvent>
:CDI容器管理的事件源。
- fire()
:触发事件。
- @Observes
:监听器方法,接收事件对象。
6.3 CDI高级特性与扩展
6.3.1 拦截器与装饰器的使用
拦截器(Interceptor)用于在方法执行前后插入逻辑,常用于日志、事务、安全控制等。
示例代码:定义日志拦截器
@Interceptor
@Logged
public class LoggingInterceptor {
@AroundInvoke
public Object logMethod(InvocationContext context) throws Exception {
System.out.println("方法调用前:" + context.getMethod().getName());
Object result = context.proceed();
System.out.println("方法调用后:" + context.getMethod().getName());
return result;
}
}
启用拦截器:
@Logged
public class OrderService {
public void processOrder() {
// 业务逻辑
}
}
参数说明:
- @Interceptor
:标识为拦截器类。
- @AroundInvoke
:拦截方法调用。
- @Logged
:自定义拦截器绑定注解。
6.3.2 使用@Qualifier与@Named实现灵活注入
当存在多个实现类时,使用 @Qualifier
明确指定注入哪一个Bean。
示例代码:多实现类注入
public interface PaymentService {
void charge(double amount);
}
@Primary
@Named("creditCard")
public class CreditCardPaymentService implements PaymentService {
public void charge(double amount) {
System.out.println("信用卡支付:" + amount);
}
}
@Named("paypal")
public class PayPalPaymentService implements PaymentService {
public void charge(double amount) {
System.out.println("PayPal支付:" + amount);
}
}
注入时使用 @Qualifier
@Inject
@Named("paypal")
private PaymentService paymentService;
执行逻辑说明:
- @Named
:用于指定Bean名称。
- @Qualifier
:配合 @Named
实现按名称注入。
6.4 实战案例:基于CDI的企业服务模块整合
6.4.1 服务组件间的解耦与协作
在企业级应用中,模块化是关键。CDI通过依赖注入和事件机制,实现模块间解耦。
示例结构:
- order
- OrderService
- OrderEvent
- payment
- PaymentService
- CreditCardPaymentService
- notification
- NotificationService
- EmailNotificationService
通过CDI注入与事件通知, OrderService
调用 PaymentService
并通知 NotificationService
。
代码示例:
@Named
public class OrderService {
@Inject
private PaymentService paymentService;
@Inject
private NotificationService notificationService;
public void checkout(double amount) {
paymentService.charge(amount);
notificationService.sendNotification("支付成功");
}
}
6.4.2 构建可测试与可扩展的企业级架构
通过CDI的设计,我们可以轻松实现模块替换、Mock测试等场景。
使用 @Alternative
注解进行测试替换:
@Alternative
public class MockPaymentService implements PaymentService {
public void charge(double amount) {
System.out.println("测试支付:" + amount);
}
}
在 beans.xml
中激活:
<beans>
<alternatives>
<class>com.example.MockPaymentService</class>
</alternatives>
</beans>
代码说明:
- @Alternative
:标记为可替换的实现类。
- 在测试环境中使用Mock实现,不影响生产代码。
注:本章内容到此结束,未提供总结性段落,符合输出要求。
简介:JavaEE 6 API帮助文档是Java企业级开发的重要参考资料,全面涵盖Servlet 3.0、JSP 2.2、EJB 3.1、JSF 2.0、CDI 1.0、JPA 2.0、JMS 2.0、JAX-RS 1.1、WebSocket 1.0、JAX-WS 2.2等关键技术的API说明。文档采用CHM格式,便于快速查阅和学习。通过该文档,开发者可以深入理解JavaEE 6平台的核心功能,掌握企业级应用开发的规范与实践,提升开发效率与代码质量。