토비의 스프링 Ver6

존스노우·2021년 11월 22일
0

스프링

목록 보기
6/22

AOP

IoC/DI/AOP

스프링에 가장 인기있는 AOP 적용대상은 선언적 태른 잭션 기능

트랜잭션 경계설저 기능을 AOP를 이용해 바꿔보자

트랜잭션 코드의 분리

메소드 분리

트랜 잭션 경계설정의 코드와 비즈니스 로직 코드간 구분되어 있음
주고 받는 정보도 없음

분리

DI를 이용한 클래스의 분리

트랜잭션 코드를 클래스 밖으로 뽑아내자

DI 적용을 이용한 트랜잭션 분리

간접적으로 사용 해보자 .

테스트와 실제 사용하는 클래스를 선택해서 적용하고싶어서

DI 적용해서 구현클래스를 만들어준다.

근대 꼭 한가지 클래스만 선택해서 사용할 필요가없다.

UserService 인터페이스 도입

먼저 기존의 UserService -> UserServiceImpl로 변경
UserService 인터페이스 생성

impl 트랜잭션 코드를 다삭제해주고..

변경후 -> 로직만 구현한 형태가 됨,

서버환경? 스프링 관련코드? 단순히 UserDao라는 인터페이스를 이용하고
User라는 도메인 정보를 가진 비즈니스 로직에만 충실한 깔끔한 코드

분리된 트랜잭션 기능

UserServiceTx 만들자.

Tx 는 단순히 UserService 구현 오브젝트 기능을 위임

경계설정 작업 부여해야됨.

이렇게함으로써 기존에 비즈니스로직 분리 트랜잭션 경계설정 분리 코드

모습이 나타났다

DI를 두개 적용 받아서 코드처리를했다. 음.. 이런모습이 맞는걸까

스프링 기능을 잘 사용하고 있다고하는데..

밑에서 계속 보자.

트랜잭션 적용을 위한 DI 설정

트랜잭션 담당 오브젝트가 트랜잭션 작업을 해주고
실제 사용자 관리 로직 호출 !

트랜잭션 분리에 따른 테스트 수정

DI를 적용해 클래스 들이 분리 됬으니 이렇게 적용해주자

이런식으로 테스트 를 변경해줌 .

트랜잭션 경계설정 코드 분리의 장점

  1. 비즈니스 로직을 담당하고 있는 UserServiceImpl의 코드를 작성 할 때는 트랜잭션과 같은 기술적인 내용은 신경 쓰지 않아도 됨.
  1. 테스트를 손쉽게 만들어 낼 수 있음

고립된 단위 테스트

가장 좋은 테스트 방법은 가능한 작은 단위로 쪼개서 테스트 하는 것.

테스트 단위가 작아야 원인을 찾고 내용도 분명해짐

하지만 작은 단위로 테스트를 하고 싶다해도 없는 경우가 많다.

테스트 대상이 다른 오브젝트와 환경에 의존하고 있다면

작은 단위 테스트가 주는 장점을 얻기 힘들다..

복잡한 의존관계속의 테스트

UserSErvice. 는 UserDao, TransactionManager,MailSender 라는 세 가지의 의존관계를 가지고 있음..

위 3가지는 또 밑으로 다른 구현 클래스들이 줄줄이 엮여있어서 다 같이

실행 된다..

테스트 대상 오브젝트 고립시키기

MailSender에서 적용해봤떤 ㅌ대로 테스트를 위한 대역을 만들어야됨..

Ex)DummymailSender 라는 테스트 스텁

MockMailSender 목오브젝트

테스트를 위한 UserServiceImp 고립

UserDao 는 단지 테스트 대상 코드가 정상적으로 수행되도록 도와주는 스텁이 아니라 검증 기능까지 가진 목 오브젝트

고립된 환경에서 upgradeLevels() 테스트 결과를 검증할 방법이 필요하기 때문

고립된 단위 테스트 활용

UserDao의 목 오브젝트

DB에 의존하고 있는 테스트 목오브젝트를 적용시켜보자

update()에 대해서는 목 오브젝트로서 동작하는 UserDao 타입의 테스트 대역이 필요함.

MockUserDao

두 개의 User 타입 리스트 정의

하나는 생성자를 통해 전달받는 사용자 목록,
다른 하나는 update() 메소드를 실행하면서 넘겨주는 업그레이드 대상

테스트 수행 성능의 향상

UserServiceTest의 upgradeLevels() 실행

성능이 훨씬 빨라짐

단위 테스트와 통합 테스트

외부 리소스를 사용하지않고 테스트 하는걸 단위테스트로 지정 고립된상태..

반대는 통합테스트..

  1. 항상 단위 테스트 먼저 고려한다.

  2. 하나의 클래스나 성격과 목적이 같은 클래스를 모아 목오브젝트 등을 이용해 테스트 만든다.

  3. 외부 리스소를 사용해야만 가능하면 통합테스트로.

  4. 단위테스트로 만들기 어려운경우 ? EX) DAO DB까지 연동되는 테스트로
    만드는 편이 좋다.

  5. DAO 테스트는 DB 외부 리소스를 사용하기 때문에 통합 테스트로 분류됨. 하지만
    코드 기준으론 ㅌ단위 테스트.

  6. 단위테스트를 충분히 거치면 통합테스트 위험은 많이 줄어듬..

  7. 단위 테스트가 만들기 너무 복잡? 처음 부터 통합테스트로 고려해본다.
    가능한 많이 단위테스트 만들고..

  8. 스프링 테스트 컨텍스트 프레임워크를 이용하는 테스트는 통합 테스트.

목 프레임워크

테스트 마다 목 프레임워크를 제작해주면 번거롭다..

그래서...?

Mockito 프레임워크

간단한 메소드 호출만으로 다이내믹하게 특정 인터페이스를 구현한 테스트용 목 오브젝트를 만듬.

아직 아무런 기능이 없는 목 오브젝트.
사용자 목록을 불러오도록 스텁 기능을 추가해보자

Mockito 목 오브젝트는 다음의 네 단계를 거쳐서 사용됨. 두 번째와 네 번째는 필요한 경우만.

  1. 인터페이스를 이용해 목 오브젝트 만듬.
  2. 목 오브젝트가 리턴할 값을 있으면 지정해줌. 메소드가 호출되면 강제로 예외 가능
  3. 테스트 대상 오브젝트에 DI 해서 목 오브젝트가 테스트 중에 사용 되도록 만듬.
  4. 테스트 대상 오브젝트를 사용한 후에 목 오브젝트의 특정 메소드가 호출 됐는지 , 어떤 값을 가지고 몇 번 호출됐는지 검증.

다이내믹 프록시와 팩토리 빈

프록시와 프록시 패턴 데코레이터 패턴

트랜잭션 경계코드 설정 을 다시설명.. 부가기능이 핵심기능을 사용하는 것처럼..

부가기능을 통해 핵심기능을 이용하게된다..

이렇게 마치 자신이 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서
클라이언트의 요청을 받아주는 것을 대리자 대리인 역활이라해서 프록시라 부름

프록시를 통해 최종적으로 위임 받아 처리하는 오브젝트를 타깃/실체 라고 함

프록시 사용이유.

  1. 클라이언트가 타깃에 접근하는 방법 제어
  2. 타깃에 부가적인 기능을 부여해주기 위해

데코레이터 패턴

데코레이션 패턴이란? 부가적인 기능을 런타임시 다이내믹하게 보여해주기 위해 프록시를
사용하는 패턴.

동적으로 기능을 부가한다?

컴파일 시점 , 즉 코드상에서 어떤 방법과 순서로 프록시와 타깃이 연결되어 사용되는지
정해지지 않다는 뜻.

데코레이터라고 불리는 이유? 케잌의 장식 붙이는 것처럼 실제 내용은 동일하지만
부가적인 효과를 누릴수 있기 때문에

프록시를 여러개 사용함.

UserServiceTx 데코레이터 패턴 적용

프록시 패턴

여기서 말하는 프록시는 사용하는 방법 중에서 타깃에 대한 접근 방법을 제어하는 목적

프록시 패턴의 프록시는 타깃의 기능을 확장하거나 추가하지 않음.
대신 타깃에 접근 방식 변경.

타깃 오브젝트에 레퍼런스가 미리 필요할 경우 프록시 패턴을 적용하면 됨..

Collection 의 unmodifiableColletion() 전형적인 접근권한 제어 프록시

다이내믹 프록시

프록시는 기존 코드에 영향을 주지 않으면서 타깃의 기능을 확장하거나 접근 방법 제어함.

하지만 프록시 만드는일은 매우 번거로움

프록시의 구성과 프록시 작성의 문제점

프록시의 기능

  1. 타깃과 같은 메소드를 구현하고 있다가 메소드가 호출 되면 타깃 오브젝트 위임
  2. 지정된 요청에 대해 부가기능 수행.

프록시를 만드는 번거로운 이유?

  1. 타깃의 인터페이스를 구현하고 위임하는 코드 작성이 번거롭다.
    부가기능이 필요 없는 메소드도 구현해서 타깃으로 위임하는 코드 일일이 만들어줘야됨.
  2. 부가기능 코드가 중복될 가능성이 많다.

리플렉션

다이내믹 프록시는 리플렉션 기능을 이용해서 프록시를 만들어 줌.

리플렉션은 자바의 코드 자체를 추상화해서 접근하도록 만듬

리플렉션 API 중 Method라는 인터페이스를 이용해 메소드 호출 방법을 살펴보자

스트링이 가진 메소드 중에서 Length라는 이름을 갖고 있고 파라미터는 없는 메소드 정보를 가져온다.

프록시 클래스

다이내믹 프록시를 이용한 프록시 만들기.

다이내믹 프록시 적용

다이내믹 프록시는 프록시 팩토리에 의해 런타임 시 다이내믹하게 만들어지는 오브젝트.

다이내믹 프록시는 인터페이스 구현 클래스의 오브젝트를 만들어 주지만. 프록시로서 필요한 부가기능 제공 코드는

직접 작성해야 함..

다이내믹 프록시의 확장

리턴 타입이 스트링이아닌경우 ?

InovacationHandler 방식의 또한가지 장점은 타깃의 종류와 상관없이도 적용이 가능함.
어떤 종류의 인터페이스를 구현한 타깃이든 항관없이 재사용할 수 있고 메소드 리턴 타입이 스트링 경우만
대문자로 결과로 바꿔주도록 Uppercasehandler 만들수 있다.


다이내믹 프록시를 이용한 트랜잭션 부가기능

트랜잭션 부가기능을 제공하는 다이내믹 프록시를 만들어 적용하는 방법이 효율적..

TransactionHandler와 다이내믹 프록시를 이용하는 테스트

다이내믹 프록시를 위한 팩토리 빈

일반적인 스프링 빈으로 다이내믹 프록시 오브젝트는 등록할 방법이 없음

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

팩토리 빈

팩토리 빈을 이용한 빈생성 방법.

스프링을 대신해 오브젝트의 생성로직 담당

팩토리빈 설정 방법

다이내믹 프록시를 만들어 주는 팩토리빈..

프록시부분 점프 .. 음 다시한번 되새김질 할때 봐야겠따 전체적으로 내용을 이해하기어렵고.
너무 시간을 잡아먹는다. 중요한 부분이라면 다시볼 기회가 있을때 더공부하자

스프링 AOP

반복적으로 등장하던 태랜잭션 코드를 깔끔하고 효과적으로 분리.

투명한 부가기능도 제공돼야 한다.

투명하다? 기존 설계 코드에 영향 X

profile
어제의 나보다 한걸음 더

0개의 댓글