1. 概述
本文将带你入门 Enterprise JavaBean (EJB) 开发。EJB 专用于构建可扩展、分布式、服务端组件,通常用于封装应用的核心业务逻辑。
我们将使用 WildFly 10.1.0 作为演示服务器,当然你也可以选择任何其他 Java EE 应用服务器。
2. 环境搭建
先介绍 EJB 3.2 开发所需的 Maven 依赖,以及如何通过 Maven Cargo 插件或手动方式配置 WildFly 服务器。
2.1 Maven 依赖
在 pom.xml
中添加最新版 EJB 3.2 依赖:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
2.2 使用 Maven Cargo 设置 WildFly
通过 Maven Cargo 插件自动化服务器配置:
<profile>
<id>wildfly-standalone</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>${cargo-maven2-plugin.version}</version>
<configuration>
<container>
<containerId>wildfly10x</containerId>
<zipUrlInstaller>
<url>
http://download.jboss.org/
wildfly/10.1.0.Final/
wildfly-10.1.0.Final.zip
</url>
</zipUrlInstaller>
</container>
<configuration>
<properties>
<cargo.hostname>127.0.0.1</cargo.hostname>
<cargo.jboss.management-http.port>
9990
</cargo.jboss.management-http.port>
<cargo.servlet.users>
testUser:admin1234!
</cargo.servlet.users>
</properties>
</configuration>
</configuration>
</plugin>
</plugins>
</build>
</profile>
此配置会:
- 自动下载 WildFly 10.1
- 设置主机为
127.0.0.1
,管理端口为9990
- 创建测试用户
testUser
(密码admin1234!
)
执行以下命令启动服务器:
mvn clean package cargo:run
首次运行会下载并安装服务器,后续启动会复用已下载文件。
2.3 手动设置 WildFly
手动安装步骤:
- 从 wildfly.org 下载安装包
- 解压到目标目录后配置环境变量:
JBOSS_HOME=/Users/yourname/wildfly-10.1.0.Final JAVA_HOME=`/usr/libexec/java_home -v 1.8`
- 在
bin
目录执行:- Linux:
./standalone.sh
- Windows:
standalone.bat
- Linux:
- 添加管理用户(参考官方文档)
详细配置见 WildFly 入门指南。
项目 POM 配置了两种部署方式:
- 默认使用 Cargo 插件
- 手动部署到已运行服务器:
mvn clean install wildfly:deploy -Pwildfly-runtime
3. Remote 与 Local 接口
EJB 业务接口分为两种类型:
类型 | 特性 |
---|---|
@Local |
仅限同一应用内访问(如同一 .ear 或 .war) |
@Remote |
可跨应用访问(不同 JVM 或服务器) |
设计时需注意:
- ✅
java.io.Serializable
、java.io.Externalizable
和javax.ejb
包接口始终被排除 - ✅ 类标记为
@Remote
时,所有实现接口自动成为远程接口 - ✅ 未标注或标注
@Local
时,所有接口默认为本地 - ✅ 无接口的 Bean 必须显式声明
@Local
- ⚠️ EJB 3.2 提供更细粒度的接口控制能力
4. 创建 Remote EJB
先定义业务接口 HelloWorld
:
@Remote
public interface HelloWorld {
String getHelloWorld();
}
实现类 HelloWorldBean
:
@Stateless(name = "HelloWorld")
public class HelloWorldBean implements HelloWorld {
@Resource
private SessionContext context;
@Override
public String getHelloWorld() {
return "Welcome to EJB Tutorial!";
}
}
关键点:
@Stateless
注解声明无状态会话 Bean- 不维护客户端状态
- 可能保留实例状态
- 适合执行独立操作
@Resource
注入 SessionContext- 提供运行时会话上下文访问
- 容器在实例创建后注入
- 生命周期内与实例绑定
⚠️ 由于容器使用对象池机制,实例变量值在多次调用间可能不保持。
5. 远程部署配置
5.1 EJB 插件配置
使用 Maven EJB 插件打包模块:
<plugin>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.4</version>
<configuration>
<ejbVersion>3.2</ejbVersion>
</configuration>
</plugin>
5.2 部署 Remote EJB
确保 WildFly 服务器运行后,在 ejb-remote
项目目录执行:
mvn wildfly:deploy
或通过管理控制台手动部署(需管理员权限)。
6. JNDI 查找机制
6.1 查找方法实现
public HelloWorld lookup() throws NamingException {
String appName = "";
String moduleName = "remote";
String distinctName = "";
String beanName = "HelloWorld";
String viewClassName = HelloWorld.class.getName();
String toLookup = String.format("ejb:%s/%s/%s/%s!%s",
appName, moduleName, distinctName, beanName, viewClassName);
return (HelloWorld) context.lookup(toLookup);
}
6.2 关键参数说明
- Context Factory:由
org.jboss:jboss-remote-naming
提供 - JNDI 上下文:将 URL 解析为远程服务器代理
6.2.1 必需参数
# 上下文工厂类
java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
# 包扫描前缀
java.naming.factory.url.pkgs=org.jboss.ejb.client.naming
# 禁用类路径配置
org.jboss.ejb.client.scoped.context=false
# 连接协议
java.naming.provider.url=http-remoting://127.0.0.1:8080
⚠️ org.jboss.ejb.client.scoped.context=false
强制从提供的参数读取连接配置(而非类路径文件),这对多环境部署至关重要。
7. 测试验证
@Test
public void testEJBClient() {
EJBClient ejbClient = new EJBClient();
HelloWorldBean bean = new HelloWorldBean();
assertEquals(bean.getHelloWorld(), ejbClient.getEJBRemoteMessage());
}
测试通过即表示远程调用链路正常。
8. 总结
我们成功实现了:
- EJB 服务器端开发
- 远程客户端调用
- 跨 JVM 方法调用
完整项目代码见 GitHub 仓库。通过调整服务器依赖,可轻松迁移到其他 Java EE 应用服务器。