2015-12-11 20 views
2

У нас есть устаревшее приложение Spring-ws для конфигурации на основе XML, которое содержит endpointInterceptors, для которых DAO вводятся для получения конфигурации из базы данных. Эти DAO имеют вложенную сессию спящего режима.Перехватчики Spring WS с введенным DAO @Transactional не работают

Когда мы обновили до весны 4.2.0.RELEASE (с весны 3.2.5.RELEASE) и пружины с 2.2.1.RELEASE (от spring-ws 2.1.4.RELEASE) Я заметил, что DAO был не прокси-объект, и казалось, что intercetor собирался в класс AnnotationActionEndpointMapping вместо класса PayloadRootAnnotationMethodEndpointMapping.

Поэтому я создал пример с весенней загрузкой 1.3.0.RELEASE, в котором излагается наше устаревшее приложение, и проблема очевидна как в конфигурации базы данных XML, так и в форме аннотации. Обратите внимание, что в примере существует аннотация @EnableTransactionManagement и существует в устаревшем приложении.

Если вы отметили контекст приложения или @EnableWS из объекта @Congiuration, тогда DAO был прокси-объектом, перехватчик, казалось, шел к правильному пути (например, PayloadRootAnnotationMethodEndpointMapping), а модульный тест работал без ошибка транзакции.

StackTrace when или EnableWS не закомментирован.

org.springframework.ws.soap.client.SoapFaultClientException: Could not obtain transaction-synchronized Session for current thread 
    at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:38) 
    at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:830) 
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:624) 
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555) 
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390) 
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378) 
    at hello.ApplicationTests.testSendAndReceive(ApplicationTests.java:61) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

Извлечение конфигурации XML, который вызывает выше исключение:

<sws:annotation-driven> 
    <sws:interceptors> 
      <ref bean="loggingInterceptorAU"/> 
    </sws:interceptors> 


<bean id="loggingInterceptorAU" class="hello.interceptor.LoggingEndpointInterceptor"/> 

Извлечение конфигурации аннотаций, который вызывает выше исключение:

@EnableWs 
@Configuration 
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 = "countries") 
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) { 
     DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); 
     wsdl11Definition.setPortTypeName("CountriesPort"); 
     wsdl11Definition.setLocationUri("/ws"); 
     wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service"); 
     wsdl11Definition.setSchema(countriesSchema); 
     return wsdl11Definition; 
    } 

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

    /** 
    * Declaring the loggingInterceptor. 
    * @return the new logging interceptor. 
    */ 
    @Bean 
    public LoggingEndpointInterceptor loggingInterceptor() { 
     LoggingEndpointInterceptor loggingEndpointInterceptor = new LoggingEndpointInterceptor(); 
     return loggingEndpointInterceptor; 
    } 

    /** 
    * Adds interceptors. 
    * @param interceptors 
    */ 
    @Override 
    public void addInterceptors(List<EndpointInterceptor> interceptors) { 
      // if these rows are uncommented 
      // and payloadRootAnnotationMethodEndpointMapping method is commented you get 
      // Error: SoapFaultClientException: Could not obtain transaction-synchronized Session for current thread 
      interceptors.add(loggingInterceptor()); 
      super.addInterceptors(interceptors); 
    } 


    /** 
    * Spring Boot with Plain Hibernate 
    * @see {https://github.com/mdeinum/samples/tree/master/spring-boot-plain-hibernate} 
    * 
    * Need to also set within application.properties. 
    * spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext 
    * @return 
    */ 
    @Bean(name="sessionFactory") 
    public HibernateJpaSessionFactoryBean sessionFactory() { 
     return new HibernateJpaSessionFactoryBean(); 
    } 
} 

После более внимательном макияжа of AnnotationActionEndpointMapping я заметил, что он реализует BeanPostProcessor. Весенний doco http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html предполагает, что «... Поскольку автопроксирование AOP реализовано как сам BeanPostProcessor, ни BeanPostProcessors, ни bean-компоненты, которые они ссылаются напрямую, не имеют права на автоматическое проксирование и, следовательно, не имеют аспектов, вплетенных в них». и поэтому я понимаю, что @Transactional не будет работать.

public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpointMapping implements BeanPostProcessor 

Мои вопросы: * что изменилось, что вызвало весной-WS-перехватчики, которые будут отображаться по умолчанию в классе AnnotationActionEndpointMapping? * В соответствии с весенней документацией рекомендуется использовать как и/или @EnableWs, так и метод addInterceptors. Есть ли какое-либо влияние, если закомментировано в нашем устаревшем приложении?

Пожалуйста, обратите внимание, у нас есть перехватчики, которые вызываются только для определенных запросов с использованием следующих, и мы не хотим, чтобы specicially создать PayloadRootAnnotationMethodEndpointMapping боб со списком перехватчиков, чтобы преодолеть эту проблему:

<sws:interceptors> 
<sws:payloadRoot localPart="TestRequest" namespaceUri="http://www.test.com/test/request/1.0"> 
... 
+1

Это все еще проблема. Кто-нибудь сталкивался с той же проблемой? Я считаю, что следующее изменение [Spring] (https://jira.spring.io/browse/SWS-874) могло вызвать эту проблему. В нашем унаследованном приложении мы все еще комментируем xml config __sws: annotation-driven__ и хотели бы, чтобы кто-то из весны проверил вышеупомянутую проблему. –

+0

Я подал билет на весну jira [SWS-974] (https://jira.spring.io/browse/SWS-974), чтобы надеяться решить эту проблему. –

+0

можно рассматривать как некроповую, но точно так же, как и предложение, пожалуйста, проверьте проверку компонентов. убедитесь, что класс, аннотированный аннотацией конечных точек, является частью, проверенной ТОЛЬКО сервлером webservice, указанным в web.xml, а также не // только с помощью проверки компонента, которую вы выполняете, например, вашего корневого приложенияContext.xml .. Я предлагаю это, потому что, например, если контроллеры сканируются как applicationContext, так и сервлетом, транзакционная аннотация не будет работать, поэтому у вас может быть одна и та же проблема, только контекстуализированная с конечными точками вместо контроллеров :) – witchedwiz

ответ

0

что вы можете do перемещает/копирует ваши транзакционные методы (методы, которые будут использоваться перехватчиками) в новый класс и создает программный компонент программным путем с помощью TransactionProxyFactoryBean.

что-то вроде этого:

@Bean 
@Autowired 
public TransactionProxyFactoryBean transactionalBeanForInterceptor(PlatformTransactionManager 
     transactionManager, SessionFactory sessionFactory) { 
    TransactionProxyFactoryBean factoryBean = new TransactionProxyFactoryBean(); 
    factoryBean.setTransactionManager(transactionManager); 
    factoryBean.setTarget(new InterceptorService(sessionFactory)); // its just an example 
    Properties transactionAttributes = new Properties(); 
    transactionAttributes.put("validate*", "PROPAGATION_REQUIRED"); // validate* is a regex with the name of the methods which are transactionals 
    factoryBean.setTransactionAttributes(transactionAttributes); 
    return factoryBean; 
} 

@Bean 
@Autowired 
public EndpointInterceptor myInterceptor(InterceptorService interceptorService) { // this will inject a proxied instance (transactional) of InterceptorService 
    return new MyEndpointInterceptor(interceptorService); 
} 
+0

Спасибо @Enrique за ваше решение. Похоже, мы продолжим с комментариями sws: annotation-driven/EnableWS в надежде, что Spring предоставит исправление. –

0

Если кто-то еще есть вопросы, пожалуйста, читайте дальше. После того, как наши проекты были обновлены до весны 4.3.10.RELEASE (с весны 4.2.0.RELEASE) и весны-вес 2.4.0.RELEASE (от весны-2.2.2.RELEASE), указанные выше ошибки больше не были проблема даже если следующий код был вновь введен в нашей базе кода:

конфигурация XML:

<sws:annotation-driven> 

Аннотация:

@EnableWS from the @Congiuration object 

После того, как это было сделано endpointinterceptors, требовавший @Transactional работал они были предназначены. Также весенний билет SWS-974 еще не назначен. Я попытаюсь сообщить Spring, что они могут закрыть его.