添加CDI Extension后Wildfly 25上Java EE 8应用启动失败问题咨询
环境信息
- Java 11(Java 17环境下问题同样可复现)
- Wildfly 25.0.0.Final
初始配置
build.gradle 配置
plugins { id 'java' id 'war' } group 'com.example.extension' version '1.0-SNAPSHOT' sourceCompatibility = 11 war { archiveName 'extension.war' } repositories { mavenCentral() } dependencies { compileOnly group: 'jakarta.platform', name: 'jakarta.jakartaee-api', version: '8.0.0' }
Main.java 代码
package com.example.extension; import javax.annotation.PostConstruct; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.inject.Inject; @Singleton @Startup public class Main { @Inject SampleClass sc; @PostConstruct public void init() { sc.sayHello(); } }
SampleClass.java 代码
package com.example.extension; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped public class SampleClass { public void sayHello() { System.out.println("Hello world"); } }
初始阶段应用运行正常,控制台输出预期日志:
INFO [stdout] (ServerService Thread Pool -- 78) Hello world
问题触发操作
向项目新增如下空类 SampleExtension.java 后,应用启动失败:
package com.example.extension; import javax.enterprise.inject.spi.Extension; public class SampleExtension implements Extension { }
报错信息如下:
com.example.extension : extension.war: java.lang.Exception: {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit."extension.war".component.Main.WeldInstantiator" => "Failed to start service
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type SampleClass with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject com.example.extension.Main.sc
at com.example.extension.Main.sc(Main.java:0)
"}}
com.example.extension : extension.war: Artifact is deployed successfully
补充说明:将代码中javax导入替换为jakarta后,相同逻辑在Jakarta EE 9.1 + GlassFish 6.2.2环境下运行无异常。
根因分析
这是Java EE 8 下CDI 2.0规范的归档判定规则导致的问题:
- 无CDI扩展、无
beans.xml文件时,CDI容器默认走隐式bean归档模式,会自动扫描所有带CDI作用域注解(比如你用到的@ApplicationScoped)的类,将其注册为可注入bean,所以初始运行正常。 - 当项目中存在实现
javax.enterprise.inject.spi.Extension接口的类时,CDI容器会直接判定当前归档为显式bean归档,此时必须存在WEB-INF/beans.xml配置文件,容器才会执行bean扫描注册逻辑。你缺少该配置文件,SampleClass没有被识别为合法bean,就抛出了依赖找不到的异常。
Jakarta EE 9 配套的CDI 3.0调整了显式归档的判定规则,GlassFish内置的Weld实现对新增扩展但无beans.xml的场景做了兼容,所以同逻辑在该环境下不会报错。
修复方案
在项目的src/main/webapp/WEB-INF目录下新增beans.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" bean-discovery-mode="annotated"> </beans>
bean-discovery-mode="annotated"和隐式归档的扫描规则一致,仅会将带CDI作用域注解的类注册为bean,符合当前使用场景。
内容的提问来源于stack exchange,提问作者RoninDev

