<토비의스프링> 6.4~6.5 AOP(2)
by BFine6.4 스프링의 프록시 팩토리빈
ProxyFactoryBean
프록시를 생성해 빈오브젝트로 등록
TxProxyFactoryBean 과 차이점
- 순수하게 프록시를 생성하는 작업만 담당
- 부가기능은 별도의 빈
부가기능은 MethodInterceptor 인터페이스를 구현
- InvocationHandler와 달리 타깃이 InvocationHandler를 구현한 클래스정보를 몰라도됨
코드 수정
@Test public void proxyFactoryBean() { ProxyFactoryBean pfBean = new ProxyFactoryBean(); pfBean.setTarget(new HelloTarget()); pfBean.addAdvice(new UppercaseAdvice()); Hello hello = (Hello) pfBean.getObject(); } static class UppercaseAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { String ret = (String) invocation.proceed(); // MethodInvocation은 메소드 정보와 타깃오브젝트를 알고있기 때문에 // 전달할 필요가없다. return ret.toUpperCase(); } }
어드바이스 : 타깃이 필요없는 순수한 부가기능
- MethodInvocation
- 타깃 오브젝트의 메소드를 실행할 수 있는 기능이 존재
- 일종의 콜백 오브젝트,
proceed()
를 실행하면 타깃의 메소드를 내부적으로 실행 - 얘를 구현한클래스는 공유가능한 템플릿처럼 동작
- ProxyFactoryBean
- MethodInvocation을 싱글톤으로 두고 공유
addAdvice()
를 통해여러개의 MethodInterceptor 추가 가능- 앞서 문제점인 추가할때마다 빈추가 문제 해결
- 인터페이스 자동검출 기능을 통해 타깃오브젝트가 구현한 인터페이스 정보를 알아냄
- MethodInterceptor 처럼 타깃에 적용하는 순수 부가기능을 담은 객체를 어드바이스라 한다
- MethodInvocation
포인트컷 : 부가기능 대상 메소드 선정방법
ProxyFatoryBean ▽ 생성 다이나믹 프록시 -> 포인트컷 (대상메서드 선정) -> 어드바이스 -> invocation 콜백 -> 타깃
DI로 주입받는 스프링빈
@Test public void pointcutAdvisor() { ProxyFactoryBean pfBean = new ProxyFactoryBean(); pfBean.setTarget(new HelloTarget()); NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); pointcut.setMappedName("sayH*"); pfBean.addAdvisor(new DefaultPointcutAdvisor(pointcut, new UppercaseAdvice())); // 별개로 두는 이유는 ProxyFactoryBean에 여러개의 어드바이스와 // 포인트컷이 추가 될 수 있기 떄문 Hello proxiedHello = (Hello) pfBean.getObject(); }
어드바이스와 포인트컷을 묶은 객체를 어드바이저
ProxyFactoryBean 적용
TransationAdvice
public class TransactionAdvice implements MethodInterceptor { PlatformTransactionManager transactionManager; @Override public Object invoke(MethodInvocation invocation) throws Throwable { TransactionStatus status = this.transactionManager.getTransaction( new DefaultTransactionDefinition()); try { Object ret = invocation.proceed(); // 타깃실행 this.transactionManager.commit(status); return ret; } catch (RuntimeException e) { this.transactionManager.rollback(status); throw e; } } }
xml 설정
<bean id="transactionAdvice" class="user.service.TransactionAdvice"> <property name="transactionManager" ref="transactionManager" /> </bean> <bean id="transactionPointCut" class="org.springframework.aop.support.NameMatchMethodPointcut"> <property name="mappedName" value="upgrade*" /> </bean> <bean id="transactionAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="transactionAdvice" /> <property name="pointcut" ref="transactionPointCut" /> </bean> <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="userServiceImpl" /> <property name="interceptorNames"> <list> <value>transactionAdvisor</value> </list> </property> </bean>
6.5 스프링 AOP
자동 프록시 생성
타킷마다 거의 비슷한 내용의 프록시팩토리빈 설정정보를 추가해야함..
→ 자동으로 각 타깃 빈에 대한 프록시를 만들 수 없을까?
빈후처리기를 이용항 자동프록시 생성기
BeanPostProcesser
인터페이스를 구현해 만드는 빈후처리기스프링빈으로 만들어 빈을 가공
DefaultAdvisorAutoProxyCreator
스프링에서 제공하는 빈후처리기어드바이저를 이용한 자동 프록시 생성기
빈이 생성될떄마다 빈후처리기로 보내 후처리작업을 요청
빈 프로퍼티를 강제로 수정, 별도의 초기화 작업가능
⇒ 이를 활용해 프록시를 빈으로 대신 등록
동작
- 빈후처리기가 있으면 스프링은 빈을 만들때 후처리기로 보낸다.
- 모든 어드바이저내의 포인트컷으로 프록시 적용대상인지 확인
- 빈에대한 프록시를 만들고 어드바이저를 연결
- 원래 빈 대신 프록시를 컨테이너에게 반환
포인트컷
- 메소드 Matcher와 클래스 필터를 가지고있음
DefaultAdvisorAutoProxyCreator
어드바이저를 이용하는 자동프록시 생성기 등록
//빈이름으로 조회될 필요가 없는 빈은 아이디 등록이 필요없다. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" /> <bean id="transactionPointCut" class="service.NameMatchClassMethodPointcut"> <property name="mappedClassName" value="*ServiceImpl" /> <property name="mappedName" value="upgrade*" /> </bean>
자동 프록시 테스트
UserService 등록
<bean id="testUserService" class="UserServiceTest$TestUserServiceImpl" parent="userService" />
$
기호는 스태틱 멤버클래스를 지정할때 사용특정 테스트 클래스에서만 사용되는 거면 스태틱 멤버클래스로 정의하는 것이 편리
자동프록시 확인
자동으로 된다고하면 한번쯤 직접확인해 보는 습관을 가지자!
- 확인사항
- 트랙잭션 부가기능이 적용되는지 → 롤백테스트
- 아무 빈에나 적용된게 아닌지 확인
- 확인사항
포인트컷 표현식을 이용한 포인트컷
- 위는 이름패턴을 각각 클래스 필터, 메서드 매처로 비교해서 선정함
- 세밀하게 적용하려면 리플렉션 API 를 쓸수 있으나 번거로움
- 표현식 언어를 사용해 포인트컷을 작성하는 것이 포인트컷 표현식
- 스프링의 포인트컷 표현식은 AspectJ라는 프레임워크에서 제공한걸 사용
- 표현식 문법
execution()
가장 대표적으로 사용- [접근제한자 패턴] 타입패턴 [타입패턴.]이름패턴 (타입패턴 | ".. ", ... )[throws 예외 패턴]
- 리플렉션의
Class.getMethod
로 메소드의 풀 시그니처 확인가능
- 적용
- 특정 어노테이션으로 포인트컷 선정하는 것도 가능 @Transactioal
- 단점은 런타임시점까지 문법의 검증이나 기능확인이 되지않음
- 클래스 이름 패턴이 아니라 타입패턴으로 등록됨
- 슈퍼클래스 구현인테페이스도 포함
AOP란 무엇인가?
트랙잭션 서비스 추상화
트랙잭션 기술이 비즈니스로직에 종속
→ 인터페이스와 DI로 분리
프록시 데코레이터 패턴
투명한 부가기능 부여를 가능하게 하는 데코레이터
: 클라이언트 → {데코레이터[트랜잭션] - 타킷}
다이나믹 프록시와 팩토리빈
- 비즈니스 로직 인터페이스의 모든 메소드마다 기능부여하는 코드추가
- 불필요한 메서드에도 일일히 구현
- 프록시 클래스를 자동으로 만들자!
- 런타임시 JDK 다이나믹프록시
- 동일기능 프록시를 여러 타킷에 적용시 타깃단위로 중복
- 스프링팩토리빈
- 어드바이스 + 포인트컷을 프록시에서 분리 및 공유사용
- 런타임시 JDK 다이나믹프록시
- 비즈니스 로직 인터페이스의 모든 메소드마다 기능부여하는 코드추가
자동프록시 생성
- 빈마다 일일히 팩토리빈 등록해야함
- 빈생성 후처리기 기법 적용 → 포인트컷이라는 독립정보로 완전분리
- 빈마다 일일히 팩토리빈 등록해야함
부가기능 모듈화
- 서로 낮은 결합도, 유연성, 확장성
- 부가기능이기 때문에 스스로 독립적으로 존재하기는 힘듬
AOP: 에스팩트 지향 프로그래밍
부가기능 모듈을 에스펙트라고 부르기 시작
핵심기능은 아니지만 중요한 요소
여러 부가기능은 결국 핵심 기능과 함께 어우러져 동작
핵심기능에서 부가기능을 분리해서 에스팩트로 개발하는 방법
→ 에스팩트 지향 프로그래밍
OOP를 돕는 보조적인 기술
AOP 적용기술
- 프록시를 이용한 AOP
- 타깃 메서드에 다이나믹하게 적용해주기 위해 중요한 역할
- 스프링 AOP는 프록시 방식이다
- 바이트코드 조작 AOP (AspectJ)
- JVM 로딩시점을 가로채서 바이트코드를 조작
- 컨테이너 사용되지 않는 환경에서도 가능
- 다양한 작업에 부가기능 부여가능
- 프록시를 이용한 AOP
AOP 용어
- 조인포인트
- 어드바이스가 적용될수 있는 위치
- 어드바이스
- 부가기능을 담은 모듈
- 조인포인트
'개발서적 > 토비의스프링' 카테고리의 다른 글
<토비의스프링> 7.1~7.2 SQL DAO 분리하기 (0) | 2021.02.20 |
---|---|
<토비의스프링> 6.7~6.8 트랜잭션 어노테이션 (0) | 2021.02.20 |
<토비의스프링> 6.1~6.3 AOP (0) | 2021.02.18 |
<토비의스프링> 5.1~5.2 서비스추상화 (0) | 2021.02.17 |
<토비의스프링> 4.1~4.2 예외 (0) | 2021.02.17 |
블로그의 정보
57개월 BackEnd
BFine