본문 바로가기

오픈소스/스프링

[Spring] AOP 설명 및 예제

AOP(Aspect Oriented Programing)는 관점 지향 프로그램입니다. 

즉, 관점이 같은 코드가 반복되지 않도록 모듈화하는 프로그래밍 패러다임이라고 생각하시면 됩니다. 

 

어떠한 경우 AOP 적용이 좋은지 예시를 통해 알아보도록 하겠습니다. 

class A {
    method a() {
        AAAA
        method a가 하는 일들
        BBBB
    }
}
 
class B {
    method b() {
        AAAA
        method b가 하는 일들
        BBBB
    }
}

 

이렇듯 다른 메소드이지만 같은 작업을 하는 경우 흩어져 있는 코드들을 묶어서 같은 작업을 한 파일에 캡슐화 하는 역할이 필요할 때 AOP를 사용하는 것이 좋다고 합니다.

 

그들 중 Spring AOP는 프록시 패턴이라는 디자인 패턴을 사용해서 AOP효과를 내게 되는데,

프록시 패턴은 실제 기능을 수행하는 객체 대신에 가상의 객체를 사용해 로직의 흐름을 제어하는 디자인 패턴입니다.

 

그러면 예제를 통해 Spring AOP를 적용하는 방법에 대해 알아보도록 하겠습니다.

 

본 문서의 일부분은 https://choi9182.tistory.com/42 를 인용하였습니다.

 

# Contents


  • Spring AOP

 

 

# Spring AOP


공통된 로직을 처리하는 것이 AOP 이라 칭합니다.

그렇기 때문에 저는 오늘 공통된 로직은 IP 세션을 통해 일정 시간이 지나면 새로운 세션으로 처리하도록 하는 프로그램을 작성해보도록 하겠습니다.

 

0. pom.xml  라이브러리 확인

 AOP 개발을 위해 pom.xml에 아래 코드 부분이 있는지 확인해주세요. 제 AOP 버전은 1.6.10 이지만 버전은 아무버전 사용하셔도 괜찮습니다.

		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<dependency>
		    <groupId>org.aspectj</groupId>
		    <artifactId>aspectjweaver</artifactId>
		    <version>${org.aspectj-version}</version>
		</dependency>

 

확인이 끝나신 분들은 먼저 공통된 부분을 만들어 보도록 클래스를 정의하겠습니다.

 

1. Class 생성

ApplicationAspect.java를 com.mycom.myapp.common 패키지에 생성하겠습니다.

패키지명과 클래스명은 각자 알아서 정해주시기 바랍니다.

 

 

 

생성된 클래스 안에 아래 코드로 바꿔보겠습니다.

import java.util.Hashtable;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;

@Aspect
public class ApplicationAspect{
	private static final Logger logger = LoggerFactory.getLogger(ApplicationAspect.class);
	private Hashtable<String, Long > sessionsList; // 세션 목록
	
	public ApplicationAspect(){
		sessionsList = new Hashtable<String, Long>(); // session list 객체 생성
	}
	
	@Around(value="execution(* com.mycom.myapp.*.*(..)) && args(locale, model, request, response)")
	public Object beforeController(ProceedingJoinPoint pjp, Locale locale, Model model, HttpServletRequest request, HttpServletResponse response) throws Throwable{
		String key = request.getRemoteAddr();
		
		if (sessionsList.get(key) == null || System.currentTimeMillis() - sessionsList.get(key) > 5000) {
			logger.info("세션키가 발급되었습니다. IP : " + key);
			sessionsList.put(key, System.currentTimeMillis());
		} else {
			logger.info(key + " 가 로그인하였습니다.");
		}
		
		return pjp.proceed(new Object[] {locale, model, request, response});
	}
}

 

아래에 있는 코드는 HashMap을 통해 IP 세션을 만들고 IP 세션의 일정 시간이 지나면 새로운 세션으로 적용하는 코드입니다. @Aspect @Around 가 나오게 됩니다. AOP의 사용을 위해서 Aspect Annotation을 사용해야 하고, Around Annotation은 어떠한 메소드로 들어가기 전 후로 처리되는 것을 지원하기 위한 Annotation 입니다. 자세한 문법과 사용 방안은 다른 페이지를 참고해주세요...

 

수정할 곳은 @Around  입니다. 

여기서 @Around(value="execution(* com.mycom.myapp.*.*(..)) && args(locale, model, request, response)") 으로 적용하였습니다. execution 구문에는 적용할 폴더의 범위이고 args 구문에는 메소드의 파라미터가 들어가게 됩니다. 따라서 이렇게 들어온 메소드의 파라미터들을 사용할 수 있기 때문에 다음줄 beforeController의 파라미터가 바뀌게 되고 ProceedingJoinPoint 객체의 proceed 함수도 파라미터와 똑같이 적용해줘야 에러가 뜨지 않습니다.

 

2. 컨트롤러 수정

1번에서 사용할 메소드의 파라미터를 그대로 바꿔줘야 합니다. 그래서 아래와 같이 Home Controller에서의 지정된 메소드의 파라미터를 변경해주시기 바랍니다. 저는 아래와 같이 바꿔주었습니다.

 

 

 

3. Bean 생성

 config 폴더에 aop-config.xml을 생성하고 아래에 있는 코드를 붙여 넣겠습니다.

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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">

	<aop:aspectj-autoproxy/>
	<bean id="applicationAspect" class="com.mycom.myapp.common.ApplicationAspect"/>
	
</beans>

 

4. servlet-context.xml 수정

 servlet-context.xml 로 이동 합니다. 

 경로는 다음과 같습니다.

 

 

 그리고 아래 코드를 추가해주세요.

<beans:import resource="classpath:config/aop-config.xml"/>

 

5. 실행