TIL_Java Spring the Modern Way_8

-·2021년 3월 7일
0

Spring AOP(Aspect Oriented Programming)

관점 지향 프로그래밍이라고 한다.

비즈니즈로직을 수행하기 위한 여러 모듈들

ex) 데이터베이스 연결, 로깅, 파일 입출력 등

이런게 비즈니스로직마다 따로 박혀있으면 생산성, 유지보수측면에서 너무 안좋다.

뭐하나 바뀔때마다 가서 하나하나 다 바꿔줘야됨

그래서 이걸 비즈니스 로직에서 분리해서 재사용가능하게 모듈화를 하겠다는게 AOP의 목적

AOP 주요 개념

  • Aspect : 위에서 설명한 흩어진 관심사를 모듈화 한 것. 주로 부가기능을 모듈화함.
  • Target : Aspect를 적용하는 곳 (클래스, 메서드 .. )
  • Advice : 실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
  • JointPoint : Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능
  • PointCut : JointPoint의 상세한 스펙을 정의한 것. 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음

Spring AOP 적용

pom.xml
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Before
@Aspect // aspect라는걸 명시
@Configuration // bean으로 등록
public class UseAccessAspect {	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
    // What kind of method calls I would intercept
	// execution(* PACKAGE.*.*(..))
	// Weaving & Weaver
    // joinpoint 에 들어오는 시점 실행전에 수행
    @Before("com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.dataLayerExecution()")
	public void before(JoinPoint joinpoint) {
        //Advice
		logger.info("Check for user access");
		logger.info("Allowed execution for - {}", joinpoint);
	}
}
@After관련
@Aspect
@Configuration
public class AfterAopAspect {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	// return 되는 객체 가로챔, 실행이 성공적으로 완료될때만 실행
	@AfterReturning(value = "com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.businessLayerExecution()",
			returning = "result")
	public void afterReturning(JoinPoint joinpoint, Object result) {
		logger.info("{} return with value {}", joinpoint, result);
	}
    // 예외 발생시에 실행, Exception객체를 해놨으므로 지금은 모든예외 다 적용
	@AfterThrowing(value = "com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.businessLayerExecution()",
			throwing = "exception")
	public void afterThrowing(JoinPoint joinpoint, Exception exception) {
		logger.info("{} return with value {}", joinpoint, exception);
	}
    // 그냥 joinpoing후에 실행
	@After(value = "com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.businessLayerExecution()")
	public void after(JoinPoint joinpoint) {
		logger.info("after execution of {}", joinpoint);
	}
}
@Around
@Aspect
@Configuration
public class MethodExecutionAspect {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Around("com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.trackTimeAnnotation()")
	public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		// 실행전에 하는거
		long startTime = System.currentTimeMillis();
		// 분기점, 이게 내가 지정한 메서드가 실행되는 시점
		proceedingJoinPoint.proceed();
		// 실행후에 하는거
		long timeTaken = System.currentTimeMillis() - startTime;
		logger.info("Time Taken by {} is {}", proceedingJoinPoint, timeTaken);
	}
}
관련 어노테이션 정리

@Before (이전) : 어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행

@After (이후) : 타겟 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 어드바이스 기능을 수행

@AfterReturning (정상적 반환 이후)타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행

@AfterThrowing (예외 발생 이후) : 타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행

@Around (메소드 실행 전후) : 어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행

pointcut 관리
public class CommonJoinPointConfig {
    // 기본적인 사용법
	@Pointcut("execution(* com.in28minutes.spring.aop.springaop.data.*.*(..))")
	public void dataLayerExecution() {}
	
	@Pointcut("execution(* com.in28minutes.spring.aop.springaop.business.*.*(..))")
	public void businessLayerExecution() {}
    
	// 2개를 묶어서 지정가능
	@Pointcut("com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.dataLayerExecution() "
			+ "&& com.in28minutes.spring.aop.springaop.aspect.CommonJoinPointConfig.businessLayerExecution()")
	public void allLayerExecution() {}
    
	// name에 dao가 포함되는것들
	@Pointcut("bean(*dao*)")
	public void beanContainingDao() {}
    
	// 특정 패키지 제외
	@Pointcut("within(*com.in28minutes.spring.aop.springaop.data..*)")
	public void dataLayerExecutionWithWithin() {}
    
	// 특정 어노테이션이 있는 것들
	@Pointcut("@annotation(com.in28minutes.spring.aop.springaop.aspect.TrackTime)")
	public void trackTimeAnnotation() {}
}

이런게 없으면 특정 pointcut을 바꾸고 싶다하면 어노테이션을 적용한 모든 메서드에 가서 일일히 바꿔줘야되지만

common class 같은거 하나 만들어놓으면 변경사항이 있다면 여기만 바꿔주면 일괄수정가능 관리가 아주쉽다.

profile
거북이는 오늘도 걷는다

0개의 댓글