Spring SOAP webservice endpoint with Spring AOP

2019-05-25 08:23发布

I am developing a webservice using spring soap implementation and hence my service class is annotated with @Endpoint annotation. Now, I want to use SPRING AOP for application logging which I have already implemented. However, as I have noticed, until I execlude my service class from the pointcut expression, I get no endpoint mapping found exception when my webservice is invoked. When I exclude the service classes from AOP's scope, things work fine again. Any idea on this?

UPDATE:

My logger class

package com.cps.arch.logging;

@Component
@Aspect
public class LoggerAspect {

    private static final Logger logger = LoggerFactory.getLogger("Centralized Payment System");

    @Before("(execution(* com.cps..*.*(..)) and not execution(* com.cps.service..*.*(..)))")
    public void logBefore(JoinPoint joinPoint) {

        logger.info("Execution Start : "+"Class: "+joinPoint.getTarget().getClass().getName()+
                "Method: "+joinPoint.getSignature().getName());
    }

}

My Service Endpoint:

package com.cps.service.impl;

@Endpoint
public class EndpointIntegrationServiceImpl  implements EndpointIntegrationService
{
    private static final String NAMESPACE_URI = "http://www.example.com/cps/model";

    @Autowired
    public MYBO myBO ;

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "SaveDataRequest")
    public void saveData(@RequestPayload
            SaveDataRequest data) {
        //business layer invocation
    }
}

My WS Configuration

@EnableWs
@Configuration
@ComponentScan(basePackages={"com.cps"})
public class WebServiceConfig extends WsConfigurerAdapter
{

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name = "MyWsdl")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("MyPort");
        wsdl11Definition.setLocationUri("/ws");
        wsdl11Definition.setTargetNamespace("http://www.example.com/micro/payment/PaymentManagement");
        wsdl11Definition.setSchema(reconciliationSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema schema() {
        return new SimpleXsdSchema(new ClassPathResource("XSD/MySchema.xsd"));
    }

    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        interceptors.add(validationInterceptor());
    }

    @Bean
    ValidationInterceptor validationInterceptor() {
            final ValidationInterceptor payloadValidatingInterceptor = new ValidationInterceptor();
            payloadValidatingInterceptor.setSchema(new ClassPathResource(
                    "XSD/MySchema.xsd"));
            return payloadValidatingInterceptor;
        }
}

Sorry but I had to change few of the variable/class names to adhere to company policy. So as you can see I had to put the "not execution" part in the AOP to make my webservice work. If I remove that part, I get 404 error.

3条回答
Bombasti
2楼-- · 2019-05-25 08:54

Try configuring a PayloadLoggingInterceptor

Check out section "5.5.2.1. PayloadLoggingInterceptor and SoapEnvelopeLoggingInterceptor" in the Spring Reference Docs

查看更多
SAY GOODBYE
3楼-- · 2019-05-25 09:03

So below is the code you shared

package org.example;

import java.util.List;

import org.aspect.PersistentAspect;
import org.springframework.aop.support.AopUtils;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

import javax.annotation.PostConstruct;

@Configuration
@EnableWs
public class WsConfig extends WsConfigurerAdapter {

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        final MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/v1/*");
    }

    @Bean
    public XsdSchema schema() {
        return new SimpleXsdSchema(new ClassPathResource("country.xsd"));
    }

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        String[] jaxbContext = new String[] { "io.spring.guides.gs_producing_web_service" };
        marshaller.setContextPaths(jaxbContext);
        return marshaller;
    }

    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        // aop not working
        //interceptors.add(new CustomValidatingInterceptor(schema(), config()));
        System.out.println("Loading addInterceptors");
        interceptors.add(new CustomValidatingInterceptor(schema(), null));
    }

    @Bean
    public AppConfig config() {
        System.out.println("Loading config Bean");

        return new AppConfig();
    }

    @PostConstruct
    @Bean
    public PersistentAspect persistentAspect() {
        System.out.println("Loading persistentAspect Bean");
        PersistentAspect persistentAspect = new PersistentAspect();

        return persistentAspect;
    }

    @Bean
    public Object testAop(AppConfig config) {
        System.out.println("is config aop proxy: " + AopUtils.isAopProxy(config));

        return config;
    }
}

You mentioned that it doesn't works with

interceptors.add(new CustomValidatingInterceptor(schema(), config()));

But works with

interceptors.add(new CustomValidatingInterceptor(schema(), null));

The issues when you call config manually, the bean is initiated by you and not by Spring and it somehow interferes. You should not initiate the class using the bean method config() instead use the class directory

interceptors.add(new CustomValidatingInterceptor(schema(), new AppConfig()));

And it work fine

查看更多
Root(大扎)
4楼-- · 2019-05-25 09:15

@Tarun is right, though I also found it necessary to delay the initialization of the AppConfig config bean.

Because the CustomValidatingInterceptor bean in your (@hudi's) example is an EndpointInterceptor, it is needed early in the Spring initialization sequence. This means it is being instantiated before the Aop weaving against the config bean has taken effect. Note how there is also an EndpointInterceptor in the original question here.

One way to avoid this is to use an ObjectFactory. This can be wired in from the start, but enables Spring to delay the actual instantiation of the config bean, until after the interceptor and Aop proxy are both well initialized.

There's an example of this back on your question. This tested fine from SoapUI.

查看更多
登录 后发表回答