首页 > 解决方案 > 为什么@EnableWs 从 spring bean 中删除了 aop 代理

问题描述

我正在尝试在我的 Spring Boot Web 服务项目中添加自定义拦截器。我按照这个例子创建了这个配置:

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;

@EnableWs
@Configuration
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()));
        // aop working
        // interceptors.add(new CustomValidatingInterceptor(schema(), null));
    }

    @Bean
    public AppConfig config() {
        return new AppConfig();
    }

    @Bean
    public PersistentAspect persistentAspect() {
        PersistentAspect persistentAspect = new PersistentAspect();
        return persistentAspect;
    }

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

        return null;
    }
}

但是,当我在addInterceptors方法中添加新的拦截器时,我在配置类中删除了 aop 代理有问题。知道为什么吗?整个项目在git上。

标签: javaspringspring-bootaop

解决方案


问题是 Spring 中的初始化序列。从技术上讲,因为有一个BeanPostProcessor用于 WS 端点(AnnotationActionEndpointMapping在 spring-ws 中),它将强制提前初始化所需的任何依赖项——尤其是任何EndpointInterceptorbean。

解决此问题的一种方法是重新排列 BeanPostProcessor,甚至创建自己的,但通常在 Spring 中保持默认配置更简单 - 以避免在初始化序列的其他地方出现类似的意外。

避免该问题的更简单方法可能是ObjectFactoryEndpointInterceptorbean 中使用 an 。这将延迟实例化AppConfigbean,直到它被引用,此时 Aop 编织也将发生。

@Component
public class CustomValidatingInterceptor extends PayloadValidatingInterceptor {

    @Autowired
    private ObjectFactory<AppConfig> konfigurace;

    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint)
            throws IOException, SAXException, TransformerException {
        System.out.println("is config aop proxy in interceptor: " +
                AopUtils.isAopProxy(konfigurace.getObject()));
        return super.handleRequest(messageContext, endpoint);
    }

显然,这意味着CustomValidatingInterceptor必须从WsConfig注入的(自动装配的)bean 中引用它。

感谢您的示例 - 这里有一个使用ObjectFactory技术的叉子。当我从 SoapUI 发送请求时,这将 bean 显示为所有的configAop 代理。WsConfig.testAop()CountryEndpointCustomValidatingInterceptor


推荐阅读