๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“– Spring/๐ŸŒฑ Spring

[ Spring ] AOP๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ๋ณด์ž!

by carrot0911 2025. 1. 15.

๊ณต๋ถ€ํ•˜๊ฒŒ ๋œ ๊ณ„๊ธฐ

ํŒ€ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๋™์•ˆ, ํŒ€์›์ด AOP(Aspect-Oriented Programming)๋ฅผ ํ™œ์šฉํ•ด ๊ถŒํ•œ ๊ฒ€์‚ฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ชจ์Šต์„ ๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” AOP๋ฅผ ์ด์šฉํ•ด ๋ณต์žกํ•œ ๋กœ์ง์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ชจ์Šต์ด ๋†€๋ผ์› ๊ณ , ๋™์‹œ์— ๋‚ด๊ฐ€ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ์—” ์–ด๋ ต๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŒ€์›์˜ ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ๋ถ„์„ํ•˜๋ฉฐ ์ž‘๋™ ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๋Š” ๊ณผ์ •์—์„œ, "๋‚˜๋„ ๋…ธ๋ ฅํ•˜๋ฉด ์ถฉ๋ถ„ํžˆ AOP๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค"๋Š” ์ž์‹ ๊ฐ์ด ์ƒ๊ฒผ๋‹ค.
์ดํ›„, AOP์˜ ๊ฐœ๋…๊ณผ ํ™œ์šฉ ์‚ฌ๋ก€๋ฅผ ๋” ๊นŠ์ด ์ดํ•ดํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ์—ด์ •์ด ์ƒ๊ฒผ๊ณ , ๊ด€๋ จ ์ž๋ฃŒ๋ฅผ ์ฐพ์•„๋ณด๋ฉฐ ํ•™์Šต์„ ์‹œ์ž‘ํ–ˆ๋‹ค. ์ด๋ฒˆ ๊ฒฝํ—˜์€ ๋‹จ์ˆœํžˆ ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์„ ๋ฐฐ์šฐ๋Š” ๊ฒƒ์„ ๋„˜์–ด, ๋‚ด๊ฐ€ ๊ธฐ์ˆ ์ ์œผ๋กœ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ํ™•์ธํ•œ ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ๋‹ค.


์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์š”์†Œ

๋ฐ”๋กœ ๊ฐ€๋…์„ฑ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

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

์˜ˆ์‹œ

์–ด๋–ค ์ฝ”๋“œ๊ฐ€ ๊ฐ€๋…์„ฑ์ด ๋” ์ข‹์€๊ฐ€์š”?!

๋”๋ณด๊ธฐ
package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void viewProfile(String username, String role) {
        if (!"ADMIN".equals(role)) {
            System.out.println("Access Denied: Only ADMIN can view profiles.");
            return;
        }
        System.out.println("Profile of " + username + " viewed successfully.");
    }

    public void updateProfile(String username, String role) {
        if (!"ADMIN".equals(role)) {
            System.out.println("Access Denied: Only ADMIN can update profiles.");
            return;
        }
        System.out.println("Profile of " + username + " updated successfully.");
    }

    public void deleteProfile(String username, String role) {
        if (!"ADMIN".equals(role)) {
            System.out.println("Access Denied: Only ADMIN can delete profiles.");
            return;
        }
        System.out.println("Profile of " + username + " deleted successfully.");
    }

    public void listUsers(String role) {
        if (!"USER".equals(role) && !"ADMIN".equals(role)) {
            System.out.println("Access Denied: Only USER or ADMIN can view the user list.");
            return;
        }
        System.out.println("User list viewed successfully.");
    }

    public void viewDashboard(String role) {
        if (!"USER".equals(role) && !"ADMIN".equals(role)) {
            System.out.println("Access Denied: Only USER or ADMIN can view the dashboard.");
            return;
        }
        System.out.println("Dashboard viewed successfully.");
    }
}
package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void viewProfile(String username, String role) {
        System.out.println("Profile of " + username + " viewed successfully.");
    }

    public void updateProfile(String username, String role) {
        System.out.println("Profile of " + username + " updated successfully.");
    }

    public void deleteProfile(String username, String role) {
        System.out.println("Profile of " + username + " deleted successfully.");
    }

    public void listUsers(String role) {
        System.out.println("User list viewed successfully.");
    }

    public void viewDashboard(String role) {
        System.out.println("Dashboard viewed successfully.");
    }
}

๊ทธ๋ ‡๋‹ค๋ฉด AOP๋ž€ ๋ฌด์—‡์ผ๊นŒ??

AOP(Aspect-Oriental Programming)์€ ๊ด€์ (Aspect) ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ, ๊ด€์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๋ณด๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค.

  • Aspect: ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๊ณผ ๊ทธ๊ฒƒ์„ ์ ์šฉํ•˜๋Š” ๊ณณ์„ ์ •์˜ํ•˜๊ณ  ํ•ฉ์ณ์„œ ๋ชจ๋“ˆ๋กœ ๋งŒ๋“  ๊ฒƒ์ด๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๊ด€๋ จ ์—†๋Š” ๋ถ€๊ฐ€์ ์ธ ๊ธฐ๋Šฅ๋“ค์„ ๋ชจ๋“ˆํ™” ํ•˜์—ฌ ์ฝ”๋“œ์˜ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒํ•˜๋Š” ๋ฐ์— ์ฃผ๋กœ ํ™œ์šฉ๋œ๋‹ค.


AOP๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋œ๋‹ค.

๋ถ€๊ฐ€์ ์ธ ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ž์ฃผ ๋ฐ˜๋ณต๋˜๋Š” ์ž‘์—…(๋กœ๊น…, ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ)์„ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต์„ ์ตœ์†Œํ™”ํ•˜๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ธ๋‹ค.

์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ

  • ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋‹จ์ˆœํ•ด์ง€๊ณ , ๋ถ€๊ฐ€์ ์ธ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ํŽธ๋ฆฌํ•ด์ง„๋‹ค.

์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€

  • ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ Aspect๋กœ ์ •์˜ํ•˜๊ณ  ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์–‘ํ•œ AOP ์ ์šฉ ๋ฐฉ์‹

์ปดํŒŒ์ผ ์‹œ์  ์ ์šฉ

  • Aspect ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ผ๋ฐ˜ .java ํŒŒ์ผ์„ ์ปดํŒŒ์ผํ•  ๋•Œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ๋„ฃ์–ด์„œ .class ํŒŒ์ผ๋กœ ์ปดํŒŒ์ผํ•ด ์ฃผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์  ์ ์šฉ

  • JVM ๋‚ด ํด๋ž˜์Šค ๋กœ๋”์— .class ํŒŒ์ผ์„ ์˜ฌ๋ฆฌ๋Š” ์‹œ์ ์— ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•ด์„œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

๋Ÿฐํƒ€์ž„ ์‹œ์  ์ ์šฉ

  • ์ปดํŒŒ์ผ, ํด๋ž˜์Šค๋กœ๋”ฉ, main( ) ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์ดํ›„์— ์ž๋ฐ”๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ฒ”์œ„ ๋‚ด์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • ์ด๋ฏธ ๋Ÿฐํƒ€์ž„ ์ค‘์ด๋ผ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์–ด๋ ค์›Œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ, DI, ๋นˆ ๋“ฑ ์—ฌ๋Ÿฌ ๊ฐœ๋…๊ณผ ๊ธฐ๋Šฅ์„ ์ด๋™์›ํ•˜์—ฌ Proxy๋ฅผ ํ†ตํ•ด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
    • Proxy๋Š” ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์‹œ์ ์—์„œ๋งŒ ๋‹ค์Œ ํƒ€๊นƒ์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์ง€์ ์œผ๋กœ ์ œํ•œ๋œ๋‹ค.

Spring AOP

Spring AOP ๊ตฌ์กฐ

์ฃผ๋กœ ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.
์ปดํŒŒ์ผ ์‹œ์ ๊ณผ ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ์— ์ ์šฉํ•˜๋ ค๋ฉด ๋ณ„๋„์˜ ์ปดํŒŒ์ผ๋Ÿฌ์™€ ํด๋ž˜์Šค๋กœ๋” ์กฐ์ž‘๊ธฐ๋ฅผ ์จ์•ผ ํ•˜๋Š”๋ฐ, ์ด๊ฒƒ์„ ์ •ํ•˜๊ณ  ์‚ฌ์šฉ ๋ฐ ์œ ์ง€ํ•˜๋Š” ๊ณผ์ •์ด ๋งค์šฐ ์–ด๋ ต๊ณ  ๋ณต์žกํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Spring AOP๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” build.gradle์— ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

implementation 'org.springframework.boot:spring-boot-starter-aop' // ์Šคํ”„๋ง aop ์ถ”๊ฐ€

AOP๊ฐ€ ํ™œ์šฉ๋˜๋Š” ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ

  • ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ
  • ๋กœ๊น…
  • ๋ณด์•ˆ / ๊ถŒํ•œ ํ™•์ธ
  • ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ

AOP ์šฉ์–ด

Aspect (Advice + Pointcut)

  • AOP๋ฅผ ์ •์˜ํ•  ํด๋ž˜์Šค ์œ„์— ๋ถ™์—ฌ์ค˜์•ผ ํ•œ๋‹ค. ex) @Service, @RestController
  • @Aspect์™€ @Component๋กœ ์„ ์–ธํ•ด์ค€๋‹ค.
@Aspect
@Component
public class AOP ์ •์˜ํ•œ ํด๋ž˜์Šค {

}

Pointcut

  • Join Point ์ค‘์—์„œ Advice๋ฅผ ์–ด๋””์— ์ ์šฉํ• ์ง€, ์ ์šฉํ•˜์ง€ ์•Š์„์ง€ ์œ„์น˜๋ฅผ ํŒ๋‹จํ•˜๋Š” ํ•„ํ„ฐ๋งํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์‹ค์ œ Advice๊ฐ€ ์ ์šฉ๋˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
  • AOP๋ฅผ ์ ์šฉํ•  ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋Š” ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์˜ˆ: ํŠน์  ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ, ํŠน์ • ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ ๋“ฑ.
  • ์–ด๋–ค ๋Œ€์ƒ์— AOP๋ฅผ ์ ์šฉํ•  ๊ฒƒ์ธ์ง€ ์ง€์ •ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
@Aspect
@Component
public class AOP ์ •์˜ํ•œ ํด๋ž˜์Šค {

    // Pointcut: com.example.service ํŒจํ‚ค์ง€ ๋‚ด์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— AOP ์ ์šฉ
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
}

Pointcut ํ‘œํ˜„์‹ โ†’ ๋ชฐ๋ผ๋„ ๋œ๋‹ค! ์šฐ๋ฆฌ๊ฐ€ ์ •๊ทœ์‹์„ ์™ธ์šธ ํ•„์š”๊ฐ€ ์—†์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์™ธ์šธ ํ•„์š”๊ฐ€ ์—†๋‹ค!

Advice

  • Join Point์—์„œ ์ ์šฉํ•  ๋ถ€๊ฐ€ ๋กœ์ง์˜ ์ข…๋ฅ˜๋ฅผ ์ •์˜ํ•œ๋‹ค. ์‹คํ–‰ ์‹œ์ ์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ์œ ํ˜•์ด ์žˆ๋‹ค.
    • @Before: ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰ํ•œ๋‹ค.
    • @After: ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋œ ํ›„์— ์‹คํ–‰ํ•œ๋‹ค.
    • @AfterReturning: ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋œ ํ›„์— ์‹คํ–‰ํ•œ๋‹ค.
    • @AfterThrowing: ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•œ๋‹ค.
    • @Around: ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„์— ์‹คํ–‰ํ•œ๋‹ค.
@Aspect
@Component
public class AOP ์ •์˜ํ•œ ํด๋ž˜์Šค {

    // Pointcut: com.example.service ํŒจํ‚ค์ง€ ๋‚ด์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ(*)์— AOP ์ ์šฉ
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}

    // Before Advice: ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „์— ๋กœ๊ทธ ์ถœ๋ ฅ
    @Before("serviceMethods()")
    public void logBefore() {
        System.out.println("[Before] Method execution started.");
    }

    // After Advice: ๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„ ๋กœ๊ทธ ์ถœ๋ ฅ
    @After("serviceMethods()")
    public void logAfter() {
        System.out.println("[After] Method execution finished.");
    }

}

Join Point

  • AOP๊ฐ€ ์ ์šฉ๋˜๋Š” ์‹คํ–‰ ์‹œ์ ์˜ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ํ๋ฆ„์—์„œ์˜ ํŠน์ • ํฌ์ธํŠธ์ด๋‹ค.
  • Spring AOP๋Š” Proxy ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— Join Point๋Š” ํ•ญ์ƒ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ง€์ ์œผ๋กœ ์ œํ•œ๋œ๋‹ค.
  • ๋ฉ”์„œ๋“œ ์ด๋ฆ„, ๋งค๊ฐœ๋ณ€์ˆ˜ ๋“ฑ ์‹คํ–‰ ์ •๋ณด๋ฅผ ์กฐํšŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
// Around Advice: ์‹คํ–‰ ์ „ํ›„๋ฅผ ๊ฐ์‹ธ์„œ ๋กœ์ง ์ˆ˜ํ–‰
@Around("serviceMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

    System.out.println("[Around] Before method: " + joinPoint.getSignature().getName());
    Object result = joinPoint.proceed(); // ๋ฉ”์„œ๋“œ ์‹คํ–‰
    System.out.println("[Around] After method: " + joinPoint.getSignature().getName());
    return result;
    
}

์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•œ AOP

์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜ @AuthCheck

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
    String[] value()
}

์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด ๊ถŒํ•œ ๊ฒ€์‚ฌํ•˜๋Š” AOP

@Slf4j
@Component
@RequiredArgsConstructor
@Aspect
public class CheckRoleStoreAspect {

    private final HttpServletRequest request;

    @Around("@annotation(team11.team11project.common.aspect.AuthCheck)")
    public Object checkRole(ProceedingJoinPoint joinPoint) throws Throwable{

        //๊ถŒํ•œ ๊ฐ€์ ธ์˜ค๊ธฐ
        String role = (String) request.getAttribute("role");
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        AuthCheck authCheck = method.getAnnotation(AuthCheck.class);

        //๊ถŒํ•œ ์ •๋ณด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
        if (role == null) {
            throw new UserRoleNotFoundException("์‚ฌ์šฉ์ž ๊ถŒํ•œ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
        }

        //์• ๋…ธํ…Œ์ด์…˜ ๊ถŒํ•œ ๊ฐ’๊ณผ ์š”์ฒญ ๋ฐ›์€ ๊ถŒํ•œ ๊ฐ’์„ ํ™•์ธ. ๋งŒ์•ฝ ๋‹ค๋ฅด๋ฉด ์˜ˆ์™ธ์ฒ˜๋ฆฌ.
        if (Arrays.stream(authCheck.value()).noneMatch(role::equals)) {
            throw new UnauthorizedAccessException(String.format(" %s ๊ถŒํ•œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.",
                    Arrays.toString(authCheck.value())));
        }

        log.info("๊ถŒํ•œ ํ™•์ธ ์™„๋ฃŒ. ์š”์ฒญ ๊ถŒํ•œ : {}, ํ•„์š” ๊ถŒํ•œ : {}", role, authCheck.value() );
        return joinPoint.proceed();
    }
}

์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์žฅ์ 

  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด
  • ์ฝ”๋“œ ๊ฐ„๊ฒฐ์„ฑ โ†’ ๊ฐ€๋…์„ฑ ๊ฐœ์„ 
  • ํ™•์žฅ์„ฑ ์ฆ๊ฐ€

AOP์™€ ๊ด€๋ จ๋œ Proxy

Proxy๋Š” ์ž๋ฐ” ๋ฐ ์Šคํ”„๋ง์—์„œ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ์ˆ˜๋งŽ์€ ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ "๋Œ€๋ฆฌ์ธ" ์—ญํ• ์„ ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.
์‹ค์ œ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๊ฑฐ๋‚˜ ๋ถ€๊ฐ€์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

Proxy์˜ ์—ญํ• 

  • ์ ‘๊ทผ ์ œ์–ด: ์‹ค์ œ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•˜๊ฑฐ๋‚˜ ์กฐ๊ฑด์„ ๊ฒ€์ฆํ•œ๋‹ค.
  • ๋ถ€๊ฐ€ ์ž‘์—… ์ˆ˜ํ–‰: ์š”์ฒญ ์ „/ํ›„์— ์ถ”๊ฐ€์ ์ธ ์ž‘์—… ์ˆ˜ํ–‰ (๋กœ๊น…, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ)
  • ์ง€์—ฐ ์ดˆ๊ธฐํ™”: ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. (์ง€์—ฐ ๋กœ๋”ฉ)

Proxy๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • ์ ‘๊ทผ ์ œ์–ด: Proxy๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ณด์•ˆ ๊ฒ€์‚ฌ๋‚˜ ๊ถŒํ•œ ํ™•์ธ ๊ฐ™์€ ์ž‘์—…์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ถ€๊ฐ€ ์ž‘์—… ์ˆ˜ํ–‰: ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋ถ€๊ฐ€์ ์ธ ๊ธฐ๋Šฅ(๋กœ๊น…, ํŠธ๋žœ์žญ์…˜)์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”: ์‹ค์ œ ๊ฐ์ฒด์˜ ์ƒ์„ฑ์ด๋‚˜ ์ดˆ๊ธฐํ™”๊ฐ€ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค ๊ฒฝ์šฐ, Proxy๋ฅผ ์‚ฌ์šฉํ•ด ์ง€์—ฐ ๋กœ๋”ฉ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

References

์ŠคํŒŒ๋ฅดํƒ€ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„ ์ˆ˜์ค€๋ณ„ ํ•™์Šต๋ฐ˜ ์Šคํƒ ๋‹ค๋“œ๋ฐ˜ ์„ธ์…˜
https://sharonprogress.tistory.com/195

 

AOP(Aspect-Oriented Programming)๋ž€? ์˜ˆ์‹œ ํฌํ•จ

1. AOP(Aspect-Oriented Programming)๋ž€? AOP(Aspect-Oriented Programming)๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„ ์ค‘ ํ•˜๋‚˜๋กœ, ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ(Concern Separation)๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. AOP๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ

sharonprogress.tistory.com

https://velog.io/@kai6666/Spring-Spring-AOP-๊ฐœ๋…

 

[Spring] Spring AOP ๊ฐœ๋…

AOP๋Š” ๊ด€์ (Aspect)์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ, ๊ด€์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๋ณด๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค. ๊ด€์ (Aspect)์ด๋ž€, ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๊ณผ ๊ทธ ์ ์šฉ์ฒ˜๋ฅผ ์ •์˜ํ•˜๊ณ  ํ•ฉ์ณ์„œ ๋ชจ๋“ˆ๋กœ ๋งŒ๋“  ๊ฒƒ์ด๋‹ค.OOP์™€ ์ด๋ฆ„

velog.io

https://hstory0208.tistory.com/entry/Spring-์Šคํ”„๋ง-AOPAspect-Oriented-Programming๋ž€-Aspect

 

[Spring] ์Šคํ”„๋ง AOP(Aspect Oriented Programming)๋ž€? - @Aspect

AOP๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ?AOP์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ธฐ ์ „์— AOP๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด ๋จผ์ € ์•Œ์•„ ๋ด…์‹œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์€ ํฌ๊ฒŒ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.ํ•ต์‹ฌ ๊ธฐ๋Šฅ : ํ•ด๋‹น ๊ฐ

hstory0208.tistory.com