복붙노트

[SPRING] Spring + Jersey 트랜잭션 주석

SPRING

Spring + Jersey 트랜잭션 주석

JPA 지원 데이터베이스에 RESTful API를 제공하는 상용구 프로젝트를 작성했습니다. 그것은 다음 버전을 사용하고 있습니다 : - 봄 3.2.6 - 최대 절전 모드 4.3.0 - 저지 2.5.1 나는 마침내 그들과 함께 놀 수 있었지만, 여전히 몇 가지 질문이 남아 있습니다. 가장 수수께끼 같은 것들 중 하나가 있습니다 (REST 서비스 클래스에서 발췌 참조).

@Service
@Path("resources")
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
@Transactional
public class ResourceServices extends AbstractServices<Resource> {
...
}

class가 @Service로 어노테이션 된 경우 @Transactional 어노테이션은 무시되고 메소드에 대한 트랜잭션은 시작되지 않습니다. 그러나 @Component로 변경하면 모든 것이 잘 동작합니다. 알아낼 수 없었어요, 왜.

전체 프로젝트를 여기에서 볼 수 있습니다.

해결법

  1. ==============================

    1.나는 이것에 대해서 당혹 스럽지만 마침내 이것을 알아 냈다.

    나는 이것에 대해서 당혹 스럽지만 마침내 이것을 알아 냈다.

    저지 - 스프링 모듈은 컨텍스트에서 @Component Bean 만 가져옵니다. 글자 그대로 SpringComponentProvider의 beanClass.isAnnotationPresent (Component.class) 체크가있다.

    그렇지 않으면 빈의 요청 범위가 절반 밖에되지 않는 인스턴스가 생성됩니다 (서비스 생성자에서 Thread.dumpStack을 사용하여 추적했습니다). 그들은 의존성 주입을 가지고있는 것처럼 보이지만 AOP는 그렇지 않습니다.

    Jersey의 이슈 추적기에는 이미 JIRA 항목이 많이 있습니다. JERSEY-2495, JERSEY-2059, JERSEY-2301

    업데이트 : 이들에 대한 내 풀 요청이 병합되었습니다. Jersey 2.11에서 수정해야합니다.

  2. ==============================

    2.다른 대답에서 언급했듯이 SpringComponentProvider는 Jersey에 의해 생성 된 Bean을 가져 와서 Spring 컨텍스트에 등록하지만이 경우에는 Spring AOP를 얻지 못한다.

    다른 대답에서 언급했듯이 SpringComponentProvider는 Jersey에 의해 생성 된 Bean을 가져 와서 Spring 컨텍스트에 등록하지만이 경우에는 Spring AOP를 얻지 못한다.

    다른 방법으로 AOP와 작업하게 만들었습니다. 빈은 Spring에 의해 생성됩니다 (사실 AOP로 인해 프록시입니다). 그런 다음 Jersey에 등록됩니다.

    하지만 Jersey의 ModelHelper 클래스에서 버그를 수정해야했습니다. https://github.com/jersey/jersey/pull/90

    이 수정 프로그램이 없으면 Jersey는 Spring 프록시에서 @Path 주석을 찾을 수 없었습니다.

    이것은 기본 구조입니다.

    public class MyApplication extends ResourceConfig {
        @Inject
        public MyApplication(ServletContext servletContext) {
            super(JSONController.class, XSSSecurityFilter.class, JacksonFeature.class);
            WebApplicationContext springFactory = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            // TODO: scan entire Spring factory for beans annotated with @Path and register them, so we don't need to do this manually.
            // Letting Jersey register the beans does not work because in this case Spring will not intercept the calls.
            register(springFactory.getBean(UserServiceFacade.class));
        }
    }
    
  3. ==============================

    3.그 이유는 Spring에 주석을 달기위한 다른 컨테이너가 있고 저어지에는 주석 컨테이너와 다른 컨테이너가 있기 때문입니다. 스프링 컨테이너의 빈에 액세스하기 위해 아래 코드를 참조 할 수 있습니다.

    그 이유는 Spring에 주석을 달기위한 다른 컨테이너가 있고 저어지에는 주석 컨테이너와 다른 컨테이너가 있기 때문입니다. 스프링 컨테이너의 빈에 액세스하기 위해 아래 코드를 참조 할 수 있습니다.

    내가 사용하는 버전과 다른 것을 구걸하고, 나는 저지의 최신 버전을 사용하지 않았다 :

    다음과 같이 web.xml을 통해 일반적인 스프링 구성으로로드합니다.

    <servlet>
        <servlet-name>project-spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:project-spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>project-spring</servlet-name>
        <url-pattern>*.htm</url-pattern>
      </servlet-mapping>
    

    이제 아래와 같이 Application을 통해 저지 리소스를로드하십시오.

    @ApplicationPath("/rest")
    public class ResourceLoader extends Application
    {
        /* (non-Javadoc)
         * @see javax.ws.rs.core.Application#getClasses()
         */
        @Override
        public Set<Class<?>> getClasses()
        {
            Set<Class<?>> classes = new HashSet<Class<?>>();
            loadResourceClasses(classes);
            return classes;
        }
    
        private void loadResourceClasses(Set<Class<?>> classes)
        {
            classes.add(StudentResource.class);
        }
    }
    

    그런 다음 귀하의 리소스 :

    @Path("student")
    class StudentResource
    {
        private StudentService studentService;
    
        StudentResource(@Context ServletContext servletContext)
        {
           ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            this.studentService= applicationContext.getBean(StudentService .class);
        }
    }
    

    Spring의 WebApplicationContextUtils를 사용하여 모든 bean이 초기화 된 ApplicationContext를 가져 와서 서블릿 컨텍스트를 전달하고 bean을 가져올 수 있습니다.

  4. from https://stackoverflow.com/questions/21104567/springjersey-transactional-annotation by cc-by-sa and MIT license