๊ณต๋ถํ๊ฒ ๋ ๊ณ๊ธฐ
ํ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ ๋์, ํ์์ด 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๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์๋ 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