HandlerValidator中Autowired Bean注入失败问题咨询:XML配置嵌入Bean的实现方案及解决办法
你碰到的这个问题很典型——HandlerValidator是由JAX-WS容器负责实例化的,根本不在Spring的管理范围内,所以Spring的@Autowired注解完全起不了作用,这就是为什么A、B两个Bean在其他Spring管理的类里正常,到这里就成null了。下面给你几个可行的解决方案,从快速修复到优雅实现都有:
方案1:手动触发Spring依赖注入(最快解决)
不需要改太多代码,只需要在Handler的业务方法里,第一次调用时主动让Spring完成注入。修改你的HandlerValidator:
public class HandlerValidator implements SOAPHandler<SOAPMessageContext> { @Autowired A a; @Autowired B b; @Override public boolean handleMessage(SOAPMessageContext context) { // 第一次调用时检查并触发注入 if (a == null) { SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); } // 这里写你的业务逻辑,现在a和b已经能正常使用了 return true; } // 其他方法保持不变 }
这个方法的原理是SpringBeanAutowiringSupport会从当前Web应用的Spring上下文里找到对应的Bean,完成依赖注入。前提是你的Spring上下文已经正确初始化(比如web.xml里配置了ContextLoaderListener)。
方案2:让Spring完全接管Handler实例(更优雅)
如果想彻底让Spring管理Handler,避免手动注入的代码,可以这么做:
- 先给
HandlerValidator加上@Component注解,让Spring扫描并管理它:
@Component public class HandlerValidator implements SOAPHandler<SOAPMessageContext> { // 原有代码不变 }
- 实现一个自定义的
HandlerFactory,从Spring上下文里获取Handler实例:
public class SpringHandlerFactory implements HandlerFactory { private ApplicationContext springContext; public SpringHandlerFactory() { // 从Web容器中获取Spring上下文 springContext = WebApplicationContextUtils.getWebApplicationContext( ServletActionContext.getServletContext()); } @Override public List<Handler> createHandlerChain(PortInfo portInfo) { List<Handler> handlerChain = new ArrayList<>(); // 从Spring上下文取出我们的Handler handlerChain.add(springContext.getBean(HandlerValidator.class)); return handlerChain; } }
- 最后在你的Web服务配置里指定这个Factory——比如在
@WebService注解所在的类上添加@HandlerChain,或者在JAX-WS的XML配置里配置这个Factory(不同JAX-WS实现的配置方式略有差异,比如Metro可以通过@EndpointConfig指定)。
方案3:通过Spring XML配置注入Handler的依赖(对应你提到的XML嵌入Bean需求)
你没法直接在JAX-WS的handler-chains XML里嵌入Spring的Bean配置,因为那个XML是JAX-WS的规范配置,和Spring无关。但你可以在Spring自己的XML配置里定义Handler并注入依赖:
- 在Spring的
applicationContext.xml里定义HandlerValidator的Bean,并注入A和B:
<bean id="handlerValidator" class="xxx.validator.HandlerValidator"> <property name="a" ref="a"/> <property name="b" ref="b"/> </bean>
(这里假设A、B的Bean id分别是a和b,和你配置类里@Bean定义的一致)
2. 然后结合方案1或者方案2的方式,让JAX-WS使用这个Spring管理的Handler实例就行。
额外注意
如果你的Web服务是通过Endpoint.publish手动发布的(不是部署在Web容器里),那获取Spring上下文的方式需要调整——比如手动初始化ClassPathXmlApplicationContext,再从中获取Bean。
内容的提问来源于stack exchange,提问作者Mary

