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 OpenWebBeansApache OpenWebBeans2026/10/12

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.shTomcat 7/8/9 自动安装
集成插件plugins/openwebbeans-*.jarEE/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.xml bean-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.jarWeb 应用集成(ServletContextListener 引导)
    openwebbeans-tomcat-4.1.1.jarTomcat 集成
    openwebbeans-ee / -ee-commonJava EE 资源注入(@Resource 等)
    openwebbeans-ejbEJB 集成
    openwebbeans-jmsJMS 资源支持
    openwebbeans-jsfJSF 集成
    openwebbeans-el22EL 表达式支持
    openwebbeans-osgiOSGi 环境支持
  • 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.

六、注意事项

⚠️ 注意:

  1. OpenWebBeans 没有 openwebbeans 命令行工具,一切通过 Java API 调用;SeContainerInitializer 需要 classpath 上有 openwebbeans-se-4.1.1.jar(ServiceLoader 注册所在)。
  2. BeanManager.fireEvent() 在 CDI 4.0 已移除,事件发布用 container.getBeanManager().getEvent().select(...).fire(...)。
  3. CDI.current() 依赖线程上下文;跨线程使用请传递容器引用(SeContainer 线程安全)。
  4. 手工 classpath 需同时具备 api/ 下的 cdi-api、annotation-api、inject-api、interceptor-api 四个 jar(补装方法见《安装指南》篇 4.4)。
  5. 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