본문 바로가기

스프링

[spring] aop 트랜잭션_JDK다이내믹 프록시_3

1.     Com.springsource.javax.activation : Spring java-mail

2.     Com.springsource.javax.mail : Spring java-mail

3.     Com.springsource.junit : junit

4.     Commons-logging : Spring-context가 사용

5.     Mail : java-mail

6.     Mockito : 목 프레임워크 중 Mockito

7.     Mysql-connector : Mysql JDBC

8.     Org.springframework.context.support : Spring java-mail

9.     Spring-aop : 스프링 기능 자체의 aop

10.   Spring-bean : 스프링 빈을 활용하는 경우 필요. 스프링의 XML 설정파일과 자바 애노테이션을 파싱 하는데 필요한 클래스 포함

11.   Spring-context : 스프링 코어를 확장한 많은 클래스가 들어 있는데 모든 클래스는 EJB, JNDI(Java Naming Directory Interface), JMX용 클래스와 연동하는데 applicationcontext기능을 사용해야 하며 스프링 리모팅 클래스, 동적 스크립팅 언어(제이루비, 그루비등)와 연동하는 클래스, 빈 유효성검증(JSR-303) API, 스케줄링을 하는 클래스도 포함되어 있다.

12.   Spring-core : 모든 스프링 모듈에서 필요한 모듈. 다른 스프링 모듈에서 사용하는 공통 클래스가 포함됨.

13.   Spring-dao : EmpltyResultDataAccessException 등 사용을 위한 jar

14.   Spring-expression : 스프링 표현언어(SpEL) 지원 클래스 포함.

15.   Spring-jdbc : 스프링이 지원하는 jdbc.

16.   Spring-test.jar

-       @RunWith : Junit 프레임워크의 테스트 실행방법을 확장시 사용.

-       SpringJUnit4ClassRunner : 어플리케이션컨텍스트를 만들고 관리하는 확장 클래스

-       @ContextConfiguration(경로) : 자동으로 만들어줄 어플리케이션 컨텍스트 설정파일

17.   Spring-tx : DuplicateKeyException.class 파일 존재 및 스프링 트랜잭션

 

 

다음레벨이 무엇인지에 관한 로직은 레벨에게 위임

 

User에 다음레벨 셋팅은 User에게 위임

 

 

JDBC, JDO, JPA, Hibernate 등 여러가지 커넥션 설정이 있으므로 인터페이스

 

 

JDBC용 구현

 

 

트랜잭션 타깃, 프록시 구현을 위한 인터페이스

 

 

49. add 메서드에 트랜잭션 필요시, add 메서드는 타겟이 되고, 프록시를 구현할 것이다.

36. upgradeLevel시 커넥션 에러 테스트를 위해 impl을 상속받는 테스트 서비스를 구현해서 테스트를 위함

 

프록시 : 클라이언트가 타겟인줄 알고 쓰지만 사실 프록시. 트랜잭션이 여기저기 들어가야하면 중복. 또한, 트랜잭션이 필요없는 메서드들도 구현해줘야 하므로 중복.

* 데코레이터 패턴

 

 

메일서버 테스트시 실제로 메일을 보내면 부하가 심하므로 테스트스텁 생성

 

 

* 프록시의 중복되는 문제를 해결하기 위한 handler. 다이내믹 프록시 기능설정(invoke)

* 트랜잭션 부가기능을 담은 TransactionHandler

12. Object로 선언함에 따라 UserServiceImpl 외에 트랜잭션 적용이 필요한 타깃 오브젝트를 적용할 수 있다.

26. 트랜잭션 적용 대상 메소드를 선별해서 트랜잭션 경계설정 기능을 부여(startWith를 붙임으로써 get 으로 입력시 get으로 시작하는 모든 메소드에 트랜잭션이 적용된다.

29. 패턴과 일치하지 않는 메소드라면 타깃을 그냥 호출

35~. 트랜잭션을 시작하고 타깃 오브젝트의 메소드를 호출

40. Method.invoke()를 이용해 타깃 오브젝트의 메소드를 호출될 때 해당 Exception으로 포장돼서 전달되기 때문에 일단 InvocationTargetException으로 받은 후 getTargetException 메소드로 중첩되어 있는 예외를 가져와야 한다.

 

 

 

 

51~. MockDao를 내부클래스로 생성하여 DB문제와 관계없이 테스트를 진행가능토록 적용

 

 

mockDao 생성

 

 

122~124. 트랜잭션 핸들러가 필요한 정보와 오브젝트를 DI

126. UserService 인터페이스 타입의 다이내믹 프록시 생성

127. getClassLoader : 동적으로 생성되는 다이내믹 프록시 클래스의 로딩에 사용할 클래스 로더

127. new Class[] : 구현할 인터페이스(프록시)

127. txHandler : 부가기능과 위임 코드를 담은 invocationHandler

* 문제점

> 이제 TransactionHandler와 다이내믹 프록시를 스프링 DI를 통해 사용할 수 있게 만들어야하지만, 다이내믹 프록시 오브젝트는 빈으로 등록할 방법이 없다.(126~127 라인)

> 다이내믹 프록시는 Proxy 클래스의 newProxyInstance() 라는 스태틱 팩토리 메소드를 통해서만 만들 수 있다.

 

 

 

스프링은 지정된 클래스 이름을 가지고 리플렉션을 이용해서 해당 클래스의 오브젝트를 만든다. 위는 파라미터가 없는 생성자를 호출하여 오브젝트를 돌려주는 리플렉션 API이다.

스프링은 위처럼 리플렉션 API를 이용해서 빈 정의에 나오는 클래스 이름을 가지고 빈 오브젝트를 생성한다.

* 따라서, 스프링은 클래스 정보를 알 수 없는 다이내믹 프록시를 빈에 정의할 방법이 없다. JDK 다이내믹 프록시의 한계

 

 

단점

InvocationHandler가 타깃과 메소드 선정 알고리즘에 의존적임

-       만약 타깃과 메소드 선정 알고리즘이 다르다면, InvocationHandler를 여러 프록시가 공유할 수 없다.

>  타깃과 메소드 선정 알고리즘은 DI를 통해 분리할 수는 있지만, 한번 빈으로 구성된 InvocationHandler 오브젝트는, 오브젝트 차원에서 특정 타깃을 위한 프록시에 제한된다.