spring - 스프링 AOP

오늘·2021년 5월 26일
0

웹 페이지 연습

목록 보기
20/35

관점 지향 프로그래밍

만약 회원 등급 기능을 구현시 로깅, 보안, 트랜잭션 기능 등의 보조기능을 일일히 구현해야했다. 이 경우 규모가 있는 웹 애플리케이션의 경우 클래스의 메소드 마다 이런 작업을 수작업으로 하나하나 하기에는 시간도 많이 걸리고 소스 코드가 복잡해졌고, 즉 유지관리에 문제가 생길 수 있었다.
-> 이에 관점 지향 프로그래밍(Aspect oriented Programming, AOP) 를 이용해 주 기능과 보조 기능을 분리해서 메소드에 적용

원리

각각의 보조 기능을 미리 만들어 놓고, 설정만 해주면 각각의 주기능을 수행하는 메소드나 클래스에 선택적으로 보조 기능이 적용

AOP 기능 구현하는 방법

스프링 프레임 워크에서 AOP 기능을 구현하는 방법
1. 스프링 프레임워크에서 제공하는 API를 이용하는 방법
2. @Aspect 어노테이션을 이용하는 방법


스프링 API를 이용하기

관련 용어

API를 이용해 AOP 기능을 구현하는 과정은 이렇다.

  1. 타깃(Target) 클래스를 지정
    타깃
    : 어떤 대상에 부가 기능을 부여할까?
    : advice가 적용되는 클래스

  2. 어드바이스(Advice) 클래스를 지정
    Advice
    : 어떤 부가기능?
    : aspect의 실제 구현체(클래스)를 의미한다. 메소드 호출을 기준으로 여러 지점에서 실행

  3. 설정 파일에서 포인트컷(Pointcut)을 설정
    Pointcut
    : 실제 Advice가 적용될 지정 advice가 적용될 메소드를 선정
    : advice가 적용되는 대상 지정. 패키지 이름, 클래스 이름, 메소드 이름을 정규식으로 지정하여 사용한다.

  4. 설정 파일에서 어드바이스와 포인트컷을 결합하는 어드바이저를 설정
  5. 설정 파일에서 스프링의 ProxyFactoryBean 클래스를 이용해 타깃에 어드바이스를 설정
  6. getBean() 메서드로 빈 객체에 접근해 사용

스프링 API를 이용한 AOP 기능 실습

  1. 새 프로젝트를 만들고 lib폴더를 생성해 라이브러리 클래스 패스부터 설정

  2. AOP를 설정하는 xml 작성
    -> 스프링의 ProxyFactoryBean의 interceptorNames 속성에 logAdvice를 어드바이스 빈으로 설정하여, 타깃 클래스의 메소드를 호출했을 시 logAdvice를 실행하도록 했다.

<?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" />
   
   
   <!-- 스프링 프레임워크에서 제공하는 ProxyFactoryBean을 이용해 타깃과 어드바이서 엮어주기 -->
   <bean id="proxyCal"
          class="org.springframework.aop.framework.ProxyFactoryBean">
      <!-- 타깃 빈을 calcTarget 빈으로 지정 -->
      <property name="target" ref="calcTarget"/>
      <!-- 스프링의 프록시팩토리빈의 interceptorNames 속성에 -->
      <property name="interceptorNames">
      	 <!-- logAdvice를 어드바이스 빈으로 설정하여
	 타깃 클래스의 메소드 호출시 실행되게끔한다 -->
         <list>
            <value>logAdvice</value>
         </list>
      </property>
   </bean>
</beans>
  1. 타깃 클래스인 Calculator 클래스 작성
package com.spring.ex01;

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);
	}

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

	public void divide(int x, int y) {
		int result=x / y;
		System.out.println("결과:"+ result);
	}
}
  1. advice클래스인 LoggingAdvice 작성
package com.spring.ex01;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

// 인터페이스MethodInterceptor을 구현해 어드바이스 클래스 만들기
public class LoggingAdvice implements MethodInterceptor {
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// 메소드 호출 전에 수행하는 구문으로
		System.out.println("[메서드 호출 전 : LogginAdvice");
		System.out.println(invocation.getMethod() + "메서드 호출 전");
		
		// invocation을 이용해 메소드를 호출
		Object object = invocation.proceed();
		
		// 메소드 호출 후에 수행하는 구문
		System.out.println("[메서드 호출 후 : loggingAdvice");
		System.out.println(invocation.getMethod() + "메서드 호출 후");
		return object;
	}
}
  1. 실행할 코드 작성
package com.spring.ex01;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CalcTest {
	public static void main(String[] args) {
		// xml 불러오기
		ApplicationContext context = new ClassPathXmlApplicationContext("AOPTest.xml");

		// id가 proxyCal인 빈에 접근하기
		Calculator cal = (Calculator) context.getBean("proxyCal");

		// 메소드를 호출 전.후에 어드바이스 빈 적용
		cal.add(100, 20);
		System.out.println();
		cal.subtract(100, 20);
		System.out.println();
		cal.multiply(100, 20);
		System.out.println();
		cal.divide(100, 20);
	}
}

0개의 댓글