DI와 AOP

스프링이 가지는 가장 대표적인 특징이라고 하면 DI와 AOP라고 할 수 있다.

DIDependency Injection

객체 간의 의존관계를 객체 자신이 아닌 외부로 부터 주입받아 객체 간의 결합도를 낮추는 것을 말한다.

  • 클래스간의 결합도를 낮춤
  • 낮은 의존성을 통해 유닛테스트 도움

DI의 종류

  1. 생성자 주입
  2. 세터(Setter) 주입

스프링의 DI

객체가 의존관계를 갖기 위해선 생성자에서 다른 객체를 생성하는, 다른 객체를 담는 큰 객체로 부터 작은 객체를 생성하는 과정을 갖는다. 하지만 DI를 통해 생성되는 객체는 작은 객체를 주입 받기 위해 작은 객체를 먼저 생성하고 큰 객체가 이를 주입 받는, 제어의 역전:IoCInverse of Control이 발생한다.

스프링의 IoC 컨테이너는 이러한 의존성을 주입하는 역할을 위해 관리되는 오브젝트들을 bean으로 등록하여 관리한다. 이렇게 관리되는 bean들은 설정파일에 기술하여 컨테이너에게 관리될 오브젝트들을 알려주게 된다.

AOPAspect-Oriented Programming

DI가 애플리케이션 모듈들 간의 결합도를 낮춰준다면, AOP는 애플리케이션 전체에 걸쳐 사용되는 부가적인 기능들을 재사용하도록 지원하는 것을 말한다. 각 클래스에서 공통으로 구현될 부가적인 기능인 횡단 관심Cross Cutting들을 Aspect 단위로 모아 의존관계의 복잡성과 코드 중복을 해소할 수 있다.

di-and-aop-0

  • 로그, 트랜잭션, 보안, 캐싱과 같은 부가적인 처리와 이런 기능들에 영향을 받는 객체간의 결합도를 낮춤
  • 흩어져서 구현되는 관심 기능을 하나의 장소로 응집
  • 코드의 재사용성이 높아져 가독성이 높아짐

주요개념

Aspect

구현하고자 하는 횡단 관심사의 기능을 의미한다. 한개 이상의 포인트컷과 어드바이스의 조합으로 만들어진다.

Join Point

Aspect를 삽입하여 Advice가 적용될 수 있는 위치를 말한다. 스프링에선 메서드 실행을 나타낸다.

Advice

Aspect의 구현체로 Join Point에 삽입되어 동작하는 코드이다. 동작하는 시점에 따라 5개로 구분된다.

  • Before : Join Point 전에 실행되는 Advice

    di-and-aop-1

  • After : Join Point에서 메서드의 실행결과에 상관없이 무조건 실행되는 Advice, 자바의 finally와 비슷한 역할을 한다.

    di-and-aop-2

  • After Returning : Join Point에서 성공적으로 리턴 된 후 실행되는 Advice

    di-and-aop-3

  • Around : Join Point의 전 과정에서 수행되는 Advice

    di-and-aop-4

  • After Throwing : 예외가 발생하였을 경우 실행되는 Advice

    di-and-aop-5

Pointcut

실행중 Join Point에 이르렀을 때 Advice를 호출할 지 선별하는 과정이나 그 기능을 정의한 모듈을 의미한다. 패턴매칭을 이용하여 어떤 조인포인트를 사용할 것인지 결정한다.

Proxy를 이용한 AOP

스프링은 AOP를 구현하기 위해 Proxy를 사용한다.

di-and-aop-6

DIxAOP 컨테이너는 Servant의 인터페이스를 구현한 Proxy 인스턴스를 자동으로 생성하여 Servant 대신 Client에 인젝션한다. 이후 Client에서 포인트 컷으로 등록된 Servant 클래스의 메서드를 호출할 때, Proxy 인스턴스의 메서드가 대신 호출되어 종류에 따라 메서드 호출 전후에 Advise를 호출한다.

인터페이스를 구현하지 않은 클래스에 AOP를 하는 경우엔, JDK Dynamic Proxy가 아닌 CGLib Proxy를 사용한다. CGLib Proxy의 경우엔 인터페이스가 아닌 클래스를 상속받은 Proxy를 생성하여 AOP를 구현한다.