WebSphere Application Server(WAS)8.5.5教程第十二讲:EJB
一、EJB
EJB(Enterprise JavaBeans)是 Java EE(现在称为 Jakarta EE) 的核心组件之一,它是一种 用于构建分布式、可伸缩、事务性和安全的企业级 Java 应用程序 的服务器端组件模型。
1、EJB 是什么?
EJB 是一套规范,由 Java EE 提出,用于定义企业级组件的开发方式,它 将复杂的系统级服务(如事务管理、安全、并发、持久化等)交给容器管理,使开发者专注于业务逻辑开发。
✅ 你可以理解为:EJB 是“托管在应用服务器中、拥有系统级功能支持”的 Java 组件。
2、EJB 的核心类型
EJB 按照功能分为三大类,每类都有特定用途:
1. 会话 Bean(Session Bean)
-
处理 业务逻辑,不保存持久状态。
-
又分为:
-
无状态 Session Bean(Stateless):不维护客户端状态(如下单操作)。
-
有状态 Session Bean(Stateful):为每个客户端保存会话状态(如购物车)。
-
单例 Session Bean(Singleton):全局共享一个实例,用于缓存等。
-
2. 消息驱动 Bean(Message-Driven Bean, MDB)
-
异步处理 JMS 消息队列,适用于异步处理任务或解耦模块。
-
例如:用户下单后,通过 MDB 异步通知仓库系统发货。
3. 实体 Bean(Entity Bean)
⚠️ 已被 JPA(Java Persistence API)替代,不推荐使用。
3、EJB 的运行机制
1. EJB 容器
-
运行在 Java EE 应用服务器(如 WebSphere、JBoss、GlassFish) 中。
-
提供如下服务:
-
生命周期管理
-
安全管理
-
事务管理(如分布式事务)
-
多线程控制
-
远程访问支持
-
2. 客户端访问方式
-
本地调用(Local Interface):部署在同一个 JVM 中。
-
远程调用(Remote Interface):可被其他服务器或系统调用。
-
Web 服务接口(可通过 JAX-WS 或 JAX-RS 暴露为 Web 服务)。
4、EJB 提供的容器服务
EJB 是“重量级”的好处在于它自带了很多“系统级能力”,例如:
功能 | 描述 |
---|---|
事务管理 | 支持声明式和编程式事务(容器自动控制提交/回滚) |
安全性 | 支持基于角色的访问控制、集成 LDAP 等 |
并发管理 | 自动管理线程安全、锁机制 |
生命周期管理 | EJB 容器负责创建、销毁、激活、钝化 Bean 实例 |
远程访问 | 可以作为远程对象提供服务 |
5、示例代码:一个无状态 Session Bean
@Stateless
public class OrderServiceBean implements OrderService {@PersistenceContextprivate EntityManager em;public void createOrder(Order order) {em.persist(order);}
}
客户端调用:
@EJB
private OrderService orderService;orderService.createOrder(new Order(...));
-
@Stateless
:声明这是一个无状态的 EJB。 -
@EJB
:注入一个 EJB 实例。 -
@PersistenceContext
:注入一个持久化上下文(JPA)。
6、EJB 的优势与局限
✅ 优势
-
提供事务、安全、并发等“开箱即用”的企业服务。
-
可扩展性好,适合高并发、高可靠系统。
-
与 JPA、JMS、JTA 等集成顺畅。
⚠️ 局限
-
学习曲线相对陡峭。
-
配置复杂,早期版本(EJB 2.x)冗长繁琐。
-
不适合轻量级应用,因此后来出现了 Spring 等更轻量的替代方案。
7、在 WebSphere / IBM BAW 中的应用场景
在 WebSphere 或 BAW 中,EJB 经常被用于以下场景:
-
多事务资源访问(XA 事务)控制。
-
后端服务接口逻辑封装(如审批流程服务、外部接口集成服务)。
-
消息驱动处理(如与 MQ、JMS 结合处理异步事件)。
-
与规则引擎(如 ODM)整合时调用服务。
总结
特点 | 说明 |
---|---|
本质 | 服务器端组件模型,托管在 Java EE 容器中 |
核心功能 | 事务、安全、生命周期、远程调用 |
核心类型 | 无状态/有状态/单例 Session Bean、消息驱动 Bean |
应用服务器 | 典型如 WebSphere、JBoss、GlassFish |
常见用途 | 封装业务逻辑、服务接口、处理异步消息 |
如果你正在使用 WebSphere 或 BAW 平台,理解和善用 EJB 将有助于你开发高可靠、可维护的企业级 Java 系统。
二、 EJB(Enterprise JavaBeans) 和 Spring Framework对比
下面详细对比 EJB(Enterprise JavaBeans) 和 Spring Framework(主要是 Spring 的 IoC 和 AOP 容器,以及 Spring Boot) 在企业 Java 应用开发中的功能、使用场景和技术理念。这个对比尤其适合像你这样使用 IBM WebSphere(传统上偏向 EJB)、但也可能在未来希望引入更轻量化方案的人。
1、总体定位对比
项目 | EJB(Jakarta EJB) | Spring Framework(+Spring Boot) |
---|---|---|
设计目的 | 构建分布式事务性企业级组件 | 提供轻量级的企业级 Java 编程模型 |
容器 | Java EE 应用服务器(如 WebSphere) | 自带容器,或运行在任何 Servlet 容器中(如 Tomcat) |
典型部署平台 | WebSphere, JBoss, GlassFish | Tomcat, Jetty, 甚至裸 JVM |
使用者 | 偏向传统大型企业开发团队 | 适合各类企业,尤其是现代互联网架构团队 |
2、功能对比(按模块)
1. IoC 容器与组件管理
功能 | EJB | Spring |
---|---|---|
管理 Bean 生命周期 | 有(由容器管理) | 有(IoC 容器管理) |
注入依赖 | @EJB , @Resource | @Autowired , @Inject , 构造器注入 |
组件类型扩展性 | 固定 EJB 类型 | 自定义 @Component、@Service 等扩展灵活 |
2. 事务管理
功能 | EJB | Spring |
---|---|---|
默认支持 | 支持容器管理事务(CMT)和编程事务(BMT) | 支持声明式和编程式事务管理 |
使用方式 | @TransactionAttribute 注解 | @Transactional 注解 |
多数据源支持(JTA) | 强项(原生支持分布式事务) | 依赖外部 JTA(如 Atomikos、Narayana) |
与 JMS 结合事务 | 原生支持 MDB 和 JMS 事务 | 需手动配置 JMS + 事务管理器 |
3. 安全性
功能 | EJB | Spring |
---|---|---|
角色管理 | 支持基于角色的访问控制(@RolesAllowed) | Spring Security 支持 RBAC、OAuth2、JWT 等多种认证授权机制 |
LDAP 集成 | WebSphere 容器级集成 | Spring Security 支持多种身份源,包括 LDAP、自定义数据库等 |
4. AOP(面向切面编程)
功能 | EJB | 基于拦截器支持基本 AOP | Spring AOP(功能强大,广泛应用) |
---|---|---|---|
用途 | 日志、安全、事务等 | 更广泛应用,如缓存、日志、审计 |
5. 远程调用
功能 | EJB | 原生支持 RMI-IIOP,支持远程接口 | Spring 默认是本地调用,可通过 RMI、HTTP、WebService 实现远程 |
---|---|---|---|
通用性 | 限制平台间调用 | 更开放,更现代(支持 REST API) |
6. 开发体验
对比项 | EJB | Spring |
---|---|---|
学习曲线 | 相对陡峭,配置复杂(尤其早期版本) | 更易上手,Spring Boot 提供自动配置 |
开发效率 | 较低(部署、容器启动慢) | 高效(支持热部署、自动装配) |
社区活跃度 | 较低 | 极高,社区生态繁荣 |
3、实际企业应用场景对比
场景 | 推荐使用 EJB | 推荐使用 Spring |
---|---|---|
基于 WebSphere/BAW 的遗留系统维护 | ✅ | 可混合使用 |
分布式事务(JTA,XA)跨数据库、MQ | ✅ 强项 | 需外部集成 |
新开发的微服务系统 | ❌ 不推荐 | ✅ Spring Boot / Spring Cloud 是主流 |
快速交付、DevOps 支持 | ❌(部署慢) | ✅(集成 CI/CD 和容器化) |
业务逻辑重,接口多,团队协作复杂 | ✅(容器分明、规范严谨) | ✅(灵活性好、扩展性强) |
4、总结对比建议
条目 | 优于 Spring 的方面(EJB) | Spring 优势 |
---|---|---|
容器服务能力 | 更强(JTA、JMS、远程调用、线程控制) | 更轻、更快、更灵活 |
配置方式 | 明确但繁琐 | 自动化、模块化、易于维护 |
面向角色 | 偏向 IT 技术管理团队 | 面向敏捷业务团队、开发者友好 |
与 WebSphere 集成 | 深度整合 | 可兼容但非首选 |
5、建议策略(以你当前使用 BAW 和 WAS 为背景)
-
✅ 继续使用 EJB 管理 核心事务服务、MQ 消息监听、流程调度器等容器关键组件。
-
✅ 对于前端接口服务层(如 REST API),可以使用 Spring Boot 与后端 EJB 服务对接。
-
✅ 若计划转向微服务架构或容器化部署,逐步从 EJB 向 Spring Cloud / Quarkus / Micronaut 等现代框架过渡。
三、BAW 业务流程调用 Spring REST 服务
在 IBM Business Automation Workflow(BAW) 中,业务流程调用外部系统是常见需求。而使用 Spring Boot 提供 REST 服务 是现代系统集成的一种高效方式。
下面我将详细说明:
✅ 如何在 BAW 中调用 Spring REST 服务
🔍 包括配置方式、传参方法、安全注意事项、以及错误处理等实际应用细节。
1、场景说明
BAW 中的业务流程(BPD 或 BPMN)需要访问一个外部微服务,比如获取客户信用评分、校验订单、计算折扣等。这些服务由 Spring Boot 开发并通过 REST 接口提供。
2、调用方式
BAW 调用 REST 服务,通常通过内置的 “集成服务(Integration Service)” 实现,使用的是:
-
JavaScript
-
Java
(External Implementation) -
Web Service
(可 REST 或 SOAP) -
REST Connector
(20.0.0.2+ 可直接使用)
3、典型实现方法(以 REST Connector 为例)
1. 准备 Spring Boot 服务
Spring Boot 示例接口:
@RestController
@RequestMapping("/api/customer")
public class CustomerController {@GetMapping("/{id}")public Customer getCustomerById(@PathVariable String id) {return customerService.getCustomer(id);}
}
返回 JSON:
{"id": "123","name": "张三","creditScore": 780
}
2. 在 BAW 中创建 REST 服务接口绑定
方法一:使用 Web Service Integration
-
在 Process Designer 中创建 服务(Service)
-
类型选择为:外部实现(Integration)
-
实现方式:Web Service Integration
-
URL:
http://your-spring-service/api/customer/123
-
设置输入参数、输出参数(可定义为业务对象)
方法二:使用 JavaScript + Ajax(在 UI 中调用)
var result = tw.system.net.http.get("http://your-service/api/customer/123", {headers: {"Accept": "application/json"}
});
tw.local.customerName = result.data.name;
3. 配置 REST Connector(如果使用的是新版 BAW)
如果你使用的是 BAW 20.0.0.2+,支持原生创建 REST Connector:
-
进入 BAW 设计器,选择“集成服务”
-
添加“调用 REST 服务”步骤
-
设置请求 URL、方法、参数、Header(可使用 Basic Auth、JWT、OAuth)
-
绑定响应到
tw.local
变量
4、安全设置
如果 Spring Boot 服务开启了安全认证(如 Spring Security):
方式一:Basic Auth
在 BAW 服务调用时设置:
Authorization: Basic {Base64 编码的 user:password}
方式二:JWT Token / OAuth2
-
先通过身份验证服务获取 Access Token
-
在调用 Spring REST API 时带入:
Authorization: Bearer {token}
5、异常处理
在 REST 调用步骤中配置:
-
如果返回非 200 状态码,使用 BAW 的错误边界事件捕获
-
捕获后可以:
-
写入日志
-
通知人工处理
-
返回错误响应并中止流程
-
6、实际项目注意事项
项目 | 说明 |
---|---|
超时时间 | 默认可能是 30 秒,可在 HTTP Connector 设置自定义超时 |
JSON 映射 | 建议在 BAW 中定义 BO(业务对象)对应 JSON 结构,便于自动绑定 |
版本管理 | BAW 调用 REST 服务时应指定接口版本,防止接口变更影响流程 |
可复用性 | 将通用 REST 调用封装成“通用集成服务模板”,供多个流程复用 |
7、混合架构优势
优势 | 说明 |
---|---|
解耦业务流程与业务逻辑 | BAW 处理流程编排,Spring 处理逻辑,职责清晰 |
更适合微服务架构 | Spring Boot REST 接口可被多个系统访问 |
流程灵活配置 | 接口参数可配置,流程调整无需重写代码 |
支持灰度升级 | 新服务部署后只需调整流程变量或目标地址即可 |
8、示例:业务流程中调用客户风控服务(REST)
[开始] → [输入客户ID] → [调用REST服务获取风控评分] → [评分判断网关] → [通过] / [拒绝]
-
调用 REST 服务步骤使用 Spring 接口
-
若评分<600,走拒绝路径
-
若评分>600,走通过路径
四、IBM BAW 调用 Spring Boot REST 服务的集成案例设计
以下是一个完整的 IBM BAW 调用 Spring Boot REST 服务的集成案例设计,涵盖从微服务接口到 BAW 流程设计的全过程。
案例目标:流程调用客户信用评分服务
IBM BAW 流程在执行中需要根据客户 ID 查询信用评分,评分结果决定流程走向。
1、Spring Boot 微服务接口
1. 项目结构
com.example.customer├── controller.CustomerController├── model.CustomerScore└── service.CustomerService
2. 接口代码
@RestController
@RequestMapping("/api/customer")
public class CustomerController {@GetMapping("/{id}/score")public ResponseEntity<CustomerScore> getScore(@PathVariable String id) {CustomerScore score = new CustomerScore(id, "张三", 750);return ResponseEntity.ok(score);}
}
3. 模型类
public class CustomerScore {private String id;private String name;private int score;// 构造器、getter/setter 略
}
4. 返回示例 JSON
{"id": "123456","name": "张三","score": 750
}
2、BAW 中的流程设计
1. 创建业务对象(BO)
在 BAW Process Designer 中创建业务对象 CustomerScoreBO
:
-
id
: String -
name
: String -
score
: Integer
2. 创建服务:调用 REST 接口
创建服务(Service)名为 CallCustomerScoreREST
,类型选择:
-
实现类型:External Implementation
-
方式一:使用 JavaScript + HTTP Request(适用于 BAW 标准版本)
-
方式二:使用 REST Connector(BAW 20.0.0.2+ 推荐)
JavaScript 实现方式示例:
var response = tw.system.net.http.get("http://localhost:8080/api/customer/" + tw.local.customerId + "/score", {headers: {"Accept": "application/json"}
});
var result = JSON.parse(response.data);
tw.local.customerScore = new tw.object.CustomerScoreBO();
tw.local.customerScore.id = result.id;
tw.local.customerScore.name = result.name;
tw.local.customerScore.score = result.score;
需要配置输入变量
customerId
和输出变量customerScore
3. 创建业务流程(BPD)
流程结构如下:
[开始]↓
[输入客户ID(用户任务)]↓
[调用 CallCustomerScoreREST(集成服务)]↓
[评分判断(网关)]├─ 分支 A: score >= 700 → [通过审批]└─ 分支 B: score < 700 → [拒绝审批]↓
[结束]
4. 错误处理机制
在调用 REST 服务步骤上添加“错误边界事件”,配置为:
-
错误类型:所有错误
-
处理方式:跳转至“错误处理”子流程或人工处理任务
5. UI 表单(可选)
输入客户 ID 的用户任务可关联 Coach 表单:
<h2>客户信用评分流程</h2>
<p>请输入客户ID:</p>
<twx:input value="tw.local.customerId" label="客户ID" />
3、测试流程
-
在 BAW 中部署流程应用
-
启动流程,输入客户ID,如
123456
-
REST 调用返回评分
-
网关判断走向
-
查看流程是否正确流转
4、安全与生产部署建议
项目 | 建议 |
---|---|
接口安全 | Spring Boot 配置 Basic Auth 或 JWT,BAW 中配置认证 Header |
服务地址配置 | BAW 中通过环境变量或服务参数动态配置接口地址 |
超时控制 | BAW HTTP 调用中设置合理超时 |
日志追踪 | 接口调用失败写入业务日志表或监控平台 |
5、后续可扩展
-
接入更多 REST 服务,如订单系统、支付系统
-
配置 REST 连接池优化性能
-
BAW 与 ODM(规则引擎)结合,由规则决定评分策略
-
与 IBM Case Manager 整合,形成完整流程+案件处理平台
6、简单示例
IBM BAW 调用 Spring Boot REST 服务配置文档
=======================================
1. 创建业务对象(CustomerScoreBO):
- id: String
- name: String
- score: Integer
2. 创建服务(CallCustomerScoreREST):
- 输入:customerId(String)
- 输出:customerScore(CustomerScoreBO)
- JavaScript 示例调用:
var response = tw.system.net.http.get("http://localhost:8080/api/customer/" + tw.local.customerId + "/score", {headers: {"Accept": "application/json"}});var result = JSON.parse(response.data);tw.local.customerScore = new tw.object.CustomerScoreBO();tw.local.customerScore.id = result.id;tw.local.customerScore.name = result.name;tw.local.customerScore.score = result.score;
3. 创建流程(BPD):
- 用户任务:输入客户ID
- 服务任务:调用REST服务
- 网关判断:评分高低决定路径
4. 错误边界事件:
- 捕捉调用异常并跳转到错误处理任务
5. Coach 表单绑定:
<twx:input value="tw.local.customerId" label="客户ID" />
7.CustomerController.java
package com.example.customer.controller;import com.example.customer.model.CustomerScore;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/customer")
public class CustomerController {@GetMapping("/{id}/score")public ResponseEntity<CustomerScore> getScore(@PathVariable String id) {CustomerScore score = new CustomerScore(id, "张三", 750);return ResponseEntity.ok(score);}
}
8.CustomerScore.java
package com.example.customer.model;public class CustomerScore {private String id;private String name;private int score;public CustomerScore(String id, String name, int score) {this.id = id;this.name = name;this.score = score;}// Getters and setterspublic String getId() { return id; }public void setId(String id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public int getScore() { return score; }public void setScore(int score) { this.score = score; }
}