๐Ÿ“š TIL 34์ผ์ฐจ

temprmnยท2023๋…„ 7์›” 10์ผ
0
post-thumbnail

Spring AOP

AOP๋Š” 'Aspect Oriented Programming'์˜ ์•ฝ์ž๋กœ, ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค. ๊ด€์  ์ง€ํ–ฅ์€ ์–ด๋–ค ๋กœ์ง์„ ํ•ต์‹ฌ์ ์ธ ๊ด€์ ๊ณผ ๋ถ€๊ฐ€์ ์ธ ๊ด€์ ์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ๋ณด๊ณ , ๊ทธ ๊ด€์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋ชจ๋“ˆํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

*๋ชจ๋“ˆํ™” : ์–ด๋–ค ๊ณตํ†ต๋œ ๋กœ์ง์ด๋‚˜ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ๋ฌถ๋Š” ๊ฒƒ

Advice

๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ '์–ธ์ œ ์ˆ˜ํ–‰ํ• ๊ฑด์ง€' ๊ฒฐ์ •ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ํ•ต์‹ฌ๊ธฐ๋Šฅ์ด ์‹คํ–‰๋œ ์ „์ด๋‚˜ ํ›„๊ฐ€ ๋  ์ˆ˜ ์žˆ๊ณ , ์ „ยทํ›„ ์ „๋ถ€๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ๋˜, ํ•ต์‹ฌ๊ธฐ๋Šฅ ์ˆ˜ํ–‰ ์„ฑ๊ณต ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋™์ž‘ํ• ์ง€๋„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ํ•ต์‹ฌ๊ธฐ๋Šฅ ์ˆ˜ํ–‰์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋œ ๊ฒฐ๊ณผ๋ฌผ์„ ์‚ฌ์šฉํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  1. @Around: 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ์ˆ˜ํ–‰ ์ „๊ณผ ํ›„ (@Before + @After)
  2. @Before: 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ํ˜ธ์ถœ ์ „
    • ex. Client ์˜ ์ž…๋ ฅ๊ฐ’ Validation ์ˆ˜ํ–‰
  3. @After: 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ์ˆ˜ํ–‰ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด ์–ธ์ œ๋‚˜ ๋™์ž‘
    • try, catch ์˜ finally() ์ฒ˜๋Ÿผ ๋™์ž‘
  4. @AfterReturning: 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ํ˜ธ์ถœ ์„ฑ๊ณต ์‹œ (ํ•จ์ˆ˜์˜ Return ๊ฐ’ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
  5. @AfterThrowing: 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ํ˜ธ์ถœ ์‹คํŒจ ์‹œ. ์ฆ‰, ์˜ˆ์™ธ (Exception) ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ๋งŒ ๋™์ž‘
    • ex. ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ email ์ด๋‚˜ SMS ๋ณด๋ƒ„)

Pointcut

pointcut = ์ง€์ . ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋งŒ๋“  ํ›„, ํ•ต์‹ฌ๊ธฐ๋Šฅ์˜ ์–ด๋””์— ๋ถ™์ผ์ง€(์ˆ˜ํ–‰ํ• ์ง€) ๊ฒฐ์ •ํ•œ๋‹ค.

- ํฌ์ธํŠธ์ปท Expression ํ˜•ํƒœ

? ๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(param-pattern) throws-pattern?)
  • modifiers-pattern
    • public, private, *
  • return-type-pattern
    • void, String, List๏ผœString๏ผž, *
  • declaring-type-pattern
    • ํด๋ž˜์Šค๋ช… (ํŒจํ‚ค์ง€๋ช… ํ•„์š”)
    • com.sparta.myselectshop.controller.* - controller ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ํด๋ž˜์Šค์— ์ ์šฉ
    • com.sparta.myselectshop.controller.. - controller ํŒจํ‚ค์ง€ ๋ฐ ํ•˜์œ„ ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ํด๋ž˜์Šค์— ์ ์šฉ
  • method-name-pattern(param-pattern)
    • ํ•จ์ˆ˜๋ช…
      • addFolders : addFolders() ํ•จ์ˆ˜์—๋งŒ ์ ์šฉ
      • add* : add ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ํ•จ์ˆ˜์— ์ ์šฉ
    • ํŒŒ๋ผ๋ฏธํ„ฐ ํŒจํ„ด (param-pattern)
      • (com.sparta.myselectshop.dto.FolderRequestDto) - FolderRequestDto ์ธ์ˆ˜ (arguments) ๋งŒ ์ ์šฉ
      • () = ์ธ์ˆ˜ ์—†์Œ
      • (*) = ์ธ์ˆ˜ 1๊ฐœ (ํƒ€์ž… ์ƒ๊ด€์—†์Œ)
      • (..) = ์ธ์ˆ˜ 0~N๊ฐœ (ํƒ€์ž… ์ƒ๊ด€์—†์Œ)

โ†’ ํฌ์ธํŠธ์ปท Expression ์˜ˆ์ œ

@Around("execution(public * com.sparta.myselectshop.controller..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { ... }

@Pointcut ์‚ฌ์šฉ ์˜ˆ์ œ 1

@Component
@Aspect
public class Aspect {

	// ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ํด๋ž˜์Šค์— ์ ์šฉ + ์ธ์ˆ˜๊ฐ€ ๋ช‡ ๊ฐœ์ธ์ง€ ์ƒ๊ด€์—†์Œ
	@Pointcut("execution(* com.sparta.myselectshop.controller.*.*(..))")
	private void forAllController() {}

	// ๋ฐ˜ํ™˜ ํƒ€์ž… String์ธ + ๋ชจ๋“  ํด๋ž˜์Šค + ์ธ์ˆ˜ ์—†์Œ
	@Pointcut("execution(String com.sparta.myselectshop.controller.*.*())")
	private void forAllViewController() {}

	/* @Pointcut์„ ํ˜ธ์ถœํ•  ๋•Œ๋Š” ๋ฉ”์„œ๋“œ ๋ช…์œผ๋กœ */
    
    // ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์ด๋ฉด์„œ && view ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์•„๋‹Œ(!)
	@Around("forAllContorller() && !forAllViewController()")
	public void saveRestApiLog() {
		...
	}

	// ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœ
	@Around("forAllContorller()")
	public void saveAllApiLog() {
		...
	}	
}

@Pointcut ์‚ฌ์šฉ ์˜ˆ์ œ 2

@Slf4j(topic = "UseTimeAop")
@Aspect
@Component
@RequiredArgsConstructor
public class UseTimeAop {

    /* ์ƒ์„ฑ์ž ์ฃผ์ž… ์ƒ๋žต */

	// ProductController + ์ธ์ˆ˜ ์ƒ๊ด€ ์—†์Œ
    @Pointcut("execution(* com.sparta.myselectshop.controller.ProductController.*(..))")
    private void product() {}
    
    // FolderController + ์ธ์ˆ˜ ์ƒ๊ด€ ์—†์Œ
    @Pointcut("execution(* com.sparta.myselectshop.controller.FolderController.*(..))")
    private void folder() {}
    
    // NaverApiController + ์ธ์ˆ˜ ์ƒ๊ด€ ์—†์Œ
    @Pointcut("execution(* com.sparta.myselectshop.naver.controller.NaverApiController.*(..))")
    private void naver() {}


	// product ํ˜น์€ folder ํ˜น์€ naver api ์ปจํŠธ๋กค๋Ÿฌ์˜
    // ์•ž ๋’ค๋กœ(@Around) execute() ์‹คํ–‰
    @Around("product() || folder() || naver()")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        // ์ธก์ • ์‹œ์ž‘ ์‹œ๊ฐ„
        // ...
        

execute() ๋‚ด๋ถ€์—์„œ๋Š” ํ•ต์‹ฌ๊ธฐ๋Šฅ์„ ์‹คํ–‰ ํ›„ โ†’ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•œ๋‹ค.

@Around("product() || folder() || naver()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
	// ์ธก์ • ์‹œ์ž‘ ์‹œ๊ฐ„
	long startTime = System.currentTimeMillis();

	try {
		// ํ•ต์‹ฌ๊ธฐ๋Šฅ ์ˆ˜ํ–‰
		Object output = joinPoint.proceed();
		return output;
        
	} finally {
    	// ....
        

Spring AOP ๋™์ž‘ ์ดํ•ด

์‹œํ€€์Šค ๋‹ค์ด์–ด๊ทธ๋žจ (Sequence Diagram)

  • AOP ์ ์šฉ ์ „
  • AOP ์ ์šฉ ํ›„
  1. Spring์ด ํ”„๋ก์‹œ(๊ฐ€์งœ ํ˜น์€ ๋Œ€๋ฆฌ) ๊ฐ์ฒด๋ฅผ ์ค‘๊ฐ„์— ์‚ฝ์ž…ํ•ด์ค€๋‹ค.
  2. DispatcherServlet ๊ณผ ProductController ์ž…์žฅ์—์„œ๋Š” ๋ณ€ํ™”๊ฐ€ ์ „ํ˜€์—†๋‹ค.
    • ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜์˜ input, output ์ด ์™„์ „ ๋™์ผํ•˜๋‹ค.
    • joinPoint.proceed() ์— ์˜ํ•ด์„œ ์›๋ž˜ ํ˜ธ์ถœํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ํ•จ์ˆ˜, ์ธ์ˆ˜(argument) ๊ฐ€ ์ „๋‹ฌ๋œ๋‹ค.
      โ†’ createProduct(requestDto);
profile
`ISFJ` T 49% F 51% /

0๊ฐœ์˜ ๋Œ“๊ธ€