引言:Java EE 服务器概述
Java EE(Java Enterprise Edition)是 Java 平台的企业版,它提供了一套完整的 API 和运行时环境,用于开发和部署大规模、多层、可扩展、可靠且安全的企业级应用程序。Java EE 服务器是这一生态系统的核心,它承载着应用程序,并提供诸如事务管理、安全性、并发性、数据库连接池等关键服务。
在现代软件开发中,尽管微服务架构和云原生技术(如 Spring Boot、Quarkus)越来越流行,但理解 Java EE 的核心概念和服务器部署仍然是构建健壮企业应用的基础。许多遗留系统和大型企业应用仍然依赖于 Java EE 规范。
本指南旨在从零基础开始,逐步引导您理解 Java EE 服务器的概念,如何选择和安装服务器,如何开发一个简单的 Java EE 应用,以及如何将其部署到服务器上。最后,我们将解析一些常见的部署和运行问题。
第一部分:理解 Java EE 服务器
1.1 什么是 Java EE 服务器?
Java EE 服务器,也称为应用服务器(Application Server),是一个实现了 Java EE 规范的软件平台。它运行在操作系统之上,为 Java EE 应用程序提供运行环境。
与简单的 Web 容器(如 Apache Tomcat)不同,Java EE 服务器提供了更全面的功能:
Web 容器
:处理 Servlet、JSP 和 JSF 等 Web 组件。
EJB 容器
:管理 Enterprise JavaBeans (EJB),提供事务管理、安全性、远程调用等。
JMS 提供者
:实现 Java 消息服务,用于异步通信。
连接器架构 (JCA)
:用于集成企业信息系统 (EIS)。
持久化提供者
:实现 JPA (Java Persistence API),用于对象关系映射 (ORM)。
1.2 常见的 Java EE 服务器
WildFly (原 JBoss AS)
:Red Hat 开源的 Java EE 应用服务器,轻量级且功能强大。
Payara Server
:GlassFish 的衍生版本,提供商业支持和额外功能。
Apache TomEE
:在 Apache Tomcat 基础上添加了 Java EE 功能。
IBM Open Liberty
:轻量级、开源的 Java EE 和 MicroProfile 运行时。
Oracle WebLogic Server
:商业级应用服务器,功能全面,性能优异。
在本指南中,我们将以
WildFly
为例,因为它易于安装、配置简单且功能强大。
第二部分:环境准备
在开始之前,我们需要准备好开发和运行环境。
2.1 安装 Java Development Kit (JDK)
Java EE 基于 Java,因此必须安装 JDK。推荐使用 Java 8 或更高版本(如 Java 11, 17)。
下载
:访问
Oracle JDK
或
OpenJDK
。
安装
:按照操作系统指南进行安装。
验证
:打开终端或命令提示符,输入以下命令:
java -version
javac -version
确保显示正确的版本号。
2.2 安装 WildFly 应用服务器
下载
:访问
WildFly 官网
下载最新版本(例如 WildFly 26+)。
解压
:将下载的压缩包解压到一个没有空格和特殊字符的目录中,例如
C:\wildfly
或
/opt/wildfly
。
环境变量 (可选但推荐)
:
设置
JBOSS_HOME
指向 WildFly 的解压目录。
将
$JBOSS_HOME/bin
添加到
PATH
中。
2.3 安装集成开发环境 (IDE)
推荐使用 IntelliJ IDEA (Ultimate 版本) 或 Eclipse IDE for Enterprise Java and Web Developers。它们都内置了对 Java EE 和 WildFly 的支持。
第三部分:创建第一个 Java EE 应用
我们将创建一个简单的 “Hello World” Web 应用,它包含一个 Servlet 和一个 JSP 页面。
3.1 项目结构
使用 Maven 来管理项目依赖。创建一个标准的 Maven Web 项目结构:
my-javaee-app
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ └── servlet
│ └── HelloServlet.java
└── webapp
├── index.jsp
└── WEB-INF
└── web.xml
3.2 配置
pom.xml
在
pom.xml
中,我们需要声明 Java EE API 的依赖。由于 WildFly 实现了 Java EE 8,我们将使用相应的依赖。
:
packaging
设置为
war
,表示这是一个 Web 应用。
dependencyManagement
导入了 Java EE 8 的 BOM (Bill of Materials),这有助于管理依赖版本。
依赖的
scope
设置为
provided
,因为这些 API 由应用服务器(WildFly)提供,不需要打包到 WAR 文件中。
3.3 编写 Servlet
创建
HelloServlet.java
。Servlet 是处理 HTTP 请求的核心组件。
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
// 使用注解配置 Servlet 的 URL 映射
@WebServlet(“/hello”)
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应内容类型
resp.setContentType(“text/html;charset=UTF-8”);
// 获取输出流
PrintWriter out = resp.getWriter();
try {
// 生成 HTML 响应
out.println(““);
out.println(““);
out.println(“
out.println(“
out.println(““);
out.println(““);
out.println(“
你好,Java EE 世界!
“);
out.println(“
这是一个来自 Servlet 的响应。
“);
out.println(“跳转到 JSP 页面“);
out.println(““);
out.println(““);
} finally {
out.close();
}
}
}
说明
:
@WebServlet(“/hello”)
:这是 Servlet 3.0 引入的注解,替代了传统的
web.xml
配置。它告诉服务器将所有访问
/hello
路径的请求交给这个 Servlet 处理。
doGet
方法:处理 HTTP GET 请求。我们在这里构建简单的 HTML 并返回给浏览器。
3.4 编写 JSP 页面
创建
index.jsp
。JSP (JavaServer Pages) 用于创建动态 Web 内容。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
欢迎来到 Java EE 应用
当前服务器时间: <%= new java.util.Date() %>
测试 Servlet
点击下面的链接测试 Servlet 功能:
使用 JSTL 标签库
循环测试: ${i}
说明
:
<%@ taglib ... %>
:引入 JSTL (JSP Standard Tag Library) 核心标签库,使得在 JSP 中可以使用
等逻辑控制标签。
<%= ... %>
:这是 JSP 表达式,用于在 HTML 中嵌入 Java 代码的计算结果(例如当前时间)。
${i}
:EL (Expression Language) 表达式,用于访问数据。
3.5 部署描述符 (web.xml)
虽然我们使用了注解,但有时
web.xml
仍然是必要的(例如配置欢迎页面、错误页面或安全约束)。创建
src/main/webapp/WEB-INF/web.xml
:
第四部分:构建与部署
4.1 构建 WAR 文件
在项目根目录下运行 Maven 命令:
mvn clean package
这将在
target/
目录下生成
my-javaee-app.war
文件。
4.2 启动 WildFly 服务器
进入 WildFly 的
bin
目录,执行启动脚本:
Windows
:
standalone.bat
Linux/Mac
:
./standalone.sh
启动完成后,您应该在控制台看到类似
WildFly 26.1.3.Final ‘Kenny’ started in 8123ms
的信息。
4.3 部署应用
有两种主要方式部署:
方式一:热部署 (推荐用于开发)
打开 WildFly 的
standalone/configuration/standalone.xml
或
standalone-full.xml
。
找到
和
deployment-scanner
子系统(默认是启用的)。
将生成的
my-javaee-app.war
文件复制到 WildFly 根目录下的
standalone/deployments/
文件夹中。
WildFly 会自动检测并部署该文件。控制台会打印日志:
Deployed “my-javaee-app.war”
。
方式二:使用管理控制台
访问
http://localhost:9990
(默认用户名/密码: admin/admin)。
导航到 “Deployment” 标签页。
点击 “Add Content”,上传 WAR 文件并部署。
方式三:使用 CLI 命令行
# 连接到服务器
jboss-cli.sh –connect
# 部署应用
deploy /path/to/my-javaee-app.war
4.4 访问应用
部署成功后,打开浏览器访问:
欢迎页面
:
http://localhost:8080/my-javaee-app/
JSP 页面
:
http://localhost:8080/my-javaee-app/index.jsp
Servlet
:
http://localhost:8080/my-javaee-app/hello
第五部分:进阶实战 – 集成 JPA 和 EJB
为了让应用更接近生产环境,我们将添加数据库持久化和业务逻辑层。
5.1 添加数据源和 JPA 依赖
在
pom.xml
中添加数据库驱动(以 H2 内存数据库为例,方便测试)和 JPA 依赖:
5.2 配置数据源 (WildFly)
WildFly 使用
standalone.xml
配置数据源。我们需要在
标签下添加 H2 的配置。
注意:WildFly 默认自带 H2 驱动,如果使用 MySQL 或 PostgreSQL,需要下载驱动 JAR 并放入
modules
目录,然后在
standalone.xml
中声明驱动。
5.3 创建实体类 (Entity)
创建
com.example.model.User
。
package com.example.model;
import javax.persistence.*;
@Entity
@Table(name = “users”)
@NamedQueries({
@NamedQuery(name = “User.findAll”, query = “SELECT u FROM User u”)
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = “username”, nullable = false, length = 50)
private String username;
@Column(name = “email”)
private String email;
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
5.4 创建 Stateless EJB (业务逻辑层)
EJB (Enterprise JavaBeans) 提供了强大的事务管理和依赖注入功能。创建
com.example.service.UserService
。
package com.example.service;
import com.example.model.User;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Stateless // 声明为无状态会话 Bean
public class UserService {
// 注入由容器管理的 EntityManager,关联 persistence unit “examplePU”
@PersistenceContext(unitName = “examplePU”)
private EntityManager em;
// 创建用户 (容器会自动管理事务)
public void createUser(String username, String email) {
User user = new User();
user.setUsername(username);
user.setEmail(email);
em.persist(user);
}
// 查询所有用户
public List
return em.createNamedQuery(“User.findAll”, User.class).getResultList();
}
}
5.5 配置 persistence.xml
在
src/main/resources/META-INF/persistence.xml
中配置 JPA。
修改
HelloServlet
或创建一个新的
UserServlet
来演示 EJB 调用。
package com.example.servlet;
import com.example.service.UserService;
import com.example.model.User;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(“/users”)
public class UserServlet extends HttpServlet {
// 使用 CDI 注入 EJB
@Inject
private UserService userService;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType(“text/html;charset=UTF-8”);
PrintWriter out = resp.getWriter();
// 添加一个测试用户 (实际应用中通常由表单提交触发 POST 请求)
// 注意:为了演示方便,这里在 GET 中直接添加,生产环境请勿这样做
// userService.createUser(“User_” + System.currentTimeMillis(), “test@example.com”);
out.println(“
用户列表
“);
out.println(“
- “);
- ID: ” + user.getId() + “, Name: ” + user.getUsername() + “
for (User user : userService.getAllUsers()) {
out.println(“
“);
}
out.println(“
“);
out.println(“返回首页“);
out.println(““);
}
}
注意
:这里使用了
@Inject
注解来注入 EJB。在 Java EE 8 中,
@EJB
和
@Inject
都可以用来注入 EJB,但
@Inject
更通用(CDI 标准)。
5.7 重新构建和部署
运行
mvn clean package
。
将新的 WAR 文件复制到
deployments
目录(覆盖旧的)。
访问
http://localhost:8080/my-javaee-app/users
查看结果。
第六部分:常见问题解析 (Troubleshooting)
在开发和部署过程中,经常会遇到各种问题。以下是一些常见问题及其解决方案。
6.1
ClassNotFoundException
或
NoClassDefFoundError
现象
:部署时控制台报错,提示找不到某个类(如
javax.servlet.ServletException
或自定义的类)。
原因
:
依赖缺失
:Maven 依赖未正确下载。
Scope 错误
:依赖的 scope 设置为
compile
或
runtime
,但该类应该由服务器提供(应为
provided
),导致服务器加载了错误的版本。
打包问题
:类文件未正确打包到 WAR 的
WEB-INF/classes
目录下。
解决方案
:
检查
pom.xml
,确保服务器提供的 API(如
javax.servlet-api
,
javaee-api
)的 scope 是
provided
。
检查
target/classes
目录,确认编译后的
.class
文件存在。
如果是自定义类,检查包路径是否正确。
6.2
java.lang.OutOfMemoryError: Java heap space
现象
:应用运行一段时间后崩溃,或在部署大应用时失败。
原因
:JVM 堆内存不足。
解决方案
:
修改 WildFly 启动脚本 (
standalone.bat
或
standalone.sh
)。
找到
JAVA_OPTS
变量,增加内存设置:
# 示例:设置初始堆内存 512MB,最大堆内存 2GB
set “JAVA_OPTS=-Xms512m -Xmx2048m …”
6.3 数据库连接失败 (
Communications link failure
)
现象
:应用尝试访问数据库时抛出连接异常。
原因
:
数据源配置错误(JNDI 名称不匹配)。
数据库服务器未启动或网络不通。
数据库驱动未正确安装到 WildFly。
解决方案
:
检查
persistence.xml
中的
是否与
standalone.xml
中的
的
jndi-name
完全一致。
检查数据库是否正在运行。
如果使用 MySQL/PostgreSQL,确保驱动 JAR 包已放置在 WildFly 的
modules/system/layers/base/com/mysql/main
(示例) 目录下,并在
standalone.xml
中添加了
引用。
6.4 端口冲突
现象
:WildFly 启动失败,报错 “Address already in use: bind”。
原因
:默认的 HTTP 端口 (8080) 或管理端口 (9990) 被其他程序占用。
解决方案
:
修改 WildFly 的
standalone.xml
,找到
部分:
或者在启动时通过系统属性指定新端口:
./standalone.sh -Djboss.http.port=8081
6.5 部署成功但 404 Not Found
原因
:
URL 路径错误。WAR 包名是上下文根(Context Root)。例如,如果 WAR 包名为
my-javaee-app.war
,则访问路径应为
http://localhost:8080/my-javaee-app/
。
Servlet 的
@WebServlet
路径拼写错误。
web.xml
配置错误或缺失欢迎文件。
解决方案
:
检查 WildFly 启动日志中的 “Deployed” 行,确认应用名称。
检查 Servlet 注解或
web.xml
中的 URL 映射。
尝试直接访问 Servlet 的完整路径(如
/my-javaee-app/hello
)。
6.6 JPA 实体未创建表
原因
:
persistence.xml
中的
javax.persistence.schema-generation.database.action
属性设置不正确(应为
create
,
drop-and-create
或
update
)。
数据源连接失败,导致无法执行建表语句。
实体类缺少
@Entity
注解或包未被扫描到。
解决方案
:
确认
persistence.xml
配置。
检查数据库连接日志。
确保实体类在
persistence-unit
定义的扫描范围内(通常在同一 JAR 或 WAR 的类路径中)。
第七部分:总结
通过本指南,您应该已经掌握了 Java EE 服务器的基础知识,学会了如何搭建环境、编写 Servlet/JSP、使用 EJB 和 JPA,以及如何将应用部署到 WildFly 服务器上。此外,我们还讨论了常见的部署问题及其解决方案。
Java EE 是一个庞大的生态系统,虽然学习曲线较陡峭,但其提供的标准化规范和强大的容器服务能极大地提高企业级应用的开发效率和稳定性。随着 Jakarta EE 的发展,这一平台正在变得更加现代化和云原生友好。继续深入学习 CDI (Contexts and Dependency Injection)、JMS (Java Message Service) 和 Bean Validation 等高级特性,将使您成为一名更优秀的 Java 企业级开发者。