Spring 07 AOP(횡단 관심 코드, 핵심 관심 코드)

Kang.__.Mingu·2024년 9월 8일

Spring

목록 보기
6/21

Spring AOP(Aspect-oriented Programming)

Spring AOP는 핵심 비즈니스 로직과 보조적인 관심사를 분리하여 코드의 모듈성과 유지보수성을 높이기 위한 프로그래밍 패러다임이다. Spring AOP를 통해 핵심코드와 횡단 관심사를 분리함으로써 더 깨끗하고 이해하기 쉬운 코드를 작성할 수 있다.


Core Interest Codes(핵심 관심 코드)

  • 핵심 관심 코드는 애플리케이션의 주요 비즈니스 로직을 수행하는 코드이다. 애플리케이션의 본질적인 기능을 담당하는 코드로, AOP에서는 이 코드가 가능한 깔끔하게 유지되는 것이 목표이다.

예시: 주문을 처리하는 비즈니스 로직은 핵심 관심 코드이다.

public class OrderService {
    public void processOrder() {
        // 주문 처리 로직
        System.out.println("Processing order...");
    }
}

Cross-Cutting Interest Codes(횡단 관심 코드)

  • 횡단 관심 코드는 여러 모듈에서 공통으로 적용되는 부가적인 기능을 의미한다. 예를 들어 로깅, 보안 검사, 트랜잭션 관리 등이 해당된다.

  • 횡단 관심사는 여러 핵심 관심 코드에 걸쳐서 반복적으로 나타날 수 있고, 코드 중복과 복잡성을 증가시킨다.

예시: 주문 처리 전후로 로깅을 하는 기능은 횡단 관심 코드입니다. 이 코드가 주문 처리뿐 아니라 다른 비즈니스 로직에도 필요할 수 있습니다.

@Aspect
@Component
public class LoggingAspect {

    // OrderService의 모든 메서드 실행 전에 로깅
    @Before("execution(* com.example.OrderService.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Logging before: " + joinPoint.getSignature().getName());
    }

    // OrderService의 모든 메서드 실행 후에 로깅
    @After("execution(* com.example.OrderService.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("Logging after: " + joinPoint.getSignature().getName());
    }
}

Spring AOP의 장점

  1. 코드 중복 감소: 공통적으로 적용되는 횡단 관심사를 한 곳에 모듈화하여 코드 중복을 줄일 수 있다.

  2. 유지보수성 향상: 핵심 비즈니스 로직과 부가적인 기능을 분리되어 있어, 코드 수정이 더 쉬워진다.

  3. 모듈화: 비즈니스 로직과 횡단 관심사가 분리되어 있어 각각을 독립적으로 관리하고 테스트할 수 있다.


Spring AOP 기능 사용하기

  • Spring AOP 기능을 사용하기 위해서는 AspectJ Runtime, AspectJ Weaver 라이브러리가 프로젝트에 빌드 처리되어 있어야된다. 메이븐 - pom.xml

  • Spring AOP 기능을 구현하기 위해 Spring Bean Configuration File(XML) 파일의 엘리먼트를 사용하거나 AOP 관련 어노테이션을 사용해 환경 설정 해줘야한다.

  • 사용하기 위해서는 spring-aop.xsd 파일을 제공받도록 설정해야한다.

Spring AOP 엘리먼트

  • config: Spring AOP 기능을 구현하기 위한 정보를 제공하기 위한 엘리먼트

    • 하위 엘리먼트: advisor 엘리먼트, aspect 엘리먼트, pointcut 엘리먼트
<aop:config>
	<하위 엘리먼트>
</aop:config>
  • aspect: 핵심관심코드에 횡단관심코드를 원하는 위치에 삽입하여 실행되도록 설정하기 위한 엘리먼트

    • 횡단관심코드가 삽입될 위치(JoinPoint)를 하위 엘리먼트로 설정
    • 하위 엘리먼트: before 엘리먼트, after-returning 엘리먼트, after-throwing 엘리먼트, after 엘리먼트, around 엘리먼트
    • ref 속성: 회단관심모듈(Advice 클래스)의 식별자(beanName)을 속성값으로 설정
      => 횡단관심코드의 메소드를 호출하기 위한 객체를 제공받아 사용
<aop:config>
  <aop:aspect ref="hewonAdvice">
      <하위 엘리먼트>
  </aop:aspect>
</aop:config>
  • before: 타겟 메소드의 명령(핵심관심코드) 실행 전 횡단관심코드를 삽입해 실행되도록 설정하기 위한 엘리먼트

  • method 속성: 횡단관심모듈(Advice 클래스)의 메소드을 속성값으로 설정

  • pointcut 속성: 핵심관심모듈로 등록된 Spring Bean의 메소드 중 횡단관심코드가 삽입될 타겟메소드를 지정하기 위한 Pointcut 표현식을 속성값으로 설정

    • Pointcut 표현식: Pointcut 언어를 사용해 클래스에 작성된 메소드 중 타겟메소드를 지정하기 위한 표현방법
    • Pointcut 표현식: execution 제한자, within 제한자, bean 제한자연산자를 사용해 타겟메소드가 지정되도록 설정 - 제한자에서는 패턴문자를 사용해 타겟메소드 설정 가능
    • 제한자에서 사용할 수 있는 패턴문자: ..(0개 이상), *(1개 이상), ?(0개 또는 1개)
    • Pointcut 표현식의 연산자: !(not), &&(and), ||(or)

execution 제한자를 사용해 타겟 메소드를 지정하는 방법

=> execution 제한자는 메소드의 머릿부를 사용해 타겟메소드 지정

형식) execution([접근제한자] 반환형 [패키지명.클래스명.]메소드명(자료형,자료형,...))

  • [패키지.클래스명]를 생략하면 Spring Bean으로 등록된 모든 클래스(핵심관심모듈)의 메소드를 대상으로 타겟메소드 지정
  • 클래스 대신 인터페이스를 사용하면 인터페이스를 상속받은 모든 자식클래스의 메소드를 대상으로 타겟메소드 지정
<!-- 반환형 또는 매개변수의 자료형이 클래스(인터페이스)인 경우 패키지를 포함하여 표현 -->			
<aop:before method="beforeLog" pointcut="execution(void addHewon(xyz.itwill06.aop.Hewon))"/>

<!-- Spring Bean으로 등록된 모든 클래스의 메소드를 타겟메소드로 지정 -->
<aop:before method="beforeLog" pointcut="execution(* *(..))"/>
			
<!-- Spring Bean으로 등록된 모든 클래스에서 매개변수가 1개 이상 작성된 메소드를 타겟메소드로 지정 -->
<aop:before method="beforeLog" pointcut="execution(* *(*))"/>

<!-- Spring Bean으로 등록된 클래스 중 특정 패키지(하위 패키지 미포함)에 작성된 클래스의 메소드를 대상으로 타겟메소드 지정 -->
<aop:before method="beforeLog" pointcut="execution(* xyz.itwill06.aop.*(..))"/>

<!-- Spring Bean으로 등록된 클래스 중 특정 패키지(하위 패키지 포함)에 작성된 클래스의 메소드를 대상으로 타겟메소드 지정 -->
<aop:before method="beforeLog" pointcut="execution(* xyz.itwill06.aop..*(..))"/>

<!-- Spring Bean으로 등록된 클래스 중 특정 클래스의 메소드를 대상으로 타겟메소드 지정 -->
<aop:before method="beforeLog" pointcut="execution(* xyz.itwill06.aop.HewonDAOImpl.*(..))"/>

<!-- Spring Bean으로 등록된 클래스 중 인터페이스를 상속받은 자식클래스의 메소드를 대상으로 타겟메소드 지정 -->
<aop:before method="beforeLog" pointcut="execution(* xyz.itwill06.aop.HewonDAO.*(..))"/>
<aop:before method="beforeLog" pointcut="execution(* xyz.itwill06.aop.Hewon*.*(..))"/>
<aop:before method="beforeLog" pointcut="execution(* get*(..))"/>
<aop:before method="beforeLog" pointcut="!execution(* get*(..))"/>
<aop:before method="beforeLog" pointcut="execution(* *(int)) or execution(int *(..))"/>

within 제한자를 사용해 타겟 메소드를 지정하는 방법

=> Spring Bean으로 등록된 클래스의 모든 메소드를 타겟메소드 지정

형식) within(패키지명.클래스명)

=> within 제한자에 패턴문자를 사용할 수 있지만 클래스 대신 인터페이스 사용 불가능

<aop:before method="beforeLog" pointcut="within(xyz.itwill06.aop.HewonDAOImpl)"/>
<aop:before method="beforeLog" pointcut="within(xyz.itwill06.aop.*)"/>

bean 제한자를 사용해 타겟 메소드를 지정하는 방법

  • Spring Bean으로 등록된 클래스의 모든 메소드를 타겟메소드 지정

  • within 제한자는 클래스명으로 타겟메소드를 지정하지만 bean 제한자는 클래스의 식별자(beanName)를 사용해 타겟메소드 지정

    형식) bean(beanName)

<aop:before method="beforeLog" pointcut="bean(hewonDAO)"/>
<aop:before method="beforeLog" pointcut="bean(hewonService*)"/>
  • pointcut: Spring Bean으로 등록된 클래스(핵심관심모듈)의 메소드 중 회단관심코드가 삽입될 타겟메소드 정보를 설정하기 위한 엘리먼트
    => 자주 사용되는 Pointcut 표현식을 저장하여 aspect 엘리먼트의 하위 엘리먼트에게 제공하기 위해 사용

    • expression 속성: 타겟메소드를 지정하기 위한 Pointcut 표현식을 속성값으로 설정
    • id 속성: pointcut 엘리먼트를 구분하기 위한 식별자를 속성값으로 설정
<aop:pointcut expression="execution(* xyz.itwill06.aop.HewonDAO.*(..))" id="hewonDAOPointcut"/>			
<aop:pointcut expression="execution(* xyz.itwill06.aop.HewonService.*(..))" id="hewonServicePointcut"/>
  • pointcut-ref 속성: pointcut 엘리먼트의 식별자(id 속성값)를 속성값으로 설정
    =>pointcut 엘리먼트로 제공된 정보를 사용해 타겟메소드 지정
<aop:before method="beforeLog" pointcut-ref="hewonDAOPointcut"/>
<aop:before method="beforeLog" pointcut-ref="hewonServicePointcut"/>
  • after-returning: 타겟 메소드의 명령(핵심관심코드)이 예외 없이 정상적으로 실행된 후에 횡단관심코드를 삽입해 실행되도록 설정하기 위한 엘리먼트
<aop:after-returning method="afterReturningLog" pointcut-ref="hewonServicePointcut"/>			
  • after-throwing: 타겟 메소드의 명령(핵심관심코드) 실행시 예외가 발생된 후에 횡단관심코드를 삽입해 실행되도록 설정하기 위한 엘리먼트
<aop:after-throwing method="afterThrowingLog" pointcut-ref="hewonServicePointcut"/>
  • after: 타겟 메소드의 명령(핵심관심코드)이 실행된 후 무조건 횡단관심코드를 삽입해 실행되도록 설정하기 위한 엘리먼트
<aop:after method="afterLog" pointcut-ref="hewonServicePointcut"/>
  • around: 타겟 메소드의 명령(핵심관심코드) 실행 전과 후에 횡단관심코드를 삽입해 실행되도록 설정하기 위한 엘리먼트
<aop:around method="aroundLog" pointcut-ref="hewonServicePointcut"/>	

횡단관심모듈


→ Hewon(클래스)
→ HewonDAO(인터페이스)
→ HewonDAOImpl(클래스)
→ HewonService(인터페이스)
→ HewonServiceImpl(클래스)
→ HewonApp(클래스)

→ HewonAdvice

JoinPoint 인터페이스

JoinPoint 인터페이스는 Spring AOP에서 매우 중요하며, 주로 횡단 관심 코드를 구현할 때 사용된다.
JoinPoint는 Aspect가 적용될 수 있는 지점(예: 메서드 호출, 객체 생성 등)을 나타내며, 현재 실행 중인 메서드, 대상 객체, 인수 등을 제공하는 메서드들을 포함하고 있다.

JoinPoint 메서드

JoinPoint 인터페이스는 AOP Advice에서 실행 지점에 대한 다양한 정보를 제공하는 메서드를 포함하고 있다.

  1. getArgs()

    • 호출된 메서드의 인수(arguments)를 배열 형태로 반환한다.
    • 메서드 호출 시 전달된 파라미터를 확인하거나 로그로 남길 때 사용한다
  2. getTarget()

    • 현재 실행되는 대상 객체를 반환한다.
    • 어떤 객체에서 메서드가 호출되었는지를 알 수 있다.
  3. getSignature()
    - 현재 실행 중인 조인포인트의 메서드 시그니처(Signature) 정보를 반환한다. 시그니처는 메서드의 이름, 반환 타입, 파라미터 타입 등을 포함한다.
    → JoinPointBean(클래스)
    → JoinPointApp(클래스)
    → JoinPointAdvice(클래스)

profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글