7

i seem to run into a small issue when using @Autowired into a custom cxf interceptor. My use case is that i want to log soap messages and send these using AMQP to another system. This process works for normal services etc. But whatever i do, the needed properties do not get autowired and stay null.

I checked the Spring DI log and the context is scanned and pickedup, so what am i missing?

Is this even possible in CXF interceptors?

@Component
public class LogInInterceptor extends AbstractSoapInterceptor {

    private @Value("#{rabbitMQProperties['rabbitmq.binding.log.soap']}")
    String binding;

    @Autowired
    AmqpTemplate amqpTemplate;

    public LogInInterceptor() {
        super(Phase.RECEIVE);
    }

    @Override
    public void handleMessage(SoapMessage soapMessage) throws Fault {
        logIt(soapMessage);
    }

    private void logIt(SoapMessage message) throws Fault {
        // rest of the code omitted...!!!     
        amqpTemplate.convertAndSend(binding, buffer.toString());
    }

}
Marco
  • 15,101
  • 33
  • 107
  • 174
  • By "picked up" you mean that your LogInInterceptor is being found and is eligible for injection from the Spring container? Has it reported any other problems with the injection (such as failing at the @Value parameter)? – Jonathan W Jun 04 '12 at 21:27
  • Can you please share the configuration for this interceptor with CXF also. The reason for this issue may be that the interceptor may have been instantiated by CXF and a separate autowired instance may have been created by Spring. – Biju Kunjummen Jun 04 '12 at 21:32
  • I have implemented the interceptor as above and added it to my webservice via the @org.apache.cxf.interceptor.InInterceptors (interceptors = {"org.apache.cxf.interceptor.LoggingInInterceptor","mypackagenames.ws.interceptor.LogInInterceptor"}) I performed no addtional configuration at all. – Marco Jun 05 '12 at 06:35
  • Marco, that's why. CXF is creating the object and using that one, not Spring. – Jonathan W Jun 05 '12 at 18:38

2 Answers2

8

You can't mix @InInterceptors (a CXF annotation) and @Component (a Spring annotation). That will create two separate instances of your interceptor: the one whose dependencies are getting injected by Spring, and one created by CXF. (You are providing class names in the @InInterceptors annotation, not a bean ID, so CXF has no way of knowing that you already created an instance in the Spring context.)

Remove the @InInterceptors annotation and, in addition to the component scan:

<context:component-scan base-package="org.example.config"/>

You also need something like this in your application context:

<jaxws:endpoint id="myWebService" address="/MyWebService">
    <jaxws:inInterceptors>
        <ref bean="myInInterceptor" />
    </jaxws:inInterceptors>
</jaxws:endpoint>
Jonathan W
  • 3,759
  • 19
  • 20
  • The component scan is successfull, the correct package name is in the spring xml file. Still the properties are not injected.. Any other clue? – Marco Jun 05 '12 at 05:18
  • Its working! Thanks for the clear explanation and help implementing this. – Marco Jun 07 '12 at 15:18
1

I know this is an old question, but Jonathan W's answer helped me and I would like to add to it.

This is how I got custom interceptors and @Autowired to work with Spring Boot 1.3.1:

http://cxf.apache.org/docs/jax-ws-configuration.html

import java.util.Arrays;

import javax.jws.WebService;

import org.apache.cxf.Bus;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@EnableAutoConfiguration
@ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class Application extends SpringBootServletInitializer {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private MyInterceptor myInterceptor;

    @Autowired
    private HelloWorldImpl helloWorldImpl;

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

    // Replaces the need for web.xml
    @Bean
    public ServletRegistrationBean servletRegistrationBean(ApplicationContext context) {
        return new ServletRegistrationBean(new CXFServlet(), "/api/*");
    }

    // Replaces cxf-servlet.xml
    @Bean
    // <jaxws:endpoint id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld"/>
    public EndpointImpl helloService() {
        Bus bus = (Bus) applicationContext.getBean(Bus.DEFAULT_BUS_ID);
        EndpointImpl endpoint = new EndpointImpl(bus, helloWorldImpl);

        // Set interceptors here
        endpoint.setInInterceptors(Arrays.asList(myInterceptor));

        endpoint.publish("/hello");
        return endpoint;
    }


    // Used when deploying to a standalone servlet container, i.e. tomcat
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    // Web service endpoint
    @WebService(endpointInterface = "demo.spring.service.HelloWorld")
    //@InInterceptors not defined here
    public static class HelloWorldImpl {

    }

    public static class MyInterceptor extends LoggingInInterceptor {
      // @Autowired works here
    }

}
Northmoor
  • 531
  • 5
  • 5