코딩항해기

[Spring] 관점 지향 프로그래밍 AOP (@어노테이션) 본문

Spring

[Spring] 관점 지향 프로그래밍 AOP (@어노테이션)

miniBcake 2024. 10. 16. 11:02

 

 

 

[Spring] 관점 지향 프로그래밍 AOP (xml)

AOP 관점 지향 프로그래밍 Aspect Oriented ProgrammingSpring 프레임워크는 IoC와 AOP을 지원하는 경량의 프레임워크이다. 그 중 AOP는 관점 지향 프로그래밍을 의미하며, 횡단 관심사의 분리를 허용해 모듈

minibcake.tistory.com

 

xml 설정파일은 @어노테이션으로 대체 가능하므로 어노테이션으로 AOP 처리하는 법에 대해 정리한다.

 

AOP 어노테이션 종류 (@AspectJ 지원)

@Service (=@Component) Bean 등록 (핵심관심과 함께 관리하기 위해 Service)
@Aspect Aspect 표기
@Pointcut 포인트 컷 지정
@After 핵심관심 전에 해당 메서드 실행
@AfterReturning 핵심관심에서 반환값 발생 이후에 해당 메서드 실행
@AfterThrowing 핵심관심에서 에러 발생 이후에 해당 메서드 실행
@Before 핵심관심 이후로 해당 메서드 실행
@Around 핵심관심 전 후로 해당 메서드 실행

 

 

환경설정 (xml)

어노테이션을 사용할 때에는 해당 어노테이션들을 인식할 수 있도록 context:componet-scan을 통해 base-package를 지정해야한다. 또한 aop 사용 중이라는 것을 알려주기 위해 aop: aspectj-autoproxy 태그를 작성해야한다. aop태그를 사용하기 때문에 루트 앨리먼트는 xml방식과 동일하다. (루트 컨테이너 xml applicationContext.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:context="http://www.springframework.org/schema/context"
	   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-4.2.xsd
                  http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<!--어노테이션 인식범위 지정-->
	<context:component-scan base-package="com.koreait.app.biz.board" />
	<context:component-scan base-package="com.koreait.app.biz.member" />
	<context:component-scan base-package="com.koreait.app.biz.common" />

	<!--AOP를 사용 중이라는 것을 안내설정-->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

 

 

어노테이션 사용

@Service //bean 등록 
@Aspect //Aspect 안내
@Slf4j //(logback사용 AOP와 관계 없음)
public class LogAdvice {
    //포인트 컷 설정
    @Pointcut("execution(* com.koreait.app.biz..*Impl.selectOne(..))")
    public void dtoPointcut() {}; 참조 메서드
    
    //공통 기능 (반환된 후 실행)
    @AfterReturning(pointcut = "dtoPointcut()", returning = "dto")
    public void dtoLogger(Object dto) {
        String logMsg = null;
        if(dto instanceof BoardDTO) { //반환된 값이 게시글 DTO일때
            logMsg = "dto is BoardDTO: " + dto;
        }
        else if(dto instanceof MemberDTO) { //반환된 값이 멤버 DTO일때
            logMsg = "dto is MemberDTO: " + dto;
        }
        log.info("AOP log: {}",logMsg);
    }
}

 

기존 bean 태그가 @Service로 변경됐으며 이는 @Component로 작성해도 동일하다. 그러나 핵심관심이 Service 공간에 저장되고 공통기능은 핵심관심과 연관되므로 비슷한 공간에서 관리하기 위해 @Service어노테이션을 사용한다.

 

bean 등록을 마쳤다면 Pointcut 설정을 한다. Pointcut의 이름을 지정하기 위한 참조 메서드를 작성하고 해당 메서드 위에 Pointcut 어노테이션을 달아 기존 Pointcut 메서드 범위 설정을 작성한다.

 

Pointcut 설정을 완료했으면 실행할 공통 기능을 설정할 수 있다. 실행할 공통기능 메서드 위에 실행 조건을 담은 어노테이션을 작성하며 After Before와 같은 어노테이션은 설정이 pointcut 메서드명 지정 밖에 없으므로 pointcut= 안내 부분을 생략가능하지만, AfterReturning과 같은 경우는 returning 설정을 해야하므로 생략이 불가하다.

 

 

Pointcut 관리

이렇게 작성해도 정상 작동되지만 다른 Advice가 생기면 Pointcut을 재사용하더라도 다시 선언해야하는 불편함이 있고, Pointcut에 대한 응집도도 낮다.

 

이러한 문제를 해결하기 위해 별도의 클래스를 통해 Pointcut만 따로 관리할 수 있다. 이때 Pointcut 참조 메서드가 공통기능과 함께 있지 않으므로 앞에 클래스명을 명시해야한다.

@Service //bean 등록 
@Aspect //Aspect 안내
@Slf4j //(logback사용 AOP와 관계 없음)
public class LogAdvice {
    //공통 기능 (반환된 후 실행)
    @AfterReturning(pointcut = "PointcutCommon.dtoPointcut()", returning = "dto") //Pointcut 클래스명 명시
    public void dtoLogger(Object dto) {
        String logMsg = null;
        if(dto instanceof BoardDTO) { //반환된 값이 게시글 DTO일때
            logMsg = "dto is BoardDTO: " + dto;
        }
        else if(dto instanceof MemberDTO) { //반환된 값이 멤버 DTO일때
            logMsg = "dto is MemberDTO: " + dto;
        }
        log.info("AOP log: {}",logMsg);
    }
}

 

Pointcut을 관리하는 클래스는 참조 메서드만 가지고 있기 때문에 해당 클래스를 bean으로 등록해 관리할 필요는 없지만 Aspect라는 것은 명시해야한다.

@Aspect
public class PointcutCommon {
    @Pointcut("execution(* com.koreait.app.biz..*Impl.selectOne(..))")
    public void dtoPointcut() {}

    @Pointcut("execution(boolean com.koreait.app.biz..*Impl.*(..))")
    public void cudPointcut() {}
}

 

 

++++

 

[Spring] AOP @AfterThrowing

@AfterThrowing사용하면 예외가 발생해 비정상적으로 종료될 때 실행된다.이 때 어떤 예외가 발생했는지 알고 싶다면 throwing 속성을 사용할 수 있다. 다만 말 그대로 예외가 발생한 뒤 실행되기 때

minibcake.tistory.com

 

 

[Spring] AOP @Order 실행 우선 순위 설정

@Order동일한 조인포인트에 여러 개의 Advice가 지정된 경우, 여러 개의 AOP가 같은 시점에 동작하게 되는 중첩 AOP상태가 된다. 특히 Spring framework에서 정의한 AOP가 사용될 때 자연스럽게 중접 AOP가

minibcake.tistory.com