Tomcat9部署Weld3.1.8 CDI2.0后JAX-WS服务注入空指针如何解决
问题原因
- 核心问题:默认情况下,Tomcat上的JAX-WS实现(Metro)创建的
@WebService端点实例不受CDI容器(Weld)管理,即使Weld本身启动正常,也不会处理端点类中的@Inject注解,导致注入对象为空。 - 次要问题:你使用的
@ManagedBean注解属于Java EE通用托管Bean注解,而非CDI规范的作用域注解,虽然bean-discovery-mode="all"配置下可以被扫描到,但存在托管兼容性风险。
修复步骤
- 替换Bean的注解为CDI规范的作用域注解,根据你的业务需求选择合适的作用域,示例用请求作用域:
package com.example.app; import javax.enterprise.context.RequestScoped; @RequestScoped public class SomeObject { public String sayHello(){ return "hello from some object :)"; } }
- 修复
@WebService端点的注入问题,有两种常用方案可选:
方案1:手动通过BeanManager获取托管实例(无需额外依赖)
因为你已经在context.xml中配置了BeanManager资源,可以在端点初始化时手动查找CDI托管的Bean:
package com.example.app; import javax.annotation.PostConstruct; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.enterprise.inject.spi.BeanManager; import javax.jws.WebService; import javax.jws.WebMethod; import javax.jws.WebParam; @WebService(serviceName = "MyService") public class MyService { private SomeObject object; @PostConstruct public void init() { try { InitialContext ic = new InitialContext(); BeanManager beanManager = (BeanManager) ic.lookup("java:comp/env/BeanManager"); // 从CDI容器获取SomeObject的托管实例 object = (SomeObject) beanManager.getBeans(SomeObject.class) .iterator().next() .create(beanManager.createCreationalContext(null)); } catch (NamingException e) { throw new RuntimeException("初始化CDI Bean失败", e); } } @WebMethod(operationName = "hello") public String hello(@WebParam(name = "name") String txt) { return "Hello " + object.sayHello() + " !"; } }
方案2:添加Metro CDI集成依赖(支持原生@Inject)
添加Metro对应的CDI扩展依赖到项目中,让JAX-WS运行时支持CDI注入到端点实例,无需手动查找,配置完成后可直接保留原有@Inject写法。
内容的提问来源于stack exchange,提问作者drewpol
相关产品推荐
相关产品推荐

