java - Spring Boot 将 JAX-WS webservice 注册为 bean

标签 java spring spring-boot web-services jax-ws

在我基于 spring boot ws 的应用程序中,我按照契约优先的方法创建了一个 jax-ws web 服务。 Web 服务已启动,但我无法在我的 web 服务中 Autowiring 其他 bean。

我如何在 spring 中将我的 web 服务定义为 bean?

以下是我的网络服务实现类:

@WebService(endpointInterface = "com.foo.bar.MyServicePortType")
@Service
public class MySoapService implements MyServicePortType {
    @Autowired
    private MyBean obj;

    public Res method(final Req request) {
        System.out.println("\n\n\nCALLING.......\n\n" + obj.toString()); //obj is null here
        return new Res();
    }
}

MyServicePortType 由 maven 从 wsdl 文件生成

当我调用此服务(通过 SoapUi)时,它会给出 NullPointerException,因为 MyBean 对象不是 Autowiring 的。

由于我的应用程序是基于 Spring boot 构建的,因此没有 xml 文件。目前我有带有端点配置的 sun-jaxws.xml 文件。如何在 spring boot 应用程序中进行以下配置

<wss:binding url="/hello">
    <wss:service>
        <ws:service bean="#helloWs"/>
    </wss:service>
</wss:binding>

以下是我的 SpringBootServletInitializer 类:

@Configuration
public class WebXml extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
        return application.sources(WSApplication.class);
    }

    @Bean
    public ServletRegistrationBean jaxws() {
        final ServletRegistrationBean jaxws = new ServletRegistrationBean(new WSServlet(), "/jaxws");
        return jaxws;
    }

    @Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.addListener(new WSServletContextListener());
    }
}

最佳答案

扩展 SpringBeanAutowiringSupport 是从当前 spring 根 Web 应用程序上下文中为 JAX-WS 端点类注入(inject) bean 的推荐方法。然而,这不适用于 spring boot,因为它在 servlet context initialization 上有点不同。 .

问题

SpringBootServletInitializer.startup() 使用自定义的 ContextLoaderListener 并且不会将创建的应用程序上下文传递给 ContextLoader。稍后当 JAX-WS 端点类的对象被初始化时,SpringBeanAutowiringSupport 依赖于 ContextLoader 来检索当前应用程序上下文,并且总是得到 null

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        WebApplicationContext rootAppContext = createRootApplicationContext(
                servletContext);
        if (rootAppContext != null) {
            servletContext.addListener(new ContextLoaderListener(rootAppContext) {
                @Override
                public void contextInitialized(ServletContextEvent event) {
                    // no-op because the application context is already initialized
                }
            });
        }
        ......
    }
}

解决方法

您可以注册一个实现 org.springframework.boot.context.embedded.ServletContextInitializer 的 bean,以在 startup() 期间检索应用程序上下文。

@Configuration
public class WebApplicationContextLocator implements ServletContextInitializer {

    private static WebApplicationContext webApplicationContext;

    public static WebApplicationContext getCurrentWebApplicationContext() {
        return webApplicationContext;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
    }
}

然后您可以在您的 JAX-WS 端点类中实现自 Autowiring 。

@WebService
public class ServiceImpl implements ServicePortType {

    @Autowired
    private FooBean bean;

    public ServiceImpl() {
        AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
        WebApplicationContext currentContext = WebApplicationContextLocator.getCurrentWebApplicationContext();
        bpp.setBeanFactory(currentContext.getAutowireCapableBeanFactory());
        bpp.processInjection(this);
    }

    // alternative constructor to facilitate unit testing.
    protected ServiceImpl(ApplicationContext context) {
        AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
        bpp.setBeanFactory(new DefaultListableBeanFactory(context));
        bpp.processInjection(this);
    }
}

单元测试

在单元测试中,您可以注入(inject)当前的 spring 应用程序上下文,并使用它调用替代构造函数。

@Autowired 
private ApplicationContext context;

private ServicePortType service;

@Before
public void setup() {
    this.service = new ServiceImpl(this.context);
}

关于java - Spring Boot 将 JAX-WS webservice 注册为 bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25177491/

相关文章:

java - 无法启动 RESTful Web 服务 IntelliJ

java - 在java中排队字节数据

spring - 如何为每个 block 创建多个文件(csv)?

java - 使用我自己的身份验证类(Spring MVC)时,用户在注销后仍然登录

spring - 使用 @ControllerAdvice 制作简单的 servlet 过滤器

java - 使用 java config 为授权服务器端点配置 Spring OAuth2 表达式处理程序方法

java - 如何使用 JOSS 在 OpenStack 容器上写入文件

java - 运行时未找到方面

java - 如何即时修改 java 属性?

spring-boot - Spring-Boot 配置 : How to keep whitespace in yaml key being used to populate Map<String, 字符串>