λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Backend/Spring Framework

[Spring]Spring AOP κ°œλ… 및 ν™œμš© 방법

by sukii 2024. 6. 25.
λ°˜μ‘ν˜•

πŸ€”Spring AOP(Aspect Oriented Programming - 관점 μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ°) λž€?

: AspectJ μ»΄νŒŒμΌλŸ¬μ— μ˜ν•΄ ν”„λ‘œκ·Έλž¨ μ‹€ν–‰μ‹œ ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œμ™€ νš‘λ‹¨κ΄€μ‹¬μ½”λ“œκ°€ κ²°ν•©(Weaving)λ˜μ–΄ μ‹€ν–‰λ˜λŠ” κΈ°λŠ₯ 제곡

1) OOP보닀 AOPκ°€ 쒋은 점?

OOP의 경우 λͺ¨λ“ˆν™”(μΊ‘μŠν™”)κ°€ λ„ˆλ¬΄ κ°•λ ₯ν•΄μ„œ ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œμ™€ νš‘λ‹¨κ΄€μ‹¬μ½”λ“œλ₯Ό λΆ„λ¦¬ν•˜μ—¬ ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜κΈ° 어렀움
=> μ½”λ“œμ˜ 쀑볡성이 λ†’μ•„ ν”„λ‘œκ·Έλž¨μ˜ 생산성 및 μœ μ§€λ³΄μˆ˜μ˜ νš¨μœ¨μ„± κ°μ†Œ

μ΄λŸ¬ν•œ 뢀뢄을 AOPλŠ” ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œμ™€ νš‘λ‹¨κ΄€μ‹¬μ½”λ“œλ₯Ό λΆ„λ¦¬ν•œ ν›„, 결합이 ν•„μš”ν•œ λΆ€λΆ„μ—μ„œλ§Œ κ²°ν•©ν•˜μ—¬ 싀행될 수 μžˆλ„λ‘ν•˜μ—¬ ν•΄κ²°ν•΄μ€Œ!

2) Spring AOP κΈ°λŠ₯을 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ 2개의 라이브러리 λΉŒλ“œ 처리 ν•„μš”

μ„œλŠ” aspectjrt λΌμ΄λΈŒλŸ¬λ¦¬μ™€ aspectjweaver λΌμ΄λΈŒλŸ¬λ¦¬κ°€ ν”„λ‘œμ νŠΈμ— λΉŒλ“œ 처리 - 메이븐 μ‚¬μš©

=> μ•„λž˜ μ‚¬μ΄νŠΈμ—μ„œ μœ„ λ‘κ°œμ˜ 라이브러리 파일 μ°Ύμ•„μ„œ pom.xml νŒŒμΌμ— λΉŒλ“œμ²˜λ¦¬ν•˜λ©΄ 됨

https://mvnrepository.com/ 

그런데 aspectjrtλŠ” 이미 λΉŒλ“œμ²˜λ¦¬ λ˜μ–΄ 있음. Spring이 자체적으둜 μ‚¬μš©ν•œλ‹€κ³  함. aspectjweaver 라이브러리만 검색! 

pom.xml νŒŒμΌμ— μ•„λž˜ μ½”λ“œ λΆ™μ—¬ λ„£μœΌλ©΄ 그것이 λ°”λ‘œ λΉŒλ“œ 처리! 

<!--이건 이미 λΉŒλ“œ 처리 λ˜μ–΄ μžˆμ—ˆμŒ -->		
        <!-- AspectJ - Spring AOP κΈ°λŠ₯을 μ œκ³΅ν•˜κΈ° μœ„ν•œ 라이브러리 -->
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
		<!-- => AspectJ μ»΄νŒŒμΌλŸ¬μ— μ˜ν•΄ μƒμ„±λœ Proxy 클래슀의 μ‹€ν–‰ 관리 κΈ°λŠ₯을 μ œκ³΅ν•˜κΈ° μœ„ν•œ 라이브러리 -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>
		
<!--이거만 ν•˜λ©΄ 됨 -->	        
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<!-- => AspectJ 컴파일러둜 ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œμ™€ νš‘λ‹¨κ΄€μ‹¬μ½”λ“œκ°€ κ²°ν•©λœ 클래슀(Proxy 클래슀)λ₯Ό
		μƒμ„±ν•˜λŠ” Weaving κΈ°λŠ₯을 μ œκ³΅ν•˜κΈ° μœ„ν•œ 라이브러리 -->
		<dependency>
		    <groupId>org.aspectj</groupId>
		    <artifactId>aspectjweaver</artifactId>
		    <version>${org.aspectj-version}</version>
		    <scope>runtime</scope>
		</dependency>

 

3) Spring AOP을 κ΅¬ν˜„(2κ°€μ§€ 방법 있음)

- Spring Bean Configuration File(XML) 파일의 μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μ‚¬μš©ν•˜μ—¬ ν™˜κ²½ μ„€μ •

or

- AOP κ΄€λ ¨ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜μ—¬ μ„€μ •

 

βš«μœ„ 두 κ°€μ§€ 방법은 μ•„λž˜ λΈ”λ‘œκ·Έ μ°Έκ³  ! 

  https://kgvovc.tistory.com/53

 

[Spring Core] AOP(Aspect Oriented Programming) - 2편(Advice μ •μ˜, @Before, @AfterReturning, @AfterThrowing, @After, @Around)

AOP - 2편 (Advice μ •μ˜) [μžλ°” 기반 μ„€μ • λ°©μ‹μ—μ„œμ˜ Advice μ •μ˜] μ•žμ„œ μŠ€ν”„λ§ AOPμ—μ„œ ν™œμš© κ°€λŠ₯ν•œ Advice둜 λ‹€μ„― κ°€μ§€ μ’…λ₯˜κ°€ μžˆλ‹€κ³  ν–ˆλ‹€. 이제 각각의 κ΅¬ν˜„ 방식을 예λ₯Ό λ“€μ–΄ μ‚΄νŽ΄λ³΄μž. Before 이미 μ•ž

kgvovc.tistory.com

 

 

cf)

*ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œ: ν”„λ‘œκ·Έλž¨ μ‹€ν–‰μ— ν•΅μ‹¬μ μΈ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” λͺ…λ Ή - λ°μ΄νƒ€ μ²˜λ¦¬ λͺ…λ Ή

*νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ: ν”„λ‘œκ·Έλž¨ 싀행에 보쑰적인 κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” λͺ…λ Ή - 둜그 μ²˜λ¦¬, κΆŒν•œ μ²˜λ¦¬, νŠΈλ Œμ μ…˜ μ²˜λ¦¬, μ˜ˆμ™Έ μ²˜λ¦¬ λ“±

 

 


 

 

πŸ‘©‍πŸ’»μ‹€μŠ΅ μ½”λ“œ

1) ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œ(데이터 처리λ₯Ό λͺ…λ Ήν•˜λŠ” λ©”μ†Œλ“œ)λ₯Ό μž‘μ„±ν•œ JoinPointBean 클래슀

package xyz.itwill06.aop;

//핡심관심λͺ¨λ“ˆ
public class JoinPointBean {
	public void add() {
		System.out.println("*** JoinPointBean 클래슀의 add() λ©”μ†Œλ“œ 호좜 ***");
	}
	
	public void modify(int num, String name) {
		System.out.println("*** JoinPointBean 클래슀의 modify(int num, String name) λ©”μ†Œλ“œ 호좜 ***");
	}
	
	public void remove(int num) {
		System.out.println("*** JoinPointBean 클래슀의 remove(int num) λ©”μ†Œλ“œ 호좜 ***");
	}
	
	public String getName() {
		System.out.println("*** JoinPointBean 클래슀의 getName() λ©”μ†Œλ“œ 호좜 ***");
		return "홍길동";
	}
	
	public void calc(int num1, int num2) {
		System.out.println("*** JoinPointBean 클래슀의 calc(int num1, int num2) λ©”μ†Œλ“œ 호좜 ***");
		System.out.println("λͺ« = "+(num1/num2));
	}
}

 

2) νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ(데이터 처리 λͺ…령을 μ œμ™Έν•œ 보쑰적인 κΈ°λŠ₯을 λͺ…λ Ήν•˜λŠ” λ©”μ†Œλ“œ)λ₯Ό μž‘μ„±ν•œ JoinPointAdvice 클래슀

=> νš‘λ‹¨κ΄€μ‹¬μ½”λ“œλ₯Ό μž‘μ„±ν•œ 클래슀λ₯Ό Advice 클래슀라고 λΆ€λ₯Έλ‹€

 

<μ£Όμš” ν‚€μ›Œλ“œ ν™•μΈν•˜κ³  μ•„λž˜ μ‹€μŠ΅μ½”λ“œ ν™•μΈν•˜κΈ° ! > 

 

νƒ€κ²Ÿ λ©”μ†Œλ“œ(Target Method) : 핡심관심λͺ¨λ“ˆ(=μœ„μ˜ 1번 클래슀)의 λ©”μ†Œλ“œ 쀑 PointCut μ–Έμ–΄λ‘œ μ§€μ •λ˜μ–΄ νš‘λ‹¨κ΄€μ‹¬μ½”λ“œκ°€ μ‚½μž…λΌ 싀행될 λ©”μ†Œλ“œ

=> PointCut μ–Έμ–΄ : 핡심관심λͺ¨λ“ˆμ˜ λ©”μ†Œλ“œ 쀑 νŠΉμ • λ©”μ†Œλ“œλ§Œμ„ μ§€μ •ν•˜κΈ° μœ„ν•œ μ–Έμ–΄

 

Before Advice Method : νƒ€κ²Ÿ λ©”μ†Œλ“œμ˜ λͺ…λ Ή 싀행전에 μ‚½μž…λ˜μ–΄ 싀행될 λͺ…령을 μž‘μ„±ν•œ λ©”μ†Œλ“œ 

=> JoinPoint : ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œλ₯Ό κΈ°μ€€μœΌλ‘œ νš‘λ‹¨κ΄€μ‹¬μ½”λ“œκ°€ μ‚½μž…λ˜μ–΄ 싀행될 μœ„μΉ˜

=> Around Advice Methodλ₯Ό μ œμ™Έν•œ λ‚˜λ¨Έμ§€ Advice MethodλŠ” 일반적으둜 λ°˜ν™˜ν˜•μ„ [void]둜 μž‘μ„±ν•˜κ³  λ§€κ°œλ³€μˆ˜λ₯Ό μž‘μ„±ν•˜μ§€ μ•Šκ±°λ‚˜ JoinPoint μΈν„°νŽ˜μ΄μŠ€λ₯Ό μžλ£Œν˜•μœΌλ‘œ μ‚¬μš©ν•˜λŠ” λ§€κ°œλ³€μˆ˜ μž‘μ„± κ°€λŠ₯
=> Advice 클래슀의 λ©”μ†Œλ“œλ₯Ό κ·œμΉ™μ— λ§žμ§€ μ•Šκ²Œ μž‘μ„±ν•œ 경우 IllegalArgumentException λ°œμƒ

 

JoinPoint 객체 : νƒ€κ²Ÿλ©”μ†Œλ“œ κ΄€λ ¨ 정보가 μ €μž₯된 객체
=> AspectJ μ»΄νŒŒμΌλŸ¬μ— μ˜ν•΄ Advice 클래슀의 λ©”μ†Œλ“œκ°€ 호좜될 λ•Œ νƒ€κ²Ÿλ©”μ†Œλ“œ κ΄€λ ¨ 정보λ₯Ό μ €μž₯ν•œ JoinPoint 객체λ₯Ό λ§€κ°œλ³€μˆ˜μ— μ „λ‹¬ν•˜μ—¬ μ €μž₯
=> Advice 클래슀의 λ©”μ†Œλ“œμ—μ„œ νƒ€κ²Ÿλ©”μ†Œλ“œ κ΄€λ ¨ 정보가 ν•„μš”ν•œ 경우 λ§€κ°œλ³€μˆ˜λ₯Ό μ„ μ–Έν•˜μ—¬ JoinPoint 객체λ₯Ό 전달받아 JoinPoint 객체의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ‚¬μš© κ°€λŠ₯

 

JoinPoint.getTarget() : νƒ€κ²Ÿλ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•œ 객체(핡심관심λͺ¨λ“ˆ - Spring Bean)λ₯Ό λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ
=> Object νƒ€μž…μ˜ 객체 λ°˜ν™˜
Object.getClass() : 객체λ₯Ό μƒμ„±ν•œ 클래슀의 Class 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ
Class.getName() : Class 객체의 클래슀(νŒ¨ν‚€μ§€ 포함)λ₯Ό λ¬Έμžμ—΄λ‘œ λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ 
System.out.println(joinPoint.getTarget().getClass().getName());
Class.getSimpleName() : Class 객체의 클래슀(νŒ¨ν‚€μ§€ 미포함)λ₯Ό λ¬Έμžμ—΄λ‘œ λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ 
System.out.println(joinPoint.getTarget().getClass().getSimpleName());
JoinPoint.getSignature() : νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ 정보가 μ €μž₯된 Signature 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ
Signature.getName() : νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ 이름을 λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ
System.out.println(joinPoint.getSignature().getName());
JoinPoint.getArgs() : νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜μ— μ €μž₯된 λͺ¨λ“  κ°’(객체)을 Object λ°°μ—΄λ‘œ λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ
System.out.println(joinPoint.getArgs());

 

 

<μŠ€ν”„λ§.AOPμ—μ„œ ν™œμš© κ°€λŠ₯ν•œ 5κ°€μ§€ μ’…λ₯˜μ˜ Adivce 클래슀>

 

1) Before Advice Method

package xyz.itwill06.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

//νš‘λ‹¨κ΄€μ‹¬λͺ¨λ“ˆ
public class JoinPointAdvice {
	
	public void beforeDisplay(JoinPoint joinPoint) {
		//System.out.println("### [before]ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œ μ‹€ν–‰ 전에 μ‚½μž…λ˜μ–΄ 싀행될 νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ ###");
		
		String className=joinPoint.getTarget().getClass().getSimpleName();
		String methodName=joinPoint.getSignature().getName();
		Object[] params=joinPoint.getArgs();
		
		System.out.print("### [before]"+className+" 클래슀의 "+methodName+"(");
		for(int i=0;i<params.length;i++) {
			System.out.print(params[i]);
			if(i < params.length-1) {
				System.out.print(", ");
			}
		}
		System.out.println(") λ©”μ†Œλ“œ 호좜 ###");
	}
	
//μ•„λž˜ μ΄μ–΄μ„œ

 

 

2) After Advice Mehtod

public void displayMessage(JoinPoint joinPoint) {
		//System.out.println("### [after]ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œ μ‹€ν–‰ 후에 무쑰건 μ‚½μž…λ˜μ–΄ 싀행될 νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ ###");
		
		Object[] params=joinPoint.getArgs();
		System.out.println("### [after]μ‚¬μ›λ²ˆν˜Έκ°€ "+params[0]+"인 사원정보λ₯Ό μ‚­μ œ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.");
	}
    
//μ•„λž˜ μ΄μ–΄μ„œ

 

 

3) After Returning Advice Mehtod

After Returning Advice Mehtodμ—λŠ” JoinPoint μΈν„°νŽ˜μ΄μŠ€μ˜ λ§€κ°œλ³€μˆ˜ 외에 Object 클래슀의 λ§€κ°œλ³€μˆ˜ μž‘μ„± κ°€λŠ₯
 => AspectJ μ»΄νŒŒμΌλŸ¬λŠ” Object 클래슀의 λ§€κ°œλ³€μˆ˜μ— νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’μ„ μ œκ³΅λ°›μ•„ μ €μž₯
 => νƒ€κ²Ÿλ©”μ†Œλ“œμ—μ„œ λ°˜ν™˜λ˜λŠ” κ°’(객체)의 μžλ£Œν˜•μ΄ κ³ μ •λ˜μ–΄ μžˆλŠ” 경우 Object 클래슀 λŒ€μ‹  λ°˜ν™˜λ˜λŠ” κ°’(객체)의 μžλ£Œν˜•μœΌλ‘œ λ§€κ°œλ³€μˆ˜ μž‘μ„± κ°€λŠ₯
 => After Returning Advice Mehtod에 Object 클래슀의 λ§€κ°œλ³€μˆ˜κ°€ μž‘μ„±λœ 경우 Spring Bean Configuration File의 AOP μ„€μ •μ—μ„œ after-returning μ—˜λ¦¬λ¨ΌνŠΈμ— returning 속성을 λ°˜λ“œμ‹œ μž‘μ„±ν•˜μ•Ό νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’μ„ μ €μž₯ν•  λ§€κ°œλ³€μˆ˜λ₯Ό μ§€μ • 
 => after-returning μ—˜λ¦¬λ¨ΌνŠΈμ— returning 속성이 μ—†κ±°λ‚˜ 속성값이 잘λͺ» μ„€μ •λ˜λ©΄ IllegalArgumentException λ°œμƒ

    public void displayName(JoinPoint joinPoint, Object object) {
		//System.out.println("### [after-returning]ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œκ°€ μ •μƒμ μœΌλ‘œ μ‹€ν–‰λœ 후에 μ‚½μž…λ˜μ–΄ 싀행될 νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ ###");

		String methodName=joinPoint.getSignature().getName();
		String userName=(String)object;
		System.out.println("### [after-returning]"+methodName+" λ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’ = "+userName);
	}
	
//μ•„λž˜ μ΄μ–΄μ„œ

 

 

4) After Throwing Advice Mehtod

After Throwing Advice Mehtodμ—λŠ” JoinPoint μΈν„°νŽ˜μ΄μŠ€μ˜ λ§€κ°œλ³€μˆ˜μ™Έμ— Exception 클래슀의 λ§€κ°œλ³€μˆ˜ μž‘μ„± κ°€λŠ₯
 => AspectJ μ»΄νŒŒμΌλŸ¬λŠ” Exception 클래슀의 λ§€κ°œλ³€μˆ˜μ— νƒ€κ²Ÿλ©”μ†Œλ“œμ—μ„œ λ°œμƒλœ μ˜ˆμ™Έ(Exception 객체)λ₯Ό μ œκ³΅λ°›μ•„ μ €μž₯
 => νƒ€κ²Ÿλ©”μ†Œλ“œμ—μ„œ λ°œμƒλ˜λŠ” μ˜ˆμ™Έκ°€ κ³ μ •λ˜μ–΄ μžˆλŠ” 경우 Exception 클래슀 λŒ€μ‹  ν•„μš”ν•œ
μ˜ˆμ™Έ 클래슀둜 λ§€κ°œλ³€μˆ˜ μž‘μ„± κ°€λŠ₯
 => After Throwing Advice Mehtod에 Exception 클래슀의 λ§€κ°œλ³€μˆ˜κ°€ μž‘μ„±λœ 경우 Spring Bean
Configuration File의 AOP μ„€μ •μ—μ„œ after-throwing μ—˜λ¦¬λ¨ΌνŠΈμ— throwing 속성을 λ°˜λ“œμ‹œ
μž‘μ„±ν•΄μ•Ό νƒ€κ²Ÿλ©”μ†Œλ“œμ—μ„œ λ°œμƒλœ μ˜ˆμ™Έκ°€ μ €μž₯될 λ§€κ°œλ³€μˆ˜λ₯Ό μ§€μ • 
 => after-throwing μ—˜λ¦¬λ¨ΌνŠΈμ— throwing 속성이 μ—†κ±°λ‚˜ 속성값이 잘λͺ» μ„€μ •λ˜λ©΄ IllegalArgumentException λ°œμƒ

	public void exceptionHandle(JoinPoint joinPoint, Exception exception) {
		//System.out.println("### [after-throwing]ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œμ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒλœ 후에 μ‚½μž…λ˜μ–΄ 싀행될 νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ ###");
		
		String methodName=joinPoint.getSignature().getName();
		System.out.println("### [after-throwing]"+methodName+" λ©”μ†Œλ“œμ—μ„œ λ°œμƒλœ μ˜ˆμ™Έ = "
				+exception.getMessage());
	}
	
//μ•„λž˜ μ΄μ–΄μ„œ

 

 

5) Around Advice Method

Around Advice MethodλŠ” Object 클래슀둜 λ°˜ν™˜ν˜•μ„ μž‘μ„±ν•˜κ³  ProceedingJoinPoint μΈν„°νŽ˜μ΄μŠ€λ‘œ λ§€κ°œλ³€μˆ˜λ₯Ό μž‘μ„±ν•˜μ—¬ μ„ μ–Έ
νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’μ„ μ œκ³΅λ°›μ•„ Around Advice Methodμ—μ„œ λ°˜ν™˜ν•˜κΈ° μœ„ν•΄ λ°˜ν™˜ν˜• μž‘μ„±
 => νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’μ΄ μ—†λŠ” 경우 void μžλ£Œν˜•μœΌλ‘œ λ°˜ν™˜ν˜•μ„ μž‘μ„±ν•  수 μžˆμ§€λ§Œ νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’μ΄ μžˆλŠ” 경우 void μžλ£Œν˜•μœΌλ‘œ λ°˜ν™˜ν˜•μ„ μž‘μ„±ν•˜λ©΄ μ—λŸ¬ λ°œμƒ
νƒ€κ²Ÿλ©”μ†Œλ“œ κ΄€λ ¨ 정보λ₯Ό ProceedingJoinPoint μΈν„°νŽ˜μ΄μŠ€μ˜ λ§€κ°œλ³€μˆ˜λ‘œ μ œκ³΅λ°›μ•„ μ‚¬μš©
 => ProceedingJoinPoint 객체 : νƒ€κ²Ÿλ©”μ†Œλ“œ κ΄€λ ¨ 정보λ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•œ 객체
 => JoinPoint 객체와 λ‹€λ₯Έμ μ€ ProceedingJoinPoint 객체둜 νƒ€κ²Ÿλ©”μ†Œλ“œλ₯Ό 직접 호좜 κ°€λŠ₯

	public Object display(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("### [around]ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œ μ‹€ν–‰ 전에 μ‚½μž…λ˜μ–΄ 싀행될 νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ ###");
		//ProceedingJoinPoint.proceed() : ProceedingJoinPoint 객체둜 νƒ€κ²Ÿλ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” λ©”μ†Œλ“œ
		// => νƒ€κ²Ÿλ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ λ°˜ν™˜λ˜λŠ” 결과값을 λ³€μˆ˜μ— μ €μž₯
		// => Throwable(Error ν΄λž˜μŠ€μ™€ Exception 클래슀의 λΆ€λͺ¨ν΄λž˜μŠ€) 객체가 λ°œμƒλ˜λ―€λ‘œ λ°˜λ“œμ‹œ
		//μ˜ˆμ™Έ μ²˜λ¦¬ν•˜κ±°λ‚˜ μ˜ˆμ™Έ 전달
		Object result=joinPoint.proceed();
		System.out.println("### [around]ν•΅μ‹¬κ΄€μ‹¬μ½”λ“œ μ‹€ν–‰ 후에 μ‚½μž…λ˜μ–΄ 싀행될 νš‘λ‹¨κ΄€μ‹¬μ½”λ“œ ###");
		return result;//νƒ€κ²Ÿλ©”μ†Œλ“œμ˜ λ°˜ν™˜κ°’μ„ λ°˜ν™˜ 처리
	}
}

 

 

λ°˜μ‘ν˜•