코딩항해기
[Spring] 관점 지향 프로그래밍 AOP (xml) 본문
AOP 관점 지향 프로그래밍 Aspect Oriented Programming
Spring 프레임워크는 IoC와 AOP을 지원하는 경량의 프레임워크이다. 그 중 AOP는 관점 지향 프로그래밍을 의미하며, 횡단 관심사의 분리를 허용해 모듈성을 증가시키는 것이 목적인 프로그래밍 패러다임이다. 객체지향(OOP)의 단점(공통된 부가기능에 대한 코드가 중복, 반복되어 유지보수가 어렵다는 단점)을 해소하기 위해 등장했다.
이처럼 중복되는 횡단 기능을 분리해 모듈화하는 개념이다. 이 횡단 기능을 공통기능, 공통로직, 횡단관심 등이라고 부르기도 하며 종단 기능을 핵심기능, 핵심관심, 비즈니스 메서드, CRUD라고 부른다.
종단 기능은 biz의 common으로 빠지게 되며 Advice라고 한다. 이 Advice는 Service처럼 Autowired를 붙여 사용할 수도 있지만 Advice가 변경되면 유지보수가 어렵고, 비용이 발생하는 문제가 있다. (OOP의 단점)
이 한계를 AOP로 해결할 수 있다. Advice를 컨테이너에게 생성과 관리를 맡겨 Advice의 메서드(공통 로직)가 사용되야하는 때에 사용할 수 있도록 설정하는 방식이다. 마치 filter처럼 사용되는 형식이며 filter와는 다르지만 특정 단계에 끼어들어 해당 메서드를 거치게 한다는 점이 유사하다.
(요청이 들어오면 Filter -> Intercepter -> AOP -> Intercepter -> Filter 순으로 거치게 된다.)
AOP 용어
조인포인트(Joinpoint)
: 클라이언트가 호출하는 모든 비즈니스 메서드, 조인포인트 중에서 포인트컷되기 때문에 포인트컷의 후보로 생각할 수 있다.
포인트컷(Pointcut)
: 특정 조건에 의해 필터링된 조인포인트, 수많은 조인포인트 중에 특정 메서드에서만 횡단 공통기능을 수행시키기 위해서 사용한다.
어드바이스(Advice)
: 횡단 관심에 해당하는 공통 기능의 코드, 독립된 클래스의 메서드로 작성한다.
위빙(Weaving)
: 포인트컷으로 지정한 핵심 관심 메서드가 호출될 때, 어드바이스에 해당하는 횡단 관심 메서드가 삽입되는 과정을 의미한다. 이를 통해 비즈니스 메서드를 수정하지 않고도 횡단 관심에 해당하는 기능을 추가하거나 변경이 가능해진다.
애스팩트(Aspect)
: 포인트컷과 어드바이스의 결합이다. 어떤 포인트컷 메서드에 대해 어떤 어드바이스 메서드를 실행할지 결정한다.
AOP 생성
환경설정
AOP를 생성하기 전에 의존성을 주입해줘야 한다. maven 의존성 태그를 추가한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
추가한 dependency를 이해할 수 있도록 스키마를 추가한다. AOP는 biz에서 다룰 예정이므로, 이 스키마는 가장 먼저 실행되는 루트 컨테이너에 사용된다.
<?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">
</beans>
Advice
package com.koreait.app.biz.common;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
public class LogAdvice {
public void insertLog(){
log.info("AOP: 글이 DB에 등록되었습니다.");
}
}
등록
객체가 스프링 컨테이너에 등록되어있어야(bean) 관리 대상이 되기 때문에 사용할 Advice를 먼저 bean으로 등록한다.
<bean class="com.koreait.app.biz.common.LogAdvice" id="la"/>
해당 bean을 등록했다면 해당 bean을 활용해 AOP를 등록할 수 있다.
<aop:config>
<aop:pointcut expression="execution(* com.koreait.app.biz..*Impl.insert(..))" id="logPointcut" />
<!--설정-->
<aop:aspect ref="la">
<aop:after method="insertLog" pointcut-ref="logPointcut"/>
</aop:aspect>
</aop:config>
AOP 설정은 aop:config 태그 안에서 진행하게 되며, 먼저 사용할 메서드를 pointcut 정규식으로 지정한다.
정규식은 execution 안에 작성해야하며 execution(아웃풋 메서드명규칙 인풋) 형식으로 작성하게 된다. 이때 아웃풋을 *로하면 모든 반환타입을 의미하고 인풋을 (..)로 작성하면 모든 인풋타입을 의미한다. 현재 작성된 메서드명을 분석하면 아래처럼 된다.
com > koreait > app > biz > 모든 폴더 > Impl로 끝나는 모든 파일 안의 insert 메서드
AOP 대상 설정까지 마쳤으면 aop:aspect 태그 아래에서 언제 해당 메서드를 거칠 지 설정할 수 있다.
aop:aspect에서 ref는 Advice bean객체의 id를 작성하면 된다.
여러가지 타이밍을 설정할 수 있는데, 그 중 자주 사용되는 타입은 5가지 정도가 있다.
aop:after | 핵심관심 후에 |
aop:after-returning | 핵심관심 반환 후에 |
aop:after-throwing | 핵심관심 에러 발생 후에 |
aop:around | 핵심관심 전후로 |
aop:before | 핵심관심 전에 |
타이밍을 결정했으면 그 타이밍에 거칠 메서드와 핵심관심 대상 메서드의 id를 작성하면 된다.
이후 핵심관심 메서드를 사용해보면 정상적으로 로그가 뜨는 것을 확인할 수 있고, 핵심관심 메서드에는 관련된 설정이 없는 것을 확인할 수 있다.
코드흐름
완성된 AOP는 루트 컨테이너가 실행될 때 bean 객체로 등록되어 AOP 설정에 따라 실행된다. 이 때의 설정은 aop태그를 따르는데, 범위는 pointcut을 읽어들여 정하고, 실행 위치는 aspact안의 태그를 읽어 결정하게 된다.
설정이 완료되고 나면 범위에 해당하는 핵심관심이 호출될 때 aspact 안의 태그에 지정된 순서에 실행된다. 예를 들어 around라면 핵심관심이 시작될 때 AOP가 실행되고나서 핵심관심이 실행된다. 이후 핵심관심이 종료되면 다시 AOP가 실행되어 종단 기능을 처리한다.
AOP 장점
이처럼 AOP는 공통로직을 분리해 관리할 수 있어 응집도가 높아지며, Spring 프레임워크는 IoC도 지원하기 때문에 결합도를 낮출 수 있어 Spring 프레임워크는 유지보수에 용이하다.
참고 블로그 : https://sjh836.tistory.com/157
++ 어노테이션 AOP
'Spring' 카테고리의 다른 글
[Spring] AOP의 JoinPoint (0) | 2024.10.15 |
---|---|
[Spring] Filter, Interceptor, AOP (0) | 2024.10.15 |
[Spring] 비동기 Controller 구현 (ResponseBody, RequestBody, RestController) (0) | 2024.10.14 |
[Spring] Logback을 통한 로그 관리 기초 (@Slf4j) (0) | 2024.10.12 |
[Spring] 2-Layered Architecture (Service, ServiceImpl) (0) | 2024.10.10 |