[ AOP 적용 - XML 방식 ]
| 용어 |
쉬운 설명 |
예시 |
| Aspect |
부가 기능을 모듈화한 클래스 |
MemberLog |
| Advice |
부가 기능 메서드 |
MemberLog.logBefore() |
| Target |
핵심 기능을 가진 클래스 |
MemberService |
| JoinPoint |
Advice를 적용할 수 있는 모든 시점(Spring AOP는 메서드 실행 지점) |
join(), login(), update() 실행 시점 전부 |
| Pointcut |
JoinPoint 중 Advice를 실제 적용할 위치를 선별하는 표현식 |
execution(* MemberService.join(..)) |
| Proxy |
Target을 감싸 Advice를 대신 실행하는 클래스 |
MemberService$$Proxy |
| Weaving |
Pointcut 기준으로 Target에 Advice를 결합하는 과정 |
join() 호출 시 logBefore()가 자동 실행 |
1. AOP 설정
- aop 네임스페이스 추가 필요
- <aop:config> 태그 안에 AOP 설정을 작성함
- Aspect로 사용할 클래스를 반드시 Bean으로 먼저 등록해야 함
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 1. Aspect로 사용할 클래스를 Bean으로 등록 -->
<bean id="memberLog" class="com.example.myapp.MemberLog"/>
<!-- 2. AOP 설정 -->
<aop:config>
<aop:pointcut .../>
<aop:aspect ref="memberLog">
<aop:before .../>
</aop:aspect>
</aop:config>
</beans>
2. AOP 적용 태그
| 태그 |
설명 |
| <aop:config> |
AOP 설정의 최상위 태그 |
| <aop:aspect> |
Aspect 선언. ref로 Bean 지정 |
| <aop:pointcut> |
Pointcut 표현식 정의 |
| <aop:before> |
Before Advice 적용 |
| <aop:after> |
After Advice 적용 |
| <aop:after-returning> |
After Returning Advice 적용 |
| <aop:after-throwing> |
After Throwing Advice 적용 |
| <aop:around> |
Around Advice 적용 |
1) <aop:config>
- AOP 설정의 최상위 태그. 모든 AOP 설정은 이 태그 안에 작성함
2) <aop:aspect>
<aop:aspect id="logAspect" ref="memberLog" order="1">
...
</aop:aspect>
| 속성 |
설명 |
| ref |
Aspect로 사용할 Bean id 지정 (필수) |
| id |
Aspect 식별자 |
| order |
여러 Aspect가 있을 때 실행 순서 지정 |
3) <aop:pointcut>
- Advice를 적용할 대상을 표현식으로 정의함
| 속성 |
설명 |
| id |
Pointcut 식별자. Advice에서 pointcut-ref로 참조 (필수) |
| expression |
Pointcut 표현식 (필수) |
<aop:pointcut id="memberPointcut"
expression="execution(* com.example.myapp.MemberService.*(..))"/>
4) <aop:before> / <aop:after>
| |
|
| 속성 |
설명 |
| method |
Aspect 클래스에서 실행할 메서드명 (필수값. 메서드명 그대로 작성!) |
| pointcut-ref |
적용할 Pointcut id 참조 |
| pointcut |
Pointcut 표현식 직접 작성 |
<aop:before method="logBefore" pointcut-ref="memberPointcut"/>
<aop:after method="logAfter" pointcut-ref="memberPointcut"/>
5) <aop:after-returning>
| 속성 |
설몀 |
| method |
실행할 메서드명 (필수) |
| pointcut-ref |
적용할 Pointcut id 참조 |
| returning |
반환값을 받을 파라미터명 |
<aop:after-returning method="logReturn"
pointcut-ref="memberPointcut"
returning="result"/>
public void logReturn(Object result) {
System.out.println("반환값 : " + result);
}
6) <aop:after-throwing>
| 속성 |
설명 |
| method |
실행할 메서드명 (필수) |
| pointcut-ref |
적용할 Pointcut id 참조 |
| throwing |
발생한 예외를 받을 파라미터명 |
<aop:after-throwing method="logException"
pointcut-ref="memberPointcut"
throwing="ex"/>
public void logException(Exception ex) {
System.out.println("예외 발생 : " + ex.getMessage());
}
7) <aop:around>
- 메서드 실행 전후를 모두 감쌈.
- Target 메서드의 실행 시기, 방법, 실행 여부까지 결정
| 속성 |
설명 |
| method |
실행할 메서드명 (필수) |
| pointcut-ref |
적용할 Pointcut id 참조 |
<aop:around method="logAround" pointcut-ref="memberPointcut"/>
public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("실행 전");
Object result = pjp.proceed(); // Target 메서드 실행
System.out.println("실행 후");
return result;
}
3. 태그 작성 순서
1) <aop:config> 안에서의 순서
| 순서 |
태그 |
설명 |
| 1 |
<aop:pointcut> |
전역 Pointcut 선언(여러 Aspect에서 공통으로 재사용 가능 |
| 2 |
<aop:advisor> |
트랜잭션 등 스프링이 제공하는 Advice 적용 |
| 3 |
<aop:aspect> |
일반 Aspect 선언 |
❓ <aop:advisor> vs <aop:aspect> 비교
| 구분 |
<aop:advisor> |
<aop:aspect> |
| 사용 대상 |
일반 POJO 클래스 (우리가 직접 만든 Aspect) |
스프링이 제공하는 Advice (트랜잭션 등) |
| 주로 사용할 때 |
로그, 보안 등 커스텀 부가기능 |
트랜잭션 관리 |
| 예시 |
ref="memberLog" |
advice-ref="txAdvice" |
<aop:config>
<aop:pointcut id="txPointcut"
expression="execution(* com.example.myapp.service.*.*(..))"/>
<!-- 스프링 트랜잭션 Advice 적용 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
<!-- 직접 만든 Aspect 적용 -->
<aop:aspect ref="memberLog">
<aop:before method="logBefore" pointcut-ref="txPointcut"/>
</aop:aspect>
</aop:config>
2) <aop:aspect> 안에서의 순서
| 순서 |
태그 |
설명 |
| 1 |
<aop:pointcut> |
지역 Pointcut 선언 (해당 Aspect 안에서만 사용 가능) |
| 2 |
<aop:before> / <aop:after> 등 |
Advice 적용 |
전체 코드
더보기
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 1. Aspect로 사용할 클래스를 Bean으로 등록 -->
<bean id="memberLog" class="com.example.myapp.MemberLog"/>
<aop:config>
<!-- 2. 전역 Pointcut 선언 -->
<aop:pointcut id="memberPointcut"
expression="execution(* com.example.myapp.MemberService.*(..))"/>
<!-- 3. Aspect 선언 -->
<aop:aspect ref="memberLog">
<!-- 4. Advice 적용 -->
<aop:before method="logBefore" pointcut-ref="memberPointcut"/>
<aop:after method="logAfter" pointcut-ref="memberPointcut"/>
</aop:aspect>
</aop:config>
</beans>
// Aspect 클래스 (부가기능 구현)
public class MemberLog {
public void logBefore() {
System.out.println("메서드 실행 전 로그");
}
public void logAfter() {