본문 바로가기
[ JAVA ]/JAVA Spring

[ Spring ] AOP 개념 및 설정

by 환이s 2023. 5. 24.


AOP(Aspect Oriented Programming)

 

AOP(Aspect Oriented Programming)란 풀 네임을 해석하면 관점 지향 프로그래밍으로, 핵심 로직과 부가 기능을 분리하여 애플리케이션 전체에 걸쳐 사용되는 부가 기능을 모듈화 하여 재사용할 수 있도록 지원해 줍니다.

 

여기서 모듈화공통된 로직이나 기능을 하나의 단위로 묶는 것을 의미하며, AOP를 간단하게 해석하기 위해 예를 들자면, 핵심적인 관점은 비즈니스 로직이 될 수 있고, 부가적인 관점은 핵심 로직을 실행하기 위해 행해지는 데이터베이스 연결, 로깅, 파일 입출력 등이 될 수 있습니다.

 

 

Aspect(측면, 관점, 관심)

 

Aspect는 부가기능을 정의한 코드인 Advice와 해당 Advice를 적용하는 걸 결정하는 PointCout을 합친 개념입니다.

 

AOP 개념을 적용하면 핵심 기능 코드 사이에 침투된 부가 기능을 독립적인 Aspect로 구분해 낼 수 있고, 구분된 부가기능 AspectRunTime 시에 필요한 위치에 동적으로 참여하게 할 수 있습니다.

 

간단하게 정리하면 다음과 같습니다.

 

핵심적인 비즈니스 로직은 아니지만 반드시 해야 하는 작업들

ex) 버스, 지하철로 출퇴근을 할 때 교통카드를 찍어야 함, 목적지에 정시에 도착하는 것이 중요하고 교통카드를 찍는 행위가 메인은 아님.

- 관심의 분리(Separation of Concerns)를 통해 핵심관점(업무로직) + 횡단관점(트랜 잭션, 로그, 보안, 인증 처리 등)으로 관심의 분리를 실현

-장점 : 중복되는 코드 제거, 효율적인 유지 보수, 높은 생산성, 재활용성 극대화, 변화 수용의 용이성

 

 

 

AOP 주요 용어

 

  • Aspect : 공통 관심사(로깅, 보안, 트랜잭션 등)
  • Join Points : Method를 호출하는 시점, 예외가 발생하는 시점 등과 같이 특정 작업이 실행되는 시점을 의미한다.
  • Advice : Join Points에서 실행되어야 하는 코드(실제로 AOP 기능을 구현한 객체)
  • Pointcuts : 실제로 Advice를 적용시킬 대상 method
  • Proxy : Advice가 적용되었을 때 만들어지는 객체

 

Advice의 종류

 

  • Before : target method 호출 전에 적용
  • After : target method 호출 후에 적용
  • Around : target method 호출 이전과 이후 모두 적용(가장 광범위하게 사용된다.)

ex ) 로그인 전/후의 각 페이지 처리 등


AOP 설정

 

Maven을 사용하시는 분들은 AOP 관련 라이브러리를 pom.xml 파일에 추가하셔야 합니다.

 

 

위 사진처럼 라이브러리를 설정하고 업데이트하시고, servlet-context.xml 파일에 aop 태그를 추가해 주면 됩니다.

 

 

AOP 설정은 예제용으로, 로깅 변수를 추가해서 해당 페이지 요청해서 view단까지의 로딩 시간을 콘솔창에 띄우려고 합니다.

 

package com.example.spring.aop;

import org.apache.catalina.tribes.util.Arrays;

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.stereotype.Component;

@Component //스프링에서 관리하는 범용 bean (참고:DAO에서 @Repository대신 적용가능)
@Aspect //공통적인 업무를 지원하는 aop bean
public class LogAdvice {
	//로깅을 위한 변수
	private static final Logger logger=LoggerFactory.getLogger(LogAdvice.class);
	
	//@Before(핵심업무 전), @After(핵심업무 후),  @Around(핵심업무 전,후 모두 사용)
	// ..은 모든 하위패키지를 의미, *(..)는 모든 메소드를 의미
	//@시점("범위" or "범위" or "범위"...)
	@Around("execution(* com.example.spring02.controller..*Controller.*(..))"
			+ " or execution(* com.example.spring02.service..*Impl.*(..))"
			+ " or execution(* com.example.spring02.model..dao.*Impl.*(..))")
	public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
		//핵심업무가 실행되는 시점에 수행할 메소드
		long start=System.currentTimeMillis();//시스템의 밀리세컨드값
		Object result=joinPoint.proceed();
		String type=joinPoint.getSignature().getDeclaringTypeName();
		String name="";
		if(type.indexOf("Controller") > -1) {
			name="Controller : "; //콘솔창에 Controller : 표시됨
		}else if(type.indexOf("Service") > -1) {
			name="ServiceImpl : ";
		}else if(type.indexOf("DAO") > -1) {
			name="DAOImpl : ";
		}
		//호출한 클래스, method 정보를 로거에 저장
		logger.info(name+type+"."+joinPoint.getSignature().getName()+"()");
		//메소드에 전달되는 매개변수들을 로거에 저장
		logger.info(Arrays.toString(joinPoint.getArgs()));
		long end=System.currentTimeMillis();
		long time=end-start;
		logger.info("실행시간 : " + time);
		return result;
	}
}

 


마치며

 

오늘은 AOP에 대해서 포스팅해보았습니다.

다음 포스팅에서 뵙겠습니다.

728x90