๊ด€๋ฆฌ ๋ฉ”๋‰ด

<Hello Hosung๐Ÿ˜Ž/>

[Spring] AOP ๊ฐœ๋…๋ถ€ํ„ฐ ๋กœ๊น… ์˜ˆ์ œ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ์ดํ•ดํ•˜๊ธฐ ๋ณธ๋ฌธ

๐Ÿ’ป Java/ใ…คJava(SpringBoot)

[Spring] AOP ๊ฐœ๋…๋ถ€ํ„ฐ ๋กœ๊น… ์˜ˆ์ œ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ์ดํ•ดํ•˜๊ธฐ

์ขŒ์ถฉ์šฐ๋Œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ผ๊ธฐ๐Ÿง 2024. 11. 17. 21:28


Spring AOP๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?


Spring AOP(Aspect-Oriented Programming)๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•œ๊ณ„๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. AOP๋Š” '๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ'์œผ๋กœ, ํ”„๋กœ๊ทธ๋žจ์˜ ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์™ธ์— ๊ณตํ†ต์ ์ธ ๊ธฐ๋Šฅ(์˜ˆ: ๋กœ๊น…, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ)์„ ๋…๋ฆฝ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ , ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ AOP๋Š” ํ•ต์‹ฌ ๊ธฐ๋Šฅ๊ณผ๋Š” ๋ณ„๋„๋กœ "๊ด€์ (Aspect)"์ด๋ผ๋Š” ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ณตํ†ต๋œ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ชจ๋“ˆํ™”ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ธฐ๋Šฅ์ด๋‚˜ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ๋ฅผ AOP๋ฅผ ํ†ตํ•ด ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


AOP์˜ ํ•ต์‹ฌ ๊ฐœ๋…


Aspect (๊ด€์ ): ํ•ต์‹ฌ ๋กœ์ง์— ๋ถ€๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊น…์ด๋‚˜ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์— ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.
Joinpoint (์กฐ์ธ ํฌ์ธํŠธ): AOP๊ฐ€ ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „, ํ›„, ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๋“ฑ์ด ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.
Advice (์–ด๋“œ๋ฐ”์ด์Šค): ์‹ค์ œ๋กœ ์‹คํ–‰๋˜๋Š” ๋ถ€๊ฐ€์ ์ธ ์ž‘์—…์ž…๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„์— ๋กœ๊น…์„ ํ•œ๋‹ค๋“ ์ง€, ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค๋“ ์ง€ ํ•˜๋Š” ์ž‘์—…์„ ๋งํ•ฉ๋‹ˆ๋‹ค.
Pointcut (ํฌ์ธํŠธ์ปท): Advice๊ฐ€ ์–ธ์ œ ์ ์šฉ๋ ์ง€ ์ •์˜ํ•˜๋Š” ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠน์ • ํŒจํ‚ค์ง€๋‚˜ ํด๋ž˜์Šค ๋‚ด์˜ ๋ฉ”์„œ๋“œ์—๋งŒ AOP๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Weaving (์œ„๋น™): AOP๊ฐ€ ์‹ค์ œ๋กœ ์ ์šฉ๋˜์–ด ์ฝ”๋“œ์— ๊ฒฐํ•ฉ๋˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. Spring์—์„œ๋Š” ๋Ÿฐํƒ€์ž„์— ์œ„๋น™์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

AOP๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์ฃผ์š” ์˜ˆ์‹œ


๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” AOP์˜ ์˜ˆ์‹œ ์ค‘ ํ•˜๋‚˜๋Š” **๋กœ๊น…(logging)**์ž…๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ๋กœ๊ทธ๋ฅผ ์ฐ๊ณ  ์‹ถ๋‹ค๋ฉด, AOP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Spring AOP๋ฅผ ์ด์šฉํ•œ ๋กœ๊น… ์˜ˆ์ œ


์ด์ œ Spring AOP๋ฅผ ์ด์šฉํ•œ ๊ฐ„๋‹จํ•œ ๋กœ๊น… ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„์— ๋กœ๊น…์„ ํ•˜๋Š” ๊ฐ„๋‹จํ•œ AOP๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

1. Spring Boot ํ”„๋กœ์ ํŠธ ์„ค์ •
๋จผ์ € Spring Boot ํ”„๋กœ์ ํŠธ์— AOP ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. build.gradle ๋˜๋Š” pom.xml์— AOP ๊ด€๋ จ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

<!-- pom.xml์— AOP ์˜์กด์„ฑ ์ถ”๊ฐ€ -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>


2. Service ํด๋ž˜์Šค ์ž‘์„ฑ
์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•  Service ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

@Service
public class UserService {

    public void createUser(String name) {
        System.out.println("์‚ฌ์šฉ์ž " + name + " ์ƒ์„ฑ");
    }
}


3. AOP ํด๋ž˜์Šค ์ž‘์„ฑ (๋กœ๊น… ๊ธฐ๋Šฅ)
๋กœ๊น…์„ ์œ„ํ•œ Aspect ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์—์„œ @Before, @After, @Around ๋“ฑ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„์— ๋กœ๊น…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Aspect
@Component
public class LoggingAspect {

    // ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „
    @Before("execution(* com.example.service.UserService.createUser(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „: " + joinPoint.getSignature().getName());
    }

    // ๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„
    @After("execution(* com.example.service.UserService.createUser(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„: " + joinPoint.getSignature().getName());
    }
}


4. AOP ์ ์šฉ ํ™•์ธ
UserService์˜ createUser ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค LoggingAspect๊ฐ€ ์ ์šฉ๋˜์–ด ๋กœ๊น…์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@SpringBootApplication
public class AopExampleApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(AopExampleApplication.class, args);
        UserService userService = context.getBean(UserService.class);
        userService.createUser("John Doe");
    }
}


์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „: createUser
์‚ฌ์šฉ์ž John Doe ์ƒ์„ฑ
๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„: createUser


AOP์˜ ์žฅ์ 

์ฝ”๋“œ ์ค‘๋ณต ์ œ๊ฑฐ: ๋กœ๊น…์ด๋‚˜ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๊ฐ™์€ ๊ณตํ†ต ๊ธฐ๋Šฅ์„ AOP๋ฅผ ํ†ตํ•ด ํ•œ ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ชจ๋“ˆํ™”: ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ ์—ฐ์„ฑ: ํฌ์ธํŠธ์ปท์„ ํ†ตํ•ด ์–ด๋””์— AOP๋ฅผ ์ ์šฉํ• ์ง€ ์‰ฝ๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


AOP์˜ ๋‹จ์ 

๋””๋ฒ„๊น… ์–ด๋ ค์›€: AOP๋Š” ์‹คํ–‰ ์‹œ์ ์—์„œ ๋™์ž‘ํ•˜๋ฏ€๋กœ ๋””๋ฒ„๊น…์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์„ฑ๋Šฅ ์ด์Šˆ: AOP๋ฅผ ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์— ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋งˆ๋ฌด๋ฆฌ

Spring AOP๋Š” ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋กœ๊น…, ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ด๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. AOP๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ฉด์„œ๋„ ํšจ์œจ์ ์ธ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.