java Spring Boot 将 JAX-WS 网络服务注册为 bean
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25177491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Boot register JAX-WS webservice as bean
提问by amique
In my spring boot ws based application I have created a jax-ws webservice following a contract first approach. The Web service is up but I cannot autowire my other beans inside my webservice.
在我的基于 spring boot ws 的应用程序中,我按照契约优先的方法创建了一个 jax-ws 网络服务。Web 服务已启动,但我无法在我的 Web 服务中自动装配其他 bean。
How can I define, my webservice in spring as bean?
我如何将 spring 中的 webservice 定义为 bean?
Following is my webservice impl class
以下是我的 webservice impl 类
@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 is geneated by maven from wsdl file
MyServicePortType 由 maven 从 wsdl 文件生成
When I call this service (via SoapUi) it gives NullPointerException as the MyBean object is not autowired.
当我调用此服务(通过 SoapUi)时,它会给出 NullPointerException,因为 MyBean 对象不是自动装配的。
Since my application is built on Spring boot, there is no xml file. Currently I have sun-jaxws.xml
file with endpoint configuration. How can I do following configuration in spring boot application
由于我的应用程序是基于 Spring boot 构建的,因此没有 xml 文件。目前我有sun-jaxws.xml
带有端点配置的文件。如何在 Spring Boot 应用程序中进行以下配置
<wss:binding url="/hello">
<wss:service>
<ws:service bean="#helloWs"/>
</wss:service>
</wss:binding>
Following is my SpringBootServletInitializer class
以下是我的 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());
}
}
thanks
谢谢
回答by Parker Wang
Extending SpringBeanAutowiringSupport
is the recommended way to get beans injected for JAX-WS endpoint class, from current spring root web application context. However this does not work with spring bootas it's a bit different on servlet context initialization.
扩展SpringBeanAutowiringSupport
是从当前 spring 根 Web 应用程序上下文为 JAX-WS 端点类注入 bean 的推荐方法。然而,这不适用于spring boot,因为它在servlet 上下文初始化上有点不同。
Problem
问题
SpringBootServletInitializer.startup()
uses a custom ContextLoaderListener
and does not pass the created application context to ContextLoader
. Later when the object of JAX-WS endpoint class being initialized, SpringBeanAutowiringSupport
depends on ContextLoader
to retrieve the current application context, and always get null
.
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
}
});
}
......
}
}
Workaround
解决方法
You could register a bean that implements org.springframework.boot.context.embedded.ServletContextInitializer
to retrieve the application context during startup()
.
您可以注册一个 bean 来实现org.springframework.boot.context.embedded.ServletContextInitializer
在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);
}
}
Then you could implement self-autowiring in your JAX-WS endpoint class.
然后,您可以在 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);
}
}
Unit Testing
单元测试
In unit tests you could get current spring application context injected, and call alternative constructor with it.
在单元测试中,您可以注入当前的 spring 应用程序上下文,并用它调用替代构造函数。
@Autowired
private ApplicationContext context;
private ServicePortType service;
@Before
public void setup() {
this.service = new ServiceImpl(this.context);
}
回答by jonashackt
You don′t have to extend your Configuration from SpringBootServletInitializer, nor override configure() or onStartup() methods. And in no way you have to build something implementing WebApplicationInitializer. There are only few steps to do (you could also do all the steps in a seperate @Configuration-class, the class with @SpringBootApplication only needs to know, where this one is - e.g. via @ComponentScan).
您不必从 SpringBootServletInitializer 扩展您的配置,也不必覆盖 configure() 或 onStartup() 方法。并且您绝不需要构建一些实现 WebApplicationInitializer 的东西。只需执行几个步骤(您也可以在单独的@Configuration-class 中完成所有步骤,带有@SpringBootApplication 的类只需要知道它在哪里——例如通过@ComponentScan)。
- Register the CXFServlet in an ServletRegistrationBean
- Instantiate a SpringBus
- Instantiate your Implementation of the JAX-WS SEI (Service Interface)
- Instantiate a EndpointImpl with the SpringBus and SEI implementing Beans
- Call publish() method on that EndpointImpl
- 在 ServletRegistrationBean 中注册 CXFServlet
- 实例化一个 SpringBus
- 实例化 JAX-WS SEI(服务接口)的实现
- 使用 SpringBus 和 SEI 实现 Bean 实例化 EndpointImpl
- 在该 EndpointImpl 上调用 publish() 方法
Done.
完毕。
@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;
}
}
回答by Andy Wilkinson
By default Spring doesn't know anything about your JAX-WS endpoints – they're managed by the JAX-WS runtime rather than Spring. You can overcome this by using SpringBeanAutowiringSupportYou'd typically do so simply by subclassing it:
默认情况下,Spring 对 JAX-WS 端点一无所知——它们由 JAX-WS 运行时而不是 Spring 管理。您可以通过使用SpringBeanAutowiringSupport来克服这个问题,您通常只需将其子类化即可:
public class MySoapService extends SpringBeanAutowiringSupport implements MyServicePortType {
…
}
You also have the option of calling it directly from a method annotated with @PostConstruct
:
您还可以选择直接从带有注释的方法中调用它@PostConstruct
:
public class MySoapService implements MyServicePortType {
@PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
}
回答by rajadilipkolli
Taking clue from @Andy Wilkinson using SpringBeanAutoWiringSupportis achieved by using
使用SpringBeanAutoWiringSupport从@Andy Wilkinson获取线索是通过使用实现的
public class MySoapService extends SpringBeanAutowiringSupport implements MyServicePortType {
…
}
You also have the option of calling it directly from a method annotated with @PostConstruct
:
您还可以选择直接从带有注释的方法中调用它@PostConstruct
:
@Service
public class MySoapService implements MyServicePortType {
@Autowired
ServletContext servletContext;
@PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
servletContext);
}
}