Web Services Sping Boot 将JAX-WS Web服务注册为Bean

7tofc5zh  于 2022-11-15  发布在  其他
关注(0)|答案(5)|浏览(165)

在我的基于ws的Sping Boot 应用程序中,我创建了一个jax-ws webservice,它遵循了契约优先的方法。
我如何定义,我的web服务在Spring作为bean?
以下是我的Web服务实现类:

@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对象不是自动连接的。
由于我应用程序是在Sping Boot 上构建,因此没有xml文件当前我有一个包含终结点配置sun-jaxws.xml文件如何在Spring启动应用程序中进行以下配置

<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());
    }
}
2q5ifsrm

2q5ifsrm1#

扩展SpringBeanAutowiringSupport是从当前Spring根Web应用程序上下文为JAX-WS端点类注入Bean的推荐方法。但是,这不适用于**Sping Boot **,因为它在servlet上下文初始化上稍有不同。
问题
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端点类中实现自自动装配。

@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);
    }
}

单元测试

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

@Autowired 
private ApplicationContext context;

private ServicePortType service;

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

e4eetjau2#

默认情况下Spring不知道你的JAX-WS端点的任何信息--它们是由JAX-WS运行时而不是Spring管理的。你可以通过使用SpringBeanAutowiringSupport来克服这个问题你通常只需要简单地将它子类化就可以做到这一点:

public class MySoapService extends SpringBeanAutowiringSupport implements MyServicePortType {
    …
}

您也可以选择从使用@PostConstruct注解的方法直接调用它:

public class MySoapService implements MyServicePortType {

    @PostConstruct
    public void init() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }
}
xv8emn3q

xv8emn3q3#

你不需要从SpringBootServletInitializer扩展你的配置,也不需要覆盖configure()或onStartup()方法。你也不需要构建实现WebApplicationInitializer的东西。只有几个步骤要做(你也可以在一个单独的@Configuration-class中完成所有的步骤,带有@SpringBootApplication的类只需要知道这个类在哪里, -例如通过@ComponentScan)。
1.在Servlet注册Bean中注册CXFServlet
1.示例化SpringBus
1.示例化JAX-WS SEI(服务接口)的实现
1.使用SpringBus和SEI实现Bean示例化EndpointImpl
1.对该EndpointImpl调用publish()方法
好了,好了

@SpringBootApplication
public class SimpleBootCxfApplication {

    public static void main(String[] args) {
        SpringApplication.run(SimpleBootCxfApplication.class, args);
    }

    @Bean
    public ServletRegistrationBean dispatcherServlet() {
        return new ServletRegistrationBean(new CXFServlet(), "/soap-api/*");
    }

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }    

    @Bean
    public WeatherService weatherService() {
        return new WeatherServiceEndpoint();
    }

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(springBus(), weatherService());
        endpoint.publish("/WeatherSoapService");
        return endpoint;
    }
}
i1icjdpr

i1icjdpr4#

试着这样看:@ Servlet组件扫描

@SpringBootApplication
@EnableTransactionManagement
@ServletComponentScan
public class TelecomApplication { .... }
g6ll5ycj

g6ll5ycj5#

从@Andy威尔金森使用SpringBeanAutoWiringSupport获取线索是通过使用

public class MySoapService extends SpringBeanAutowiringSupport implements MyServicePortType {
    …
}

您也可以选择从使用@PostConstruct注解的方法直接调用它:

@Service
public class MySoapService implements MyServicePortType {

    @Autowired
    ServletContext servletContext;

    @PostConstruct
    public void init() {
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
            servletContext);
    }
}

相关问题