Как иметь интерфейс реализации класса веб-службы Джерси и быть транзакционным

Я хотел бы использовать Джерси и Spring для написания класса java, который является одновременно классом на стороне сервера веб-службы, а также транзакционным с помощью spring-tx (так что каждый запрос веб-службы либо полностью завершает свою работу в БД, либо полностью откатывает его работа в БД).

Но когда я так делаю...

package com.test.rest

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component 
@Transactional
public class TestRestService implements TestRestServiceInterface {
    ...
}

класс TestRestService не зарегистрирован Spring как класс веб-службы.

Я использую <context:component-scan base-package="com.test.rest"/> в своем файле конфигурации spring для регистрации классов веб-сервисов в пакете com.test.rest (имя пакета для примера изменено).

Если я либо удаляю @Transactional, либо TestRestService не реализует интерфейс, класс регистрируется Spring как класс веб-службы, и код работает.

Есть ли способ получить и то, и другое?

В настоящее время я использую sprint-tx, spring-jersey и spring-context 3.0.7 и jersey 1.0.3.1.


person Paul D. Eden    schedule 21.11.2012    source источник
comment
Что, если вы удалите этот интерфейс и будете использовать прокси-серверы CGLIB? Добавьте CGLIB и включите прокси на основе классов в Spring.   -  person Tomasz Nurkiewicz    schedule 22.11.2012
comment
Спасибо Tomasz, но мы хотели бы сохранить интерфейс, если это возможно, и без него даже стандартные динамические прокси JDK работают нормально. В идеале мы хотели бы, чтобы интерфейс и класс были транзакционными.   -  person Paul D. Eden    schedule 22.11.2012
comment
Исправление, я узнал из документации и собственной статьи Томаша о подводных камнях spring aop, что прокси-серверы JDK не работают без интерфейсов. Интересно, могу ли я использовать прокси CGLIB с интерфейсом. Я собираюсь попробовать это.   -  person Paul D. Eden    schedule 22.11.2012
comment
Я изменил <context:component-scan base-package="com.test.test"/> на <context:component-scan base-package="com.test.rest" scoped-proxy="targetClass"/>, и проблема осталась. Я думаю, это просто не должно быть.   -  person Paul D. Eden    schedule 22.11.2012


Ответы (1)


Посмотрев на это много, я пришел к выводу, что это просто не будет работать (возможно, без AspectJ).

Я считаю, что это не сработает из-за этого кода в jersey-server-1.0.3.1:com.sun.jersey.api.core.ResourceConfig.java

438  /**
439   * Determine if a class is a root resource class.
440   *
441   * @param c the class.
442   * @return true if the class is a root resource class, otherwise false
443   *         (including if the class is null).
444   */
445  public static boolean isRootResourceClass(Class<?> c) {
446      if (c == null)
447          return false;
448      
449      if (c.isAnnotationPresent(Path.class)) return true;
450  
451      for (Class i : c.getInterfaces())
452          if (i.isAnnotationPresent(Path.class)) return true;
453  
454      return false;
455  }

По какой-то причине, когда у нас есть @Transactional в классе, который реализует интерфейс, класс Proxy, сгенерированный spring-tx (будь то на основе CGLIB или JDK Dynamic proxy), не имеет аннотации @Path, поэтому isRootResourceClass возвращает false, а класс не зарегистрирован как класс веб-сервиса. Я проверил это во время отладки кода.

Думаю, мне просто придется выбирать между реализацией интерфейса или созданием транзакционного класса моего веб-сервиса (если только я не перейду к AspectJ).

person Paul D. Eden    schedule 21.11.2012
comment
Удалось решить эту проблему? У меня аналогичная проблема, когда мой класс обслуживания отдыха на основе трикотажа имеет аннотацию @ Transactional для некоторых методов (PUT). Но это дает мне исключение нулевого указателя (для @ autowired DAO), когда я вызываю метод службы из клиента службы отдыха. Если я удалю @ Transactional из метода, он не выдаст нулевой указатель, но и не зафиксирует транзакцию. Я также пробовал это с АОП из XML с тем же результатом. Похоже, что он не может работать с транзакционными методами. Мое приложение основано на Spring 3.1, JPA и Jersey 1.17. - person Kamran; 30.01.2013
comment
Хорошо, я решил это. Это работает, когда вы отделяете свой транзакционный сервис от трикотажного ресурса. Это означает, что вместо использования трикотажных аннотаций в классе обслуживания транзакций вы создаете новый класс, который предоставляется как трикотажный ресурс. Затем этот новый ресурс трикотажа может использовать класс транзакционного обслуживания (внедрение через пружину) для сохранения объектов. - person Kamran; 30.01.2013