본문 바로가기

Programming/Framework

DAY 149. Spring AOP(Aspect Oridented Programming)

 

 

Spring AOP(Aspect Oridented Programming) 관점 지향 프로그래밍

 

- 일반적으로 사용하는 클래스(Service, Dao) 에서 중복되는 공통 코드 부분(commit, rollback, log, security 처리) 을 별도의 영역으로 분리하고

 

- 코드가 실행되기 전이나 이 후 시점에 해당 코드를 붙여 넣음으로써 소스 코드의 중복을 줄이고, 필요할 때마다 가져다 사용할 수 있게 객체화하는 기술

 

- 한 애플리케이션의 여러 서비스에 걸쳐져 있는 기능 (= Corss-cutting Concern : 횡단 관점, 횡단 관심사) 를 분리하는 기능이다.

 

- 궁극적으로 결합도를 낮추는 데 목적과 의의가 있다.

 

- 개발자는 서비스에 집중할 수 있도록 한다.

 

 

동작 구조 & 용어

 

▶ Aspect

* AOP는 횡단 관심사(한 애플리케이션 내의 여러 부분에서 공통으로 사용하고 있는 기능)를 Aspect라는 특별한 클래스로 모듈화해서 관리한다.

* Aspect는 Advice와 PointCut을 합친 것이다.

 

 

Aspect Advice
- Advice + PointCut
- 여러 객체에 공통적으로 적용되는 기능을 분리하여 작성한 클래스
- 공통 기능
- 횡단 관심사를 모듈화 한 것
- AOP의 기본 모듈
- 싱글톤 형태의 객체로 존재
- 여러 객체에서 공통적으로 적용되는 공통 관심 사항
→ 핵심 기능이 아닌 부수적 기능
(트랜잭션, 로깅, 보안, 인증 등)
- 부가 기능을 정의한 코드
- 그 안의 세부적인 주요 기능
- 실질적인 부가기능을 담은 구현체
- 부가기능을 담고 있는 모듈
- 적용할 Aspects가 무엇이고
언제 사용할 것인지 정의하는 것
- 언제 어떤 Aspect를 핵심 로직에 적용할지 정의한 것
- Aspect가 해야 할 작업

 

-> AOP 개념을 적용하면 핵심 기능 코드 사이에 끼어있는 부가기능을 독립적인 요소로 분리할 수 있고

부가기능 Aspect는 런타임 시에 필요한 위치에 동적으로 참여할 수 있다.

 

 Advice 

* Aspect가 해야하는 작업(공통적으로 사용하고 있는 기능)과 언제 그 작업을 수행해야 하는지 정의하는 것을 AOP 용어로 Advice라고 한다.

 

Advice 종류

01. Before Advice : Joinpoint 앞에서 실행

-> 타겟의 메소드가 실행되기 이전 시점에 처리해야 할 필요가 있는 부가 기능 정의

 

02. Around Advice : Joinpoint 앞과 뒤에서 실행

-> 타겟의 메소드가 호출되기 이전 시점과 이후 시점에 모두 처리해야 할 필요가 있는 부가 기능 정의

 

03. After Advice : Joinpoint 호출이 리턴되기 직전에 실행, Joinpoint와 상관없이 무조건 실행

 

04. After Returning Advice : Joinpoint 메소드 호출이 정상적으로 종료된 후에 실행

-> 타겟의 메소드가 정상적으로 실행된 이후 시점에 처리해야 할 필요가 있는 부가 기능 정의

 

05. After Throwing Advice : 예외가 발생했을 때 실행

-> 타겟의 메소드에 예외가 발생된 이후 시점에 처리해야 할 필요가 있는 부가 기능 정의

 

 

Joinpoint PointCut
- Aspect가 적용될 수 있는 모든 지점
- Advice를 실행하는 시점
- 객체(인스턴스) 생성 시점
- 메소드 호출 시점
- 예외 발생 시점 등 특정 작업이 시작되는 시점
- Advice를 어디에 적용하는지 결정하는 것
- JointPoint의 부분 집합
- 실제 Adivce가 적용되는 부분
- 여러 Jointpoint 중에서 실제 기능이 적용되어야 하는 것을 추린 것

 

 JointPoint

* Advice를 적용되는 모든 지점을 Joinpoint라고 한다.

* Joinpoint는 애플리케이션 실행에 공통적인 기능(Advice)을 끼워 넣을 수 있는 지점(Point)을 말한다. (ex. 메소드 호출 지점, 예외 발생 등)

▷ JointPoint Interface

- 모든 어드바이스org.aspectj.lang.JoinPoint 타입의 파라미터를 어드바이스 메소드의 첫 번째 매개 변수로 선언해야 한다.

- 단, Around 어드바이스는 JoinPoint의 하위 클래스인 ProceedingJoinPoint 타입의 파라미터를 필수적으로 선언해야 한다.

 

▷ JointPoint Interface 메소드

getArgs() 메소드의 매개 변수를 반환
getThis() 현재 사용 중인 프록시 객체를 반환
getTarget() 대상 객체를 반환
getSignature() 대상 객체 메소드의 설명(메소드 명, 리턴 타입 등)을 반환
toString() 대상 객체 메소드의 정보를 출력

 

 PointCut

* Advice가 적용될 Joinpoint의 영역을 좁히는 일을 한다.

* Advice는 Aspect가 해야하는 '작업''언제' 그 작업을 수행해야 하는지 정의하는 것이라면, PointCut'어디에' Advice를 적용할지 정의하는 것이다.

* Spring에서는 PointCut 지정하기 위해서 AspectJ PointCut 표현식을 통해서 지정할 수 있다.

 

더보기

 

[ Spring AOP 에서 지원되는 AspectJ 포인트 커트 표현식 ]


 *  execution([접근지정자] 리턴타입 [클래스이름].메소드명(파라미터)) : 메소드 실행에 대한 조인 포인트를 지정한다.
     -> 접근지정자 : public, private 등, 생략 가능
     -> 리턴타입  : 메소드의 반환값을 의미한다.
     -> 클래스이름 : 클래스의 풀 패키지명이 포함된 이름을 적어준다.
    " * "  : 메소드에서 리턴하는 타입의 모든 값을 표현한다.
    " .. " : 매개 값의 개수가 0개 이상을 의미한다.


 *   args(파라미터) : 타겟 메소드에 전달되는 파라미터 값을 Advice에 전달하기 위한 파라미터를 지정한다.


 *   bean(빈ID) : 포인트 커트 표현식 내에서 빈ID로 특정 빈을 지정할 수 있다.


 *   @annotation(어노테이션이름(풀패키지명)) : 주어진 어노테이션을 갖는 조인 포인트를 지정한다.

 

 

 Weaving(삽입)

- 그 시점에 공통 코드를 끼워 넣는 작업, Target 객체에 내가 작성한 Advice를 핵심 로직 코드에 삽입

- Target 객체에 Aspect를 적용해서 새로운 객체를 생성하는 과정

 

Weaving 종류

01. 컴파일 시 위빙 : 타겟 객체를 컴파일 시 AOP가 적용된 클래스 파일이 새로 생성(AspectJ)

02. 클래스 로딩 시 위빙 : JVM에서 로딩한 클래스의 바이트 코드를 AOP 가 변경하여 사용,  전용 클래스 로더가 필요

03. 런타임 시 위빙 : 클래스 정보 자체를 변경하지 않고, 애플리케이션이 실행될 때, 타겟 객체를 감싸는 프록시를 생성하여 경유(스프링)

 

 Proxy

- 대상 객체에 Advice가 적용된 후 생성되는 객체

 

Target Obejct

- Advice가 적용될 대상 객체, 실체 호출되는 것

 


 

특징

Spring은 프록시(Proxy) 기반 AOP를 지원한다.

Spring은 Target Object에 대한 프록시를 만들어 제공한다. (프록시 패턴 활용)

타겟을 감싸는 프록시는 서버 Runtime 시에 생성된다.

외부에서 대상 객체를 호출할 때 Proxy 객체가 먼저 호출되어 Advice의 로직을 처리한 후 대상 객체를 호출한다.

** Proxy : 대상 객체를 직접 접근하지 못하게 ‘대리인’ 으로서 요청을 대신 받는 기술

 

Proxy는 대상 객체의 호출을 가로챈다.

Proxy는 그 역할에 따라 대상 객체에 대한 호출을 가로챈 다음,

전처리 어드바이스 => Advice의 부가기능 로직을 수행하고 난 후 에 타겟의 핵심 기능 로직을 호출하거나

후처리 어드바이스 => 타겟의 핵심 기능 로직 메소드를 호출한 후에 Advice 부가 기능을 수행한다.

 

Spring AOP는 메소드 조인 포인트만 지원한다.

스프링은 동적 프록시를 기반으로 AOP를 구현하기 때문에 모든 조인포인트를 지원하는 것이 아니라,

메소드 조인포인트만 지원한다.

즉, 핵심 기능 (대상 객체)의 메소드가 호출되는 런타임 시점에만 부가기능(어드바이스)를 적용할 수 있다.

(cf. AspectJ 같은 고급 AOP 프레임워크를 사용하면 객체의 생성, 필드 값의 조회와 조작, static 메소드 호출 및 초기화 등 다양한 작업에 부가기능을 적용할 수 있다.)

 

 

더보기

1. Aspect 내용을 참고해서 실제 타겟 오브젝트를 감싸고 있는 Proxy 객체를 만든다.

2. 호출을하면 Proxy 객체가 받아서 quest를 호출하기 전에 전 내용 수행-> Object의 quest 수행 -> 후 수행

3. Proxy가 quest 메소드를 받은 것을 리턴한다.

 


 

구현 방식

✔️ xml 기반의 aop 네임 스페이스를 통한 AOP 구현

1. 부가 기능을 제공하는 Adivce 클래스를 작성

2. XML 설정 파일에 <aop:config> 이용해서 Asepct 설정 (어드바이스와 포인트 컷을 설정)

 

▶ Advice를 정의하는 태그

01. <aop:before> : 메소드 실행 전에 적용되는 어드바이스

02. <aop:roung> : 메소드 호출 이전, 이후, 예외 발생 등 모든 시점에 적용 가능한 어드바이스

03. <aop:after> : 메소드가 정상적 실행되는지 or 예외 발생하는지 여부에 상관없는 어드바이스

04. <aop:after-returning> : 메소드가 정상적 실행된 후에 적용되는 어드바이스

05. <aop:after-thorwing> : 메소드가 예외 발생시킬 때 적용되는 어드바이스 정의

 

✔️ @Aspect 어노테이션 기반의 AOP 구현

1. @Aspect 어노테이션을 이용해서 부가기능을 제공하는 Aspect 클래스 작성

(이 때, Aspect 클래스는 어드바이스를 구현하는 메소드와 포인트컷을 포함)

2. XML 설정 파일에 <aop:aspect-autoproxy /> 설정

 

▶ Advice를 정의하는 어노테이션

 

✔️ Java 기반의 AOP 구현

 

 


 

더보기

[실습 문제]


  Sword, Bow의 attack 메소드 실행 시, @Around 어드바이스를 사용하여 코드를 작성하세요.
  1. attack 메소드 정상 동작시, 
  공격을 준비 중입니다.
  "검을 휘두른다." or "민첩하게 활을 쏜다." 출력
  공격을 성공했습니다.
  2. attack 메소드 실행 중에 예외가 발생시,
  공격을 준비 중입니다.
  "에러가 발생하였습니다.."

 

01. 내가 작성한 코드 ㅠ_ㅠ

 

02. 정답 코드

- 일단 Sword 인 경우

 

- 모든 무기에 적용