@Endpoint和@Transactional使用Spring-ws库在同一个类上

时间:2013-05-02 19:27:06

标签: spring spring-ws

我正在尝试实现一个事务性的Web服务端点,因为我不想使用事务方法创建一个特殊的“worker”类。我正在使用Spring-ws库和Spring框架。

这是我的班级定义:

@Endpoint
@Transactional
@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyEndpoint implements ApplicationContextAware { ... }

请注意,我明确指定了使用CGLIB强制使用代理方法。

另请注意,我的类实现了一些接口,因此默认情况下,Spring使用JDK动态代理,除非指定了另一个代理方法。在我的情况下,这种代理是不合适的。

PayloadRootAnnotationMethodEndpointMapping类开始工作时,问题将从应用程序部署开始。它使用@Endpoint注释收集所有Spring bean的名称。我的端点类计数两次,名称为“myEndpoint”和“scopedTarget.myEndpoint”。这种重复导致ApplicationContextException消息“无法在注册密钥[...]上映射端点[...]:已经有[...]映射的端点”。

问题:如何使我的端点类成为事务性的?

1 个答案:

答案 0 :(得分:0)

您可以编写自己的PayloadRootAnnotationMethodEndpointMapping扩展名并覆盖initApplicationContext方法。在那里,您可以检查scopedTarget.前缀以过滤掉不需要的bean:

public class ProxiedBeanAwareEndpointMapping extends PayloadRootAnnotationMethodEndpointMapping {

    @Override
    protected void initApplicationContext() throws BeansException {
        initInterceptors();
        String[] beanNames = getApplicationContext().getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if (!beanName.startsWith("scopedTarget.")) {
                Class<?> endpointClass = getApplicationContext().getType(beanName);
                if (endpointClass != null && AnnotationUtils.findAnnotation(endpointClass, getEndpointAnnotationType()) != null) {
                    registerMethods(beanName);
                }
            }
        }
    }

}

或者您可以使用open session in view方法,因此您无需代理@Endpoint