Spring AOP(JDK Proxy/CGLib Proxy)

개발자·2023년 1월 5일
0

Spring

목록 보기
17/18
post-thumbnail
post-custom-banner

AOP

부가기능은 핵심기능과 섞이면 설계와 코드가 지저분해지기 때문에 부가기능을 독립적인 모듈로 만들고자 하는 필요성이 대두되었다.그리고 핵심 기능에 부여되는 부가 기능을 효과적으로 모듈화하는 방법을 찾다가, 어드바이스와 포인트컷을 결합한 어드바이스가 발전하여 AOP가 만들어지게 되었다. 이러한 부가 기능 모듈은 기존의 객체지향 설계와 구분되는 새로운 특성이 있어서 Aspect라고 불리기 시작하였다. Aspect는 애플리케이션의 핵심 기능을 담고 있지는 않지만 애플리케이션을 구성하는 한 가지 요소로써 핵심 기능에 부가되어 의미를 갖는 모듈을 의미한다. 그리고 이렇게 애플리케이션의 핵심적인 기능에서 부가적인 기능을 분리하여 독특한 모듈로 만들고 설계하여 개발하는 방법을 AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)라고 부른다.

AOP는 OOP를 대체하는 기술이 아니라 OOP를 돕는 보조 기술로써 핵심 기능을 설계하고 구현할 때 객체지향적인 가치를 지킬 수 있도록 도와준다. 예를 들어 사용자 관리 기능을 개발할 때 핵심 로직 대신 트랜잭션의 처리라는 관점에서 바라보고, 그 부분을 집중해서 설계하고 개발할 수 있도록 도와준다.

  • 어드바이스(Advice): 타겟 오브젝트에 적용하는 부가 기능을 담은 오브젝트
  • 포인트컷(PointCut): 메소드 선정 알고리즘을 담은 오브젝트

Spring의 AOP는 내부적으로 다음과 같이 동작을 하게 된다.
1. 다이내믹 프록시 객체의 생성 요청
2. 포인트컷을 통해 부가 기능 대상 여부 확인
3. 어드바이스로 부가 기능 적용
4. 실제 기능 처리

장점

  • 공통 관심 사항을 핵심 관심사항으로부터 분리시켜 핵심 로직을 깔끔하게 유지할 수 있다.
  • 그에 따라 코드의 가독성, 유지보수성 등을 높일 수 있다.
  • 각각의 모듈에 수정이 필요하면 다른 모듈의 수정 없이 해당 로직만 변경하면 된다.
  • 공통 로직을 적용할 대상을 선택할 수 있다

Spring AOP

Spring AOP는 기본적으로 프록시 방식으로 동작한다. 프록시 패턴이란 어떤 객체를 사용하고자 할 때, 객체를 직접적으로 참조 하는 것이 아니라, 해당 객체를 대행(대리, proxy)하는 객체를 통해 대상객체에 접근하는 방식을 말한다.

Spring AOP는 왜 프록시 방식을 사용하는가?

프록시 객체 없이 Target 객체를 사용하고 있다고 생각해보자. Aspect 클래스에 정의된 부가 기능을 사용하기 위해서, 우리는 원하는 위치에서 직접 Aspect 클래스를 호출해야 한다. 이 경우 Target 클래스 안에 부가 기능을 호출하는 로직이 포함되기 때문에, AOP를 적용하지 않았을 때와 동일한 문제가 발생한다. 여러 곳에서 반복적으로 Aspect를 호출해야 하고, 그로 인해 유지보수성이 크게 떨어진다.
그래서 Spring에서는 Target 클래스 혹은 그의 상위 인터페이스를 상속하는 프록시 클래스를 생성하고, 프록시 클래스에서 부가 기능에 관련된 처리를 한다. 이렇게 하면 Target에서 Aspect을 알 필요 없이 순수한 비즈니스 로직에 집중할 수 있다.

Spring의 AOP 프록시 구현 방법

Spring의 AOP 프록시 구현 방법에는 JDK Proxy와 CGLib Proxy가 있다. 두 방식의 가장 큰 차이점은 Target의 어떤 부분을 상속 받아서 프록시를 구현하느냐에 있다.

JDK Proxy

JDK Proxy는 Target의 상위 인터페이스를 상속 받아 프록시를 만든다. 따라서 인터페이스를 구현한 클래스가 아니면 의존할 수 없으므로 프록시를 적용하기 위해서는 반드시 인터페이스를 생성해야 한다. 또한, Target에서 다른 구체 클래스에 의존하고 있다면, JDK 방식에서는 그 클래스(빈)를 찾을 수 없어 런타임 에러가 발생한다.

단점

  • 프록시를 적용하기 위해서 반드시 인터페이스를 생성해야 함
  • 구체 클래스로는 빈을 주입받을 수 없고, 반드시 인터페이스로만 주입받아야 함

CGLib Proxy

CGLib Proxy는 Target 클래스를 상속 받아 프록시를 만든다. JDK 방식과는 달리 인터페이스를 구현하지 않아도 되고, 구체 클래스에 의존하기 때문에 런타임 에러가 발생할 확률도 상대적으로 적다. 또한 JDK Proxy는 내부적으로 Reflection을 사용해서 추가적인 비용이 들지만, CGLib는 그렇지 않다. 대신 CGLib 프록시는 상속을 이용하므로 기본 생성자를 필요로 하며, 생성자가 2번 호출되고 final 클래스나 final 메소드면 안된다는 제약이 있다. 하지만 최근 스프링에서는 이러한 문제들을 해결하여 여러 성능 상 이점으로 인해 Spring Boot에서는 CGLib를 사용한 방식을 기본으로 채택하고 있다.

Ref.

https://mangkyu.tistory.com/175
https://minkukjo.github.io/framework/2021/05/23/Spring/

profile
log.info("공부 기록 블로9")
post-custom-banner

0개의 댓글