Spring SOAP webservice endpoint with Spring AOP

回眸只為那壹抹淺笑 提交于 2019-12-10 11:16:44

问题


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.


回答1:


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




回答2:


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




回答3:


Try configuring a PayloadLoggingInterceptor

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



来源:https://stackoverflow.com/questions/33492267/spring-soap-webservice-endpoint-with-spring-aop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!