AOP(4) - AspectJ

AspectJ๋ž€ ์ˆœ์ˆ˜ Spring AOP API์—์„œ ์ œ๊ณตํ•˜์ง€ ์•Š์€ ํ•„๋“œ์— ๋Œ€ํ•œ Advisor๋ฅผ ์ง€์›ํ•˜๊ณ , CTW(Compile Time Weaving), LTW(Load Time Weaving)๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์œ„๋น™ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ด ํ”„๋กœ๊ทธ๋žจ์˜ ํผํฌ๋จผ์Šค๋ฅผ ํ–ฅ์ƒ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.

๋˜ํ•œ @Aspect ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ฐ”ํƒ•์œผ๋กœ ๋กœ์ง์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด, xml ๋ฐฉ์‹๋ณด๋‹ค๋Š” ๋” ํŽธ๋ฆฌํ•˜๋‹ค.

Weaving

Weaving์€ Aspect ํด๋ž˜์Šค์— ์ •์˜ ํ•œ Advice ๋กœ์ง์„ ํƒ€๊ฒŸ์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ, RTW, CTW, LTW 3๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

RTW(Run Time Weaving)

Spring AOP์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, Proxy๋ฅผ ์ƒ์„ฑํ•ด ์‹ค์ œ ํƒ€๊นƒ ์˜ค๋ธŒ์ ํŠธ์˜ ๋ณ€ํ˜•์—†์ด ์œ„๋น™์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์‹ค์ œ ๋Ÿฐํƒ€์ž„์‹œ Method ํ˜ธ์ถœ ์‹œ์— ์œ„๋น™์ด ์ด๋ฃจ์–ด์ง€๋Š” ๋ฐฉ์‹์ด๋‹ค.

์†Œ์ŠคํŒŒ์ผ, ํด๋ž˜์Šค ํŒŒ์ผ์— ๋ณ€ํ˜•์ด ์—†๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ, Point Cut์— ๋Œ€ํ•œ Advice ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง„๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

CTW(Compile Time Weaving)

AspectJ์—๋Š” AJC (AspectJ Compiler)๋ผ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์žˆ๋Š”๋ฐ Java Compiler๋ฅผ ํ™•์žฅํ•œ ํ˜•ํƒœ์˜ ์ปดํŒŒ์ผ๋Ÿฌ์ด๋‹ค. AJC๋ฅผ ํ†ตํ•ด javaํŒŒ์ผ์„ ์ปดํŒŒ์ผ ํ•˜๋ฉฐ, ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ๋ฐ”์ดํŠธ ์ฝ”๋“œ ์กฐ์ž‘์„ ํ†ตํ•ด Advisor ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์‚ฝ์ž…ํ•˜์—ฌ ์œ„๋น™์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์žฅ์ ์œผ๋กœ๋Š” 3๊ฐ€์ง€ ์œ„๋น™ ์ค‘์—์„œ๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ํผํฌ๋จผ์Šค๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ํ•˜์ง€๋งŒ ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ lombok๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์•„์ฃผ ๋†’๋‹ค. (๊ฑฐ์˜ ๊ฐ™์ด ์‚ฌ์šฉ ๋ถˆ๊ฐ€)

LTW(Load Time Weaving)

ClassLoader๋ฅผ ์ด์šฉํ•ด ํด๋ž˜์Šค๊ฐ€ JVM์— ๋กœ๋“œ๋  ๋•Œ ๋ฐ”์ดํŠธ ์ฝ”๋“œ ์กฐ์ž‘์„ ํ†ตํ•ด ์œ„๋น™๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์€ ์ƒ๋Œ€์ ์œผ๋กœ CTW๋ณด๋‹ค ์งง๋‹ค. ํ•˜์ง€๋งŒ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€๋Š” ๊ณผ์ •์—์„œ ์œ„๋น™์ด ์ผ์–ด๋‚˜๊ธฐ๋•Œ๋ฌธ์— ๋Ÿฐํƒ€์ž„์‹œ ์‹œ๊ฐ„์€ CTW๋ณด๋‹ค ์ƒ๋Œ€์ ์œผ๋กœ ๋Š๋ฆฌ๋‹ค.

Application Context์— ๊ฐ์ฒด๊ฐ€ ๋กœ๋“œ๋  ๋•Œ, ๊ฐ์ฒด ํ•ธ๋“ค๋ง์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ํผํฌ๋จผ์Šค๊ฐ€ ์ €ํ•˜๋œ๋‹ค.

Annotatoin

์„ค๋ช…

@Before

๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์ด์ „ ๋ถ€๋ถ„์— ๋Œ€ํ•œ JoinPoint ์„ค์ •

@Around

๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์ „/ํ›„์— JoinPoint ์„ค์ •

@After

๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์ดํ›„ ๋ถ‘ใ„ด์˜ ๋Œ€ํ•œ JoinPoint์„ค์ •

@AfterReturning

return ์‹คํ–‰ ์ดํ›„ ๋ถ€๋ถ„์— ๋Œ€ํ•œ JoinPoint ์„ค์ •

@AfterThrowable

๋ฉ”์†Œ๋“œ ์‹คํ–‰์‹œ, Throw ์ดํ›„ ๋ถ€๋ถ„์— ๋Œ€ํ•œ Joinpoint ์„ค์ •

@Pointcut

Pointcut์— ๋Œ€ํ•œ ํ‘œํ˜„์‹์„ ๊ฐ€์ง€๋ฉฐ, @Pointcut์ด ์ ์šฉ๋œ ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ฆฌํ„ดํƒ€์ž…์ด void์—ฌ์•ผํ•œ๋‹ค.

  1. ์ ‘๊ทผ ์ œ์–ด์ž ํŒจํ„ด(public or protected)

    • *์ธ ๊ฒฝ์šฐ(or ์ƒ๋žต) ๋ชจ๋“  ์ ‘๊ทผ ์ œ์–ด์ž์— ๋Œ€ํ•ด ์„ค์ • ๊ฐ€๋Šฅ

  2. ๋ฆฌํ„ดํƒ€์ž… : ๋ฉ”์†Œ๋“œ์˜ ๋ฆฌํ„ดํƒ€์ž…์„ ์ง€์ •(ํ•ด๋‹น ํƒ€์ž…์œผ๋กœ ๋ฆฌํ„ด๋˜๋Š” ๋ชจ๋“  ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ point cut)

    • ํ•„์ˆ˜ ๊ธฐ์žฌ

  3. Class ํƒ€์ž… : ํด๋ž˜์Šค ํƒ€์ž… ํŒจํ„ด(ํ•ด๋‹น ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋ชจ๋“  ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•ด Point cut)

    • ํŒจํ‚ค์ง€ ๋ช…๋„ ๊ธฐ์žฌ ํ•„์š”

    • ํ•„์ˆ˜ ๊ธฐ์žฌ

  4. ๋ฉ”์†Œ๋“œ ๋ช… : ํŠน์ • ํด๋ž˜์Šค ๋˜๋Š” ํŒจํ‚ค์ง€ ํ•˜์œ„์˜ ๋ฉ”์†Œ๋“œ ๋ช…์— ๋Œ€ํ•ด Point Cut

    • ํ•„์ˆ˜ ๊ธฐ์žฌ

  5. ์˜ˆ์™ธํƒ€์ž… : ์˜ˆ์™ธ ํด๋ž˜์Šค์— ๋Œ€ํ•ด์„œ Jointpoint ์„ค์ • ๊ฐ€๋Šฅ

AOP ๊ตฌํ˜„

์Šคํ”„๋ง์€ 3๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ AOP๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

  1. XML ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜์˜ POJOํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•œ AOP ๊ตฌํ˜„

  2. AspectJ์—์„œ ์ •์˜ํ•œ @Aspect ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ AOP ๊ตฌํ˜„

์ด์ค‘์—์„œ @Aspect ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ AOP ๊ตฌํ˜„์„ ์˜ˆ๋กœ ๊ตฌํ˜„ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

  1. maven(pom.xml) ์„ค์ •

<!-- aop aspectj -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. @EnableAspectJAutoProxy ์ ์šฉ : ์ตœ์ƒ์œ„ ํŒจํ‚ค์ง€์˜ ํด๋ž˜์Šค์— ์ ์šฉํ•ด AOP๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๊ฒŒํ•ด์ค€๋‹ค.

package com.example.practiceAop;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
@SpringBootApplication
public class PracticeAopApplication {

    public static void main(String[] args) {
        SpringApplication.run(PracticeAopApplication.class, args);
    }
}
  1. ๊ณตํ†ต๊ธฐ๋Šฅ ์ •์˜ ๋ฐ ์‹œ์  ์ •์˜(๋กœ๊ทธ ์ ์šฉ)

package com.example.practiceAop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


/**
 * LoggerAspect
 *  
 * pointcut ๊ธฐ์ค€์œผ๋กœ Log ๊ธฐ๋ก
 * @Aspect : ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๋ชจ๋“ˆ, ํ•ต์‹ฌ๊ธฐ๋Šฅ์— ๋ถ€๊ฐ€๋˜์–ด ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š” ํŠน๋ณ„ํ•œ ๋ชจ๋“ˆ(Pointcut + Advice)
 * Advice : ์‹ค์ œ๋กœ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋‹ด์€ ๊ตฌํ˜„์ฒด
 * PointCut : ๋ณต์ˆ˜์˜ ์กฐ์ธ ํฌ์ธํŠธ๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์€ ๊ฒƒ
 * JoinPoint : Advice๊ฐ€ ์ ์šฉ๋  ์œ„์น˜
 */
@Aspect
@Component
public class LoggerAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    // AOP Point Cut
    // Controller, ServiceImpl, Repository ๊ธฐ์ค€์œผ๋กœ ๋กœ๊ทธ ์ถœ๋ ฅ
    @Around("execution(* com.example.practiceAop.controller.*Controller.*(..)) or execution(* com.example.practiceAop.service.impl.*Impl.*(..)) or execution(* com.example.practiceAop.repository.*Repository.*(..))")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {

        String type = "";
        String name = joinPoint.getSignature().getDeclaringTypeName(); // ์‹คํ–‰๋˜๋Š” ๋Œ€์ƒ ๋ฉ”์„œ๋“œ ์ •๋ณด
        if (name.contains("Controller") == true) {
            type = "Controller ===> ";

        }else if (name.contains("Service") == true) {
            type = "ServiceImpl ===> ";
        }else if (name.contains("Repository") == true) {
            type = "Repository ===> ";
        }

        logger.info(type + name + "." + joinPoint.getSignature().getName() + "( )" );

        return joinPoint.proceed();
    }

}

์ฐธ์กฐ

Last updated