在我的spring boot基于ws的应用程序中,我根据合同第一种方法创建了一个jax-ws webservice。 Web服务已启动,但我无法在我的Web服务中自动装配其他bean。
我怎样才能将我的webservice定义为bean?
以下是我的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由来自wsdl文件的maven生成
当我调用此服务时(通过SoapUi),它会给出NullPointerException,因为MyBean对象没有自动装配。
由于我的应用程序是基于Spring启动的,因此没有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());
}
}
感谢
答案 0 :(得分:4)
扩展SpringBeanAutowiringSupport
是从当前Spring根Web应用程序上下文为JAX-WS端点类注入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端点类中实现自动装配。
@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);
}
答案 1 :(得分:2)
您不必从SpringBootServletInitializer扩展配置,也不必覆盖configure()或onStartup()方法。并且绝不必构建实现WebApplicationInitializer的东西。只需要做很少的步骤(你也可以在单独的@Configuration类中完成所有步骤,只有@SpringBootApplication的类需要知道这个步骤 - 例如通过@ComponentScan)。
完成。
@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;
}
}
答案 2 :(得分:1)
默认情况下,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);
}
}
答案 3 :(得分:0)
使用SpringBeanAutoWiringSupport从@Andy Wilkinson获取线索是通过使用
实现的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);
}
}