20장. 스프링 AOP 기능

20.1 관점 지향 프로그래밍의 등장

  • 모든 웹 애플리케이션에서 공통으로 사용하는 보조기능(ex. 로깅, 트랜잭션, 예외 처리, 이메일 통보 기능 등)은 일일이 구현하는 번거로움을 관점 지향 프로그래밍(AOP, Aspect Oriented Programming)으로 해결한다.
  • AOP : 메서드 안의 주기능과 보조 기능을 분리한 후 선택적으로 메서드에 적용해서 사용하는 것
    • AOP를 사용하면 전체 코드에 흩어져 있는 보조 기능을 하나의 장소에 모아서 관리할 수 있음
    • 보조 기능을 자신이 원하는 주기능에 선택적으로 적용할 수 있음

 

 

20.2 스프링에서 AOP 기능 사용하기

 

  • 여러가지 AOP 관련 용어
용어 설명
aspect 구현하고자 하는 보조 기능
advice aspect의 실제 구현체(클래스). 메서드 호출을 기준으로 여러 지점에서 실행됨.
joinpoint advice를 적용하는 지점. 스프링은 method 결합점만 제공.
pointcut advice가 적용되는 대상. 패키지이름/클래스이름/메서드이름을 정규식으로 지정하여 사용.
target advice가 적용되는 클래스를 의미.
weaving advice를 주기능에 적용하는 것.

 

  •  스프링 프레임워크에서 AOP 기능을 구현하는 방법
    •   방법1) 스프링 프레임워크에서 제공하는 AOP 관련 API를 이용
    •   방법2) @Aspect 애너테이션을 이용

 

< 방법1. 스프링 API를 이용한 방법 >

  • 과정~
  1. Target 클래스를 지정
  2. Advice 클래스를 지정
  3. 설정파일에서 Pointcut을 설정
  4. 설정파일에서 Advice와 PointCut을 결합하는 Adviser를 설정
  5. 설정파일에서 스프링의 ProxyFactoryBean 클래스를 이용해 Target에 Advice를 설정
  6. getBean() 메서드로 빈 객체에 접근해 사용

 

  •  스프링 API에서 제공하는 여러가지 Advice 인터페이스
추상 메서드 설명 인터페이스
void before(Method method, Object[] args, Object target) 해당 메서드가 실행되기 전 실행 MethodBeforeAdvice
void afterReturning(Object returnValue, Method method, Object[] args, Object target)  해당 메서드가 실행된 후 실행 AfterReturningAdvice
void afterThrowing(Method method, Object[] args, Object target, Exception ex) 해당 메서드에서 예외 발생 시 실행 ThrowsAdvice
Object invoke(MethodInvocation invocation)  - 해당 메서드의 실행 전/후와 예외 발생 시 실행
- 위 세가지 인터페이스들의 기능을 동시에 수행 가능
MethodInterceptor

>> afterThrowning을 제외하고 모두 예외처리로 throws Throwable를 함

>> 클래스를 생성한 뒤 위의 인터페이스를 구현하면(해당 추상 메서드를 구현하면) 됨

>> 인자 설명  

  • Method method : 대상 객체에서 실행된 메서드를 나타내는 메서드 객체
  • Object[] args : 메서드 인자 목록
  • Object target : 대상 객체
  • Object returnValue : 대상 객체의 메서드가 반환하는 값
  • Exception ex : 발생한 예외 타입
  • MethodInvocation invocation : 대상 객체의 모든 정보를 담고 있는 객체(위의 method, args 등)
    • >> invocation.proceed()로 타깃 메서드 호출을 명시

 

  • 실습!!
  1. 프로젝트 생성 후 lib 클래스 패스 설정
  2. AOP 설정 파일 xml을 src 패키지에 생성
  3. xml) <bean> 태그를 이용해 타깃 빈과 어드바이스 빈 생성
  4. xml) 스프링의 ProxyFactoryBean 클래스 빈 생성 후 <property> 태그를 이용해 타깃 빈과 어드바이스 빈을 엮어줌
    • 사용할 어드바이스가 여러개일 시 <value> 태그로 추가
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
   "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
	<bean id="calcTarget" class="com.spring.ex01.Calculator"/>	<!-- 타깃 클래스 빈 생성 -->
	<bean id="logAdvice" class="com.spring.ex01.LoggingAdvice"/>	<!-- 어드바이스 빈 생성  -->
	
	<bean id="proxyCal" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 타깃-어드바이스 엮기  -->
		<property name="target" ref="calcTarget"/> <!-- 타깃 빈 지정 -->
		<property name="interceptorNames"> <!-- 어드바이스빈 지정 -->
			<list>
				<value>logAdvice</value> <!-- 어드바이스빈, 타깃 클래스의 메서드 호출 시 이 빈을 실행 -->
			</list>
		</property>
	</bean>
</beans>

>> 3~4의 과정.. 타깃 클래스의 모든 메서드에 AOP기능이 적용된다.

 

5. 타겟 클래스 작성

public class Calculator {
	
	public void add(int x, int y) {
		int result=x+y;
		System.out.println("결과:"+ result);
	}

	public void subtract(int x, int y) {
		int result=x - y;
		System.out.println("결과:"+ result);
	}

6. 어드바이스 클래스 작성

public class LoggingAdvice implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("[메서드 호출 전 : LoggingAdvice");
		System.out.println(invocation.getMethod()+" 메서드 호출 전"); //메서드 호출 전 수행
		
		invocation.proceed();	//타깃 메서드 호출!!!
		
		System.out.println("[메서드 호출 후 : LoggingAdvice");
		System.out.println(invocation.getMethod()+" 메서드 호출 후");	//메서드 호출 후 수행

		return null;
	}

}

- CalcTest.java

public static void main(String[] args) {

    ApplicationContext context=new ClassPathXmlApplicationContext("AOPTest.xml"); //빈 생성
    Calculator cal=(Calculator) context.getBean("proxyCal"); //빈에 접근
    cal.add(100, 20);
    System.out.println();
    cal.subtract(100, 20);
    System.out.println();
}

 

~ 결과~