Apache OpenWebBeans 4.1.1 常用工具与 API 详解
Apache OpenWebBeans 4.1.1 常用工具与 API 详解:说明 OpenWebBeans 无独立命令行工具、以 jar 库 + CDI SE 容器形态使用,逐类速查 SeContainerInitializer / SeContainer / CDI.current / 事件 Event / OpenWebBeansConfiguration 配置读取 API 与二进制分发包附带工具(install 脚本、插件 jar),含代码示例与实测回显、FAQ。
Apache OpenWebBeans 4.1.1 常用工具与 API 详解
目标:详解 Apache OpenWebBeans 4.1.1 的核心 API 与附带工具使用。OpenWebBeans 没有独立命令行可执行程序,以「jar 库 + CDI SE 容器」形态提供,通过 Java 代码调用。本文按类速查
SeContainerInitializer/SeContainer/CDI.current()/事件Event/OpenWebBeansConfiguration等关键 API,并介绍二进制分发包自带的安装脚本与插件 jar。所有示例在 Ubuntu 22.04.5 + JDK 21 + OpenWebBeans 4.1.1 环境实测。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS
- Java:OpenJDK 21.0.12.1
- OpenWebBeans 版本:4.1.1(openwebbeans-se / openwebbeans-impl / openwebbeans-spi)
- CDI API:jakarta.enterprise.cdi-api 4.1.0(SeContainerInitializer / SeContainer / CDI)
- 安装目录:
/opt/openwebbeans/(二进制分发包) - 示例工程:
/root/owb-demo/
二、工具概览
OpenWebBeans 以「类库 + jar + 分发包脚本」形态提供,没有 openwebbeans 命令行可执行程序;对容器的全部操作通过 Java API 完成。实际使用方式是把 jar 放进 classpath(Maven 依赖或 -cp),在 Java 类中调用以下核心 API 与附带工具:
| 工具/API 类别 | 代表类/文件 | 作用 |
|---|---|---|
| 容器启动/关闭 | SeContainerInitializer、SeContainer | 引导 CDI SE 容器 |
| 全局访问 | CDI.current() | 应用内任意位置取容器与 BeanManager |
| 事件机制 | Event<T>、@Observes | 发布与观察事件 |
| 配置读取 | OpenWebBeansConfiguration、WebBeansContext | 读取生效配置参数 |
| 分发包脚本 | install_owb_tomcat7.sh | Tomcat 7/8/9 自动安装 |
| 集成插件 | plugins/openwebbeans-*.jar | EE/EJB/JMS/JSF/OSGi/Tomcat/Web 集成 |
三、前置条件
安装 JDK 21 与 OpenWebBeans 4.1.1 依赖,编译运行示例工程:
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
cd /root/owb-demo
mvn -q compile
四、核心 API 详解
4.1 SeContainerInitializer(容器引导)
SeContainerInitializer 是 CDI SE 标准的容器引导入口,newInstance() 经 ServiceLoader 找到 OpenWebBeans 的实现(org.apache.openwebbeans.se.SeInitializerFacade / OWBInitializer)。实测可用方法(jakarta.enterprise.cdi-api 4.1.0):
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
SeContainerInitializer initializer = SeContainerInitializer.newInstance();
initializer.addBeanClasses(GreetingService.class, UserService.class); // 显式追加 Bean 类
initializer.addPackages("demo"); // 按包名扫描
initializer.addProperty("org.apache.webbeans.scanner.maxThreads", "2");// 程序化配置
SeContainer container = initializer.initialize(); // 启动容器
container.close(); // 关闭容器
| 方法 | 说明 |
|---|---|
newInstance() | 静态工厂,发现 CDI 实现(缺 openwebbeans-se jar 时报 No valid CDI implementation found,实测复现) |
addBeanClasses(Class...) | 显式注册 Bean 类 |
addPackages(Class/Package...) | 按包扫描注册 |
addExtensions(Extension...) | 注册 Portable Extension |
enableInterceptors / enableDecorators(Class...) | 启用拦截器/装饰器 |
selectAlternatives / selectAlternativeStereotypes | 选择替代 Bean/替代 stereotype |
addProperty(String, Object) | 配置容器属性(优先级最高,实测可覆盖文件与 -D) |
setProperties(Map) | 批量设置属性 |
disableDiscovery() | 关闭自动发现(配合 addBeanClasses 精确控制) |
setClassLoader(ClassLoader) | 指定容器类加载器 |
initialize() | 启动容器,返回 SeContainer |
4.2 SeContainer(容器句柄)
SeContainer 继承 Instance<Object> 与 AutoCloseable,实测方法:
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
boolean running = container.isRunning(); // 容器是否运行中
UserService svc = container.select(UserService.class).get(); // 按类型取 Bean(Instance API)
jakarta.enterprise.inject.spi.BeanManager bm = container.getBeanManager(); // BeanManager
}
| 方法 | 说明 |
|---|---|
select(Class).get() | 按类型/限定符解析并返回 Bean 实例(Instance API) |
isRunning() | 容器运行状态 |
getBeanManager() | 获取 BeanManager(元数据查询、事件等) |
getBeanContainer() | 获取 BeanContainer(CDI 4 新增,BeanManager 的轻量视图) |
close() | 关闭容器(try-with-resources 自动调用) |
💡 实测:
container.select(GreetingService.class).get().getClass().getName()返回demo.GreetingService$$OwbNormalScopeProxy0,证明应用作用域 Bean 通过客户端代理访问。
4.3 CDI.current()(全局容器访问)
容器运行期间,任意位置可通过静态 CDI.current() 拿到容器:
import jakarta.enterprise.inject.spi.CDI;
CDI<Object> cdi = CDI.current();
UserService svc = cdi.select(UserService.class).get();
jakarta.enterprise.inject.spi.BeanManager bm = cdi.getBeanManager();
| 方法 | 说明 |
|---|---|
CDI.current() | 返回当前线程绑定的 CDI 容器 |
select(Class).get() | 同 Instance API 取 Bean |
getBeanManager() | 取 BeanManager |
setCDIProvider(CDIProvider) | 手工指定 CDI 提供者(一般无需调用) |
⚠️ 注意:
CDI.current()依赖线程上下文(CDIProvider按线程绑定),需在容器激活期间调用;异步线程中若容器未传播上下文,应先取得容器引用再传递。
4.4 事件 API(Event + @Observes)
CDI 事件机制:用 Event<T>.fire() 发布,用 @Observes 方法观察。实测示例:
import jakarta.enterprise.event.Event;
import jakarta.enterprise.event.Observes;
// 发布端(4.x 从 BeanManager 取 Event,BeanManager.fireEvent 已移除)
container.getBeanManager().getEvent().select(GreetingEvent.class)
.fire(new GreetingEvent("hello-from-fireEvent"));
// 观察端
public class GreetingObserver {
public void onGreeting(@Observes GreetingEvent event) {
System.out.println("[Observer] received event: " + event.getMessage());
}
}
实测回显(完整运行见《构建并运行示例应用指南》篇):
[Observer] received event: hello-from-fireEvent
💡 说明:
@Observes打在观察方法参数上;观察者与事件类需被容器扫描(beans.xmlbean-discovery-mode="all")。事件可带限定符做精细化订阅(@Observes @Qualifier)。
4.5 OpenWebBeansConfiguration(配置读取)
运行期读取容器生效配置(实测方法):
import org.apache.webbeans.config.OpenWebBeansConfiguration;
import org.apache.webbeans.config.WebBeansContext;
OpenWebBeansConfiguration cfg = WebBeansContext.getInstance().getOpenWebBeansConfiguration();
String maxThreads = cfg.getProperty("org.apache.webbeans.scanner.maxThreads"); // 实测默认 "8"
String missing = cfg.getProperty("org.apache.webbeans.does.not.exist", "fb"); // 缺省回退 "fb"
int scannerThreads = cfg.getScannerServiceMaxThreads(); // 8
int deployerThreads = cfg.getBeanDeployerMaxThreads(); // 8
实测默认值回显:
CONFIG scanner.maxThreads = 8
CONFIG deployer.maxThreads = 8
CONFIG defaultBeanDiscoveryMode = ALL
CONFIG ContainerLifecycle = org.apache.webbeans.lifecycle.StandaloneLifeCycle
| 方法 | 说明 |
|---|---|
getProperty(String) / getProperty(String, String) | 读配置(带默认回退) |
getScannerServiceMaxThreads() | 扫描线程数(默认 8) |
getBeanDeployerMaxThreads() | 部署线程数(默认 8) |
getDefaultBeanDiscoveryMode() | 默认 Bean 发现模式(默认 ALL) |
splitValues(String) | 逗号/换行分隔值解析 |
4.6 二进制分发包附带工具
-
install_owb_tomcat7.sh:把 OpenWebBeans 安装进 Tomcat 7/8/9 的脚本(安装指南注明其同时兼容 Tomcat 8/9)。执行方式(需 Tomcat 已安装):
cd /opt/openwebbeans bash install_owb_tomcat7.sh <TOMCAT_HOME>⚠️ 注意:本脚本面向 Web 容器部署场景(ServletContextListener 引导),SE 应用无需执行;示例以 SE 容器为主,脚本未在本文运行验证,具体参数以脚本内帮助为准。
-
插件 jar(
/opt/openwebbeans/plugins/):按部署形态按需加入 classpath。插件 用途 openwebbeans-web-4.1.1.jar Web 应用集成(ServletContextListener 引导) openwebbeans-tomcat-4.1.1.jar Tomcat 集成 openwebbeans-ee / -ee-common Java EE 资源注入(@Resource 等) openwebbeans-ejb EJB 集成 openwebbeans-jms JMS 资源支持 openwebbeans-jsf JSF 集成 openwebbeans-el22 EL 表达式支持 openwebbeans-osgi OSGi 环境支持 -
config/openwebbeans.properties:默认配置参考文件(17856 字节),覆盖方式见《配置参数详解》篇。
五、完整最小可运行示例
把上述 API 串成一次「启动容器 → 取 Bean → 发事件 → 关闭容器」的完整程序(对应《构建并运行示例应用指南》篇的可执行源码核心调用):
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
UserService userService = container.select(UserService.class).get();
System.out.println(userService.welcome("Apache OpenWebBeans"));
container.getBeanManager().getEvent().select(GreetingEvent.class)
.fire(new GreetingEvent("hello-from-fireEvent"));
}
运行实测输出(节选):
CDI container started: true
Hello, Apache OpenWebBeans! (call #1)
Hello, World! (call #2)
GreetingService instance: demo.GreetingService$$OwbNormalScopeProxy0
[Observer] received event: hello-from-fireEvent
CDI container stopped.
六、注意事项
⚠️ 注意:
- OpenWebBeans 没有
openwebbeans命令行工具,一切通过 Java API 调用;SeContainerInitializer需要 classpath 上有openwebbeans-se-4.1.1.jar(ServiceLoader 注册所在)。BeanManager.fireEvent()在 CDI 4.0 已移除,事件发布用container.getBeanManager().getEvent().select(...).fire(...)。CDI.current()依赖线程上下文;跨线程使用请传递容器引用(SeContainer 线程安全)。- 手工 classpath 需同时具备 api/ 下的 cdi-api、annotation-api、inject-api、interceptor-api 四个 jar(补装方法见《安装指南》篇 4.4)。
- SE 容器 Bean 与代理类驻留 JVM 堆,运行参数建议
-Xms256m -Xmx512m。
七、常见问题
Q1:OpenWebBeans 有命令行工具吗?
没有独立的命令行可执行程序。容器引导、Bean 解析、事件、配置全部通过 Java API(SeContainerInitializer / CDI.current / BeanManager / OpenWebBeansConfiguration)完成;Web 部署场景可用分发包自带的 install_owb_tomcat7.sh 脚本安装到 Tomcat。
Q2:CDI.current() 抛 IllegalStateException: Unable to identify any CDI providers?
容器未启动或当前线程无容器上下文。在容器激活期间调用,或改用 SeContainer 引用(container.select(...))。
Q3:newInstance() 报 No valid CDI implementation found?
classpath 缺少 openwebbeans-se jar(其 META-INF/services/jakarta.enterprise.inject.se.SeContainerInitializer 注册了 org.apache.openwebbeans.se.SeInitializerFacade)。补依赖后重启。
Q4:addProperty 方法找不到?
CDI 4.x 的方法名是 addProperty(String, Object)(不是 setProperty)。若使用旧文档的 setProperty 会编译失败(实测复现)。
Q5:事件观察方法没被调用?
检查 @Observes 是否打在参数上、观察者类是否被扫描(bean-discovery-mode="all")、事件类型是否精确匹配(子类事件不会触发父类观察,除非加 @Observes 的继承语义配置)。
Q6:怎么查看当前生效的配置?
用 WebBeansContext.getInstance().getOpenWebBeansConfiguration().getProperty(key) 打印(实测回显见 4.5),或参考《配置参数详解》篇 3.3。
八、参考链接
- OpenWebBeans 官网:
https://openwebbeans.apache.org/ - CDI 4.0 API 文档:
https://jakarta.ee/specifications/cdi/4.0/apidocs/ - SeContainerInitializer API:
https://jakarta.ee/specifications/cdi/4.0/apidocs/jakarta/enterprise/inject/se/SeContainerInitializer.html - OpenWebBeans 源码与文档:
https://github.com/apache/openwebbeans