코딩하는 문과생

[Spring] Spring 프레임워크(9) - AOP 본문

웹 프로그래밍/Spring

[Spring] Spring 프레임워크(9) - AOP

코딩하는 문과생 2020. 3. 12. 13:27

[AOP: Aspect Oriented Programming]

: 관심사의 분리(기능의 분리) - 핵심적인 기능에서 부가적인 기능(Aspect)을 분리

  • 핵심기능(Core Concerns): 업무 로직
  • 부가기능(Cross-cutting Concerns): 로깅, 보안

1. 런타임시 핵심기능과 부가기능이 결합되어 작동

2. Advice(부가기능 "자체") + PointCut(어디에 적용할 지에 대한 "문법") = Aspect = Advisor(Spring AOP)

3. Target = Core Concerns

4. JoinPoint: 어디에 "위치"해야할 지

5. 위빙(Weaving): 포인트컷에 의해서 결정된 타깃의 JoinPoint에 부가기능이 삽입되는 과정

 

- Spring AOP

  • Spring은 프록시 기반 AOP를 지원
  • 프록시가 호출을 가로챈다.
  • Spring AOP는 메서드 조인 포인트만 지원한다.

 

ex. AOP

- pom.xml에 의존성 추가

	<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-aop</artifactId>
	    <version>4.3.9.RELEASE</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
	<dependency>
	    <groupId>org.aspectj</groupId>
	    <artifactId>aspectjweaver</artifactId>
	    <version>1.8.10</version>
	</dependency>

- root-context.xml에 프록시 기반 aop추가

	<!-- AOP가 컨트롤러에는 적용되지 않는다. -->
	<aop:aspectj-autoproxy/>

- SampleAspect작성

package kr.co.acomp.hello.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class SampleAspect {
	//hello패키지내 모든 메소드
	@Before("execution(* kr.co.acomp.hello..*.*(..))")
	public void before(JoinPoint joinPoint) {
		String targetMethodName = joinPoint.getSignature().getName();
		System.out.println(targetMethodName+" is invoked...");
	}
	
}

Controller 적용 X
DAO 적용 O


[PointCut표현식과 Advisor 구현]

- AspectJ 포인트컷 표현식을 따른다

ex. "execution(* aspects.trace.demo.*.*(..))"

(..): 모든 종류의 파라미터 허용

(): 파라미터가 없는 메소드에만 적용하겠다.

 

- Spring AOP의 구현 방식

XML POJO 클래스를 이용

  • 트랜잭션 처리와 같이 구현되어 있는 부분을 사용할 경우
  • <aop:config>

 

@Aspect 어노테이션을 이용

  • 직접 부가기능을 구현할 경우
  • <aop:aspectj-autoproxy/>태그를 설정파일에 추가하면 @Aspect 어노테이션이 적용된 Bean을 Aspect로 사용 가능

 

-Advice의 종류

  • Around 어드바이스: JoinPoint가 앞과 뒤에서 실행되는 Advice - @Around("pointcut문법")
  • Before 어드바이스 - @Before("pointcut문법")
  • After Returning 어드바이스: JoinPoint 메서드 호출이 정상적으로 종료된 뒤에 실행되는 Advice - @AfterReturning("pointcut문법")

 

-JoinPoint 인터페이스

ex. getSignature(): 타겟 메서드의 정보 확인 가능

 

- ProceedingJoinPoint 인터페이스

JointPoint 인터페이스를 상속받는다.

Around 어드바이스와 사용된다.

ex. proceed(): 타겟 메서드를 실행시키는 메서드, 가령 타겟 메서드의 실행시간을 체크하는 기능을 예로 들 수 있다.

 

 

ex. 메소드 수행시간 확인 Aspect 생성

- MeasuringAspect 생성

package kr.co.acomp.hello.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MeasuringAspect {
	
	//서비스 메소드에만 적용해보자
	//Aspect = Advice + PointCut
	@Around("execution(* kr.co.acomp.hello.service.*Service.*(..))")
	public Object measuringMethodRunningTime(ProceedingJoinPoint joinPoint) throws Throwable {
		
		long start = System.currentTimeMillis();
		
		try {
			return joinPoint.proceed();
			//타겟 메서드를 실행시키는 함수
		}finally {
			//타겟 메서드를 실행시킨 이후 내용
			long result = System.currentTimeMillis() - start;
			String targetMethodName = joinPoint.getSignature().getName();
			System.out.println(targetMethodName + " running time is " + result);
		}
	}
	
}

- BbsService 추가

	public void testService() {
		System.out.println("target invoked..");
	}

- BbsController 추가

	@GetMapping("")
	public String index() {
		bbsService.testService();
		return "index";
	}

해당 url로 접근시
Aspect 작동