복붙노트

[SPRING] Spring / EJB / Mockito ... 프록시에서 내부 호출을 처리하는 방법?

SPRING

Spring / EJB / Mockito ... 프록시에서 내부 호출을 처리하는 방법?

여러분이 많은 것을 알고 있듯이, Spring / EJB를위한 트랜잭션 속성을 가진 bean을 생성하거나 심지어 일부 프레임 워크를 사용하여 부분 모의 객체를 생성 할 때처럼 프록시 객체는이를 알지 못하고 내부 호출이 리디렉션되지 않습니다 , 그리고 도망 간다 ...

스프링에서 그런 일을하는 이유는 다음과 같습니다.

@Transactionnal
public void doSomething() {
    doSomethingInNewTransaction();
    doSomethingInNewTransaction();
    doSomethingInNewTransaction();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomethingInNewTransaction() {
    ...
}

doSomething을 호출하면 주 트랜잭션 이외에 3 개의 트랜잭션이 추가 될 것으로 예상되지만 실제로이 문제로 인해 하나만 가져옵니다.

이런 종류의 문제를 어떻게 처리 할 수 ​​있을지 궁금합니다.

사실 복잡한 트랜잭션 시스템을 처리해야하는 상황에 처해 있습니다. 내 서비스를 여러 개의 작은 서비스로 분할하는 것보다 더 좋은 방법은 없기 때문에 모든 프록시를 통과해야합니다.

모든 코드가 동일한 기능적 도메인에 속하고 분리되어서는 안되기 때문에 저에게 많은 불편을 겪습니다 ...

흥미로운 답변으로이 관련 질문을 찾았습니다. Spring - @Transactional - 백그라운드에서 어떻게됩니까?

Rob H는 스프링 프록시를 서비스 내에 삽입 할 수 있으며 proxy.doSomethingInNewTransaction ()을 호출 할 수 있다고 말합니다. 대신에. 그것은하기 쉽고 작동하지만, 나는 그것을 정말로 좋아하지 않습니다 ...

유엔 펭 H 조이 말 :

봄이 지금하고있는 것은 무엇을 의미합니까? 내부 트랜잭션 호출이 가로 챌 수 있습니까?

뭐가 더 낫다고 생각하니?

트랜잭션 세분화가 필요할 때 클래스를 분할합니까? 아니면 위와 같은 해결 방법을 사용합니까? (그것을 공유하십시오)

해결법

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

    1.나는 Spring과 @Transactional에 대해 이야기 할 것이지만 그 조언은 다른 많은 프레임 워크에도 적용된다.

    나는 Spring과 @Transactional에 대해 이야기 할 것이지만 그 조언은 다른 많은 프레임 워크에도 적용된다.

    이것은 프록시 기반 측면에 내재 된 문제입니다. 여기 스프링 문서에서 논의됩니다 :

    http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies

    여러 가지 가능한 솔루션이 있습니다.

    클래스를 리 팩터링하여 프록시를 우회하는 자체 호출 호출을 피하십시오.

    Spring 문서는 이것을 "가장 좋은 접근법 (여기서 가장 좋은 용어는 느슨하게 사용된다)"이라고 설명한다.

    이 접근법의 장점은 단순성과 어떤 프레임 워크와도 관련이 없다는 점입니다. 그러나, 아주 작은 규모의 많은 클래스로 끝나기 때문에 트랜잭션이 많은 무거운 코드베이스에는 적절하지 않을 수 있습니다.

    내부적으로 클래스에서 프록시에 대한 참조를 얻습니다.

    이것은 프록시를 삽입하거나 하드 코딩 된 "AopContext.currentProxy ()"호출로 수행 할 수 있습니다 (위의 Spring 문서 참조).

    이 방법을 사용하면 클래스를 분할하지 않아도되지만 여러 가지면에서 트랜잭션 주석을 사용하면 얻을 수있는 이점을 무효화 할 수 있습니다. 개인적 견해는 이것이 약간 못 생기는 것들 중 하나이지만 추한 것은 자체적으로 포함되어 있으며 많은 거래가 사용된다면 실용적인 접근 방식이 될 수 있다는 것입니다.

    AspectJ 사용으로 전환

    AspectJ는 프록시를 사용하지 않으므로 자체 호출은 문제가되지 않는다.

    이것은 매우 깨끗한 방법이지만, 다른 프레임 워크를 도입하는 비용입니다. 저는 AspectJ가 소개 된 커다란 프로젝트에서 일해 왔습니다.

    @Transactional을 전혀 사용하지 마십시오.

    아마도 데코레이터 패턴을 사용하여 수동 트랜잭션 구분을 사용하도록 코드를 리 팩터링하십시오.

    옵션 - 중간 리팩토링이 필요하고 추가 프레임 워크와 복잡성이 증가하므로 선호되는 옵션이 아닐 수 있습니다.

    나의 충고

    일반적으로 코드를 분할하는 것이 가장 좋은 대답이며 문제의 분리를위한 좋은 방법이기도합니다. 그러나 중첩 된 트랜잭션에 크게 의존하는 프레임 워크 / 응용 프로그램이있는 경우 AspectJ를 사용하여 자체 호출을 허용하는 것이 좋습니다.

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

    2.복잡한 유스 케이스를 모델링하고 설계 할 때 언제나 그렇듯이 이해할 수 있고 유지 보수가 가능한 디자인과 코드에 중점을 둡니다. 특정 패턴이나 디자인을 선호하지만 기본 프레임 워크와 충돌하는 경우 프레임 워크에 디자인을 구속하는 복잡한 해결 방법이 필요한지 또는 필요에 따라 디자인을 타협하여 프레임 워크에 적용해야하는지 고려해야합니다. 절대적으로해야하지 않는 한 프레임 워크와 싸우지 마십시오.

    복잡한 유스 케이스를 모델링하고 설계 할 때 언제나 그렇듯이 이해할 수 있고 유지 보수가 가능한 디자인과 코드에 중점을 둡니다. 특정 패턴이나 디자인을 선호하지만 기본 프레임 워크와 충돌하는 경우 프레임 워크에 디자인을 구속하는 복잡한 해결 방법이 필요한지 또는 필요에 따라 디자인을 타협하여 프레임 워크에 적용해야하는지 고려해야합니다. 절대적으로해야하지 않는 한 프레임 워크와 싸우지 마십시오.

    내 충고 - 몇 가지 추가 서비스 클래스로 분리하는 것과 같은 쉬운 타협을 통해 목표를 달성 할 수 있다면 그렇게하십시오. 대안보다는 시간, 시험 및 고뇌면에서 훨씬 저렴합니다. 그리고 유지하는 것이 훨씬 쉽고 다음 사람을 대신 할 두통이 덜한 것 같습니다.

  3. ==============================

    3.보통 간단하게 만들었으므로 코드를 두 개의 객체로 분리했습니다.

    보통 간단하게 만들었으므로 코드를 두 개의 객체로 분리했습니다.

    다른 방법은 TransactionTemplate을 사용하여 동일한 파일에 모든 것을 유지해야하는 경우 새 트랜잭션을 직접 구분하는 것입니다. 몇 줄의 코드가 있지만 새로운 빈을 정의하는 것 이상은 아닙니다. 그리고 때로는 그 점을 더욱 분명하게 만듭니다.

  4. from https://stackoverflow.com/questions/8039041/how-to-handle-internal-calls-on-spring-ejb-mockito-proxies by cc-by-sa and MIT license