AOP
부가 기능을 핵심 기능으로 분리하기 위해 등장한 기술. 부가 기능을 분리함으로써 해당 로직을 재사용할 수 있고, 핵심 기능은 핵심 역할에만 집중할 수 있도록 도와줌
Spring의 AOP는 프록시 방식으로 동작. Spring에서 AOP를 활용하기 위해서는 @EnableAspectJAutoProxy 어노테이션을 붙여줘야하며, 이에 대한 옵션으로 proxyTargetClass가 있음.
Proxy 구현체
- 프록시 구현체로는 두 가지가 있음
- JDK Proxy(Dynamic Proxy)
- 구현된 클래스의 인터페이스를 프록시 객체로 구현해서 코드를 끼워넣는 방식
- 자바에서 기본적으로 제공
- 프록시 객체를 생성할 때 내부적으로
Reflection
을 사용
- 리플렉션 API가 비용이 크기 때문에 가급적 사용하지 않는 것을 추천
- AOP 적용을 위해 반드시 인터페이스를 구현해야한다는 단점 존재
- 서비스 계층에서 인터페이스 → XXXImpl 클래스를 작성하던 관례도 JDK Proxy의 특성 때문이기도 함
- Dynamic Proxy는
InvocationHandler
라는 인터페이스 구현
- 메소드에 대한 명세와 파라미터를 가져오는 과정에서 리플렉션을 사용
- 사용 코드 예시
- CGLib
- 인터페이스가 아닌 클래스 기반으로 바이트코드를 조작하여 타켓 클래스를 상속받는 프록시 객체를 생성
- ASM이라는 자바 바이트코드 조작 및 분석 프레임워크 사용 → 클래스를 동적으로 생성하거나 수정
- 상속 방식을 사용하기 때문에 final이나 private과 같이 오버라이딩을 지원하지 않는 경우 해당 메소드에 대한 Aspect 적용 불가
- 바이트코드를 조작해 프록시 만들기 때문에 Dynamic Proxy에 비해 성능이 우수
- 외부 3rd party library
Enhancer
라는 클래스를 바탕으로 Proxy를 생성
- 사용 코드 예시
- 자바 리플렉션 방식보다 CGLib의 MethodProxy 방식이 더 빠르고 예외를 방식시키지 않아 CGLib를 기본 프록시 객체 생성 라이브러리로 채택
스프링의 AOP 구현
- AOP 적용 대상이 인터페이스거나 인터페이스를 구현하고 있으면 jdkDynamicAopProxy가 생성된다.
- 그렇지 않으면 ObjenesisCglibAopProxy 기반 실 객체가 생성된다.
- Objenesis : 과거 Cglib의 몇 가지 단점을 해결주는 라이브러리 (생성자 중복 호출, default 생성자 필요 문제 등)
- Transaction 대상의 경우 기본적으로 Cglib으로 생성하게 설정되어있다.
- 성능상 Cglib이 이점이 많고, 예외발생 확률도 적다고 한다.
스프링의 ProxyFactoryBean
ProxyFactoryBean
는 프록시를 생성해 Bean 객체로 등록하게 해주는 팩토리 빈
…https://velog.io/@hanblueblue/Spring-Proxy-2-Spring-with-proxy
@Transactional
동작 원리
- Transactional 애노테이션은 AOP를 사용하여 구현됨
- 메인 로직 앞 뒤에 begin과 commit을 붙여주고, 에러 발생 시 rollback을 처리해주는 역할 담당