Spring Boot register JAX-WS webservice as bean

后端 未结 4 1787
天命终不由人
天命终不由人 2021-01-03 01:47

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 ins

4条回答
  •  佛祖请我去吃肉
    2021-01-03 02:10

    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 boot as it's a bit different on servlet context initialization.

    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.

    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().

    @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.

    @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.

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

提交回复
热议问题