java OOP 관련 게시글을 작성하다가 Spring POJO 에서 필수적으로 알아야 하는 AOP/IoC/DI/PSA에 대해 정리한 글을 공유하면 좋을 것 같아 글을 남겨 본다.
그중에서도 이번 게시글은 AOP에 관련된 내용이다.
2024.05.01 - [개발/java] - Garbage Collection과 JVM 메모리 구조 ( OOP를 제대로 알기 )
AOP 란?
AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다. OOP를 보완한 일종의 패러다임이라고 볼 수도 있다
관점지향이란 어떤 서비스 로직에 대해 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화를 진행하는 것을 의미한다.
핵심적인 관점은 우리가 적용하고자 하는 핵심 비즈니스 로직이되며, 부가적인 관점은 핵심 로직을 실행하기 위해서 행해지는 데이터베이스 연결, 로깅, 파일 입출력등을 예로 들 수 있다.
- 핵심 비즈니스 로직
- 부가적인 기능 ( 인프라 로직 )
애플리케이션의 전 영역에서 나타날 수 있으며 중복코드를 만들어낼 가능성 때문에 유지보수가 힘들어질 수 있다. 비즈니스 핵심 로직과 함께 있으면 비즈니스 로직의 이해를 방해한다. 소요시간, 권한체크, DB 연결 및 트랜잭션 처리, 로깅, 파일입출력등이 모두 인프라로직에 해당한다. 인프라 로직의 중복이 횡단으로 나타나기 때문에 이것을 횡단 관심사(흩어진관심사, Crosscutting Concerns)라고 표현한다.
AOP에서 각 관점을 기준으로 로직을 모듈화 한다는 것은 코드들을 부분적으로 나누어서 모듈화 하겠다는 의미이다. 이렇게 반복적으로 쓰는 코드들, 즉 CrossCutting Concerns를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하는 것이 AOP의 취지이다. 이렇게 하면 코드의 간결성을 높일 수 있고 변경과 확장이 용이해진다.
AOP의 동작방식
스프링의 AOP 동작 방식은 다음과 같다.
memberService와 memberRepository에 대해 AOP를 생성하고 나면 memberController 이 service와 repository를 호출했을 때 각각의 클래스들과 비슷하게 생긴 프록시 객체를 생성한다. 이 프록시객체는 스프링이 생성한 객체로 AOP에서 지정해 둔 메서드를 실행한 뒤에 실제 클래스들을 호출하게 된다.
이런 프록시 객체를 생성하는 방법은 두 가지가 있다. 일반적으로 스프링에서 AOP를 사용할 경우 기본적으로 JDK proxy를 지원한다.
- JDK dynamic proxy ( interface based )
interface 기반이다. targeted object가 interface를 구현하였다면 JDK dynamic proxy가 사용된다.
Spring에서 제공하는 기능으로 자동 프록시 생성기를 통해 직접 프록시 객체를 생성하고 특별한 처리를 해준다. Spring은 프록시를 구현할 때 프록시를 구현한 객체를 마치 실제빈처럼 포장하고 2개의 빈을 모두 등록하는 것이 아니라 실제 빈을 프록시가 적용된 빈으로 바꿔치기한다.
인터페이스를 기반으로 프록시 객체를 생성하기 때문에 인터페이스를 구현한 클래스가 아니면 프록시 객체를 생성할 수 없다. 따라서 프록시를 적용하기 위해서는 반드시 인터페이스를 생성해야 하고, 구체 클래스(Concrete class, 클래스의 모든 메서드를 완벽하게 구현한 클래스)로는 빈을 주입받을 수 없으며 인터페이스로만 주입받아야 한다.
- CGLIB proxy
class 기반이다. targeted object가 interface를 구현하지 않았다면 사용 된다. JDK dynamic proxy에서 인터페이스 없이 구체 클래스(Concrete class)에 의존하는 경우 AOP를 적용할 수 없다는 단점을 ( AOP를 적용하기 위해 모든 빈들에게 인터페이스를 만들어 줘야 하는 점 ) 해결할 수 있다. 해당 프록시는 상속을 이용하므로 기본 생성자를 필요로 하며 생성자가 2번 호출되고 final 클래스나 final 메서드면 사용할 수 없다는 제약이 있다.
- @EnableAspectJAutoProxy의 ProxyTargetClass
스프링 프레임워크에서 JDK dynamic 프록시를 구현하도록 할 것인지, CGLIB 프록시를 구현할 것인지를 지정하는 옵션이다.
Springboot에서는 CGLIB 라이브러리가 안정화되었다고 판단하여 proxyTragetClass=true를 default로 사용하고 있으며 이것은 CGLIB proxy를 기본으로 사용한다는 것을 의미한다. ( 스프링에서는 여전히 기본값은 false이다. 부트에서만 해당하니 주의하자 )
AOP 용어
AOP에서 사용하는 용어들은 다음과 같다.
- Aspect
흩어진 관심사를 모듈화 한 것
- Target
어떤 대상에 부가 기능을 부여할 것인가를 정한다. Aspect를 적용하는 곳, 대상객체인 model과 Controller 클래스, 메서드등이 해당한다.
- Advice
Aspect의 동작을 적은 것을 의미한다
@Before | 어드바이스 타겟 메서드가 호출되기 전에 어드바이스 기능을 수행함 |
@After | 타겟 메서드의 결과에 상관없이 완료되면 어드바이스 기능을 수행함 |
@AfterReturning(정상적 반환 이후) | 어드바이스 타겟 메서드가 성공적으로 리턴 후에 기능을 수행함 |
@AfterThrowing(예외 발생 이후) | 어드바이스 타겟 메서드 수행 중 예외를 던지면 기능을 수행함 |
@Around(이전) | 어드바이스가 타겟 메서드를 감싸서 호출 전과 후에 기능을 수행 함 |
- Join point
어디에 적용할 것인가( 메서드, 필드, 객체, 생성자 등 ) 를 의미하며 Advice가 적용되는 시점을 의미한다
단, 스프링은 메서드에서만 사용할 수 있다
- Point cut
실제 advice가 적용 될 지점, Spring AOP에서는 advice가 적용될 메서드를 선정한다
- Weaving
어드바이스를 적용하는 것을 의미한다. 공통 코드를 원하는 대상에 삽입하는 것이 해당한다. ( AOP가 적용되는 것 )
컴파일, 클래스 로딩, 런타임 시점 중 하나에 실행된다
Runtime weaving | JDK dynamic proxy나 CGLIB proxy를 생성하여 실행시간에 target에 weaving 하는 방식 |
Compile-time weaving | 컴파일 시점에 Application 소스코드와 Aspect 코드를 Weaving 하여 AOP가 적용된 클래스를 만들어내는 방식 |
Post-compile weaving | Binary weaving이라고도 하며 이미 존재하는 클래스나 JAR파일을 조작하여 weaving 한다 |
Load-time weaving | Weaving 하는 시점을 class loader가 class를 jvm에 로드하는 시점으로 늦춘 것을 제외하고 post-compile weaving 방식과 동일하다 |
AOP 예제 코드
'Dev > Springboot' 카테고리의 다른 글
Spring 의 PSA - 웹 기술 스택을 간편하게 변경할 수 있는 방법 (0) | 2024.05.06 |
---|---|
Spring의 DI - 코드를 유연하고 단순하게 하는 방법 (0) | 2024.05.06 |
HttpUrlConnection을 사용하여 외부URL Data Scrapping 하기 (0) | 2024.03.14 |
WebApplication 의 Exception 처리 (0) | 2024.03.10 |
RedirectAttributes 사용시 java.lang.IllegalArgumentException: Model has no value for key 오류 해결하기 (0) | 2024.02.25 |