일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 배열
- LV03
- 알고리즘
- 연습문제
- 포트 폴리오
- CoffiesVol.02
- jpa blog
- 코테
- mysql
- LV0
- docker
- Til
- Java
- 일정관리프로젝트
- LV01
- Redis
- LV1
- 네트워크
- JPA
- LV.02
- 이것이 자바다
- Spring Frame Work
- 디자인 패턴
- 포트폴리오
- 프로그래머스
- 데이터 베이스
- Lv.0
- Join
- SQL
- LV02
- Today
- Total
코드 저장소.
Aop?? (관점지향 프로그래밍) 본문
목차
- Aop ??
- Spring Aop 용어
- Aop의 특징
- Aop의 구현방법
1. Aop ??
aop는 spring의 핵심개념중 하나로서 관점지향 프로그래밍을 말합니다. 기존의 객체지향(OOP)를 보완하는 방법으서, 흩어진 관점을 모듈화해서 비즈니시로직을 해치지 않고 재사용을 하는 프로그래밍 기법을 말합니다.
여기서 "관점"이라는 것은 프로그램의 특정 기능이나 관심사를 횡단(cross-cutting)하는 구조적 요소를 나타냅니다. 다시 말해, 코드의 여러 부분에서 반복적으로 나타나는 공통 관심사를 캡슐화한 것을 의미합니다.
2.Spring Aop용어
- Target : AOP 가 적용될 타겟(클래스)
- Aspect : Target에 적용될 부가 공통 관심 사항(로깅, 보안, 트랜잭션 관리 등등) (Advice + PointCut)
- Advice : JoinPoint에 실행될 실제 코드
- JoinPoint : Advice가 적용될 위치
- PointCut : Advice를 적용할 JoinPoint을 선별하는 표현식
- Weaving : PointCut으로 결정된 타겟에 부가기능(Advice)를 삽입하는 과정
3.Aop 특징
Spring Aop의 특징은 다음과 같습니다.
- spring aop는 프록시 패턴 기반의 aop 구현체입니다.
- target 객체에 대한 프록시를 만들어서 제공
- target을 감싸는 프록시는 런타임시 생성
- 접근 제어 및 부가 기능 추가를 위해서 프록시객체를 생성
※프록시 패턴
interface가 존재하고 Client는 이 interface 타입으로 Proxy 객체를 사용하게 된다.
Proxy 객체는 기존의 타겟 객체(Real Subject)를 참조하고 있다. Proxy 객체와 Real Subject의 타입은 같고, Proxy는 원래 해야 할 일을 가지고 있는 Real Subject를 감싸서 Client의 요청을 처리한다.
- 프록시가 target 객체의 호출을 가로채 advice 수행 전/후에 핵심로직을 실행
- 스프링 Bean에만 AOP적용 가능
- 메소드 조인 포인트만 지원하여 메소드가 호출되는 런타임 시점에만 advice적용
4.Aop의 구현 방법
aop를 구현하는 방법은 JDK Dynamic Proxy 와 CGlib Proxy로 구현을 할 수 있습니다.
JDK Dynamic Proxy
JDK Dynamic Proxy는 자바에서 제공하는 api(Reflection)를 사용해서 인터페이스기반으로 proxy를 생성한다.
InvocationHandler객체의 invoke()메서드를 오버라이딩을 해서 구현을 합니다.
다만 단점이 있다면 Dynamic Proxy는 Invocation Handler를 상속받아서 실체를 구현하게 되는데, 이 과정에서 특정 Object에 대해 Reflection을 사용하기 때문에 성능이 조금 떨어지는 단점이 있습니다.
간단한 예를 들어 구현을 해보자면 다음과 같다.
// Aspect 클래스
class LoggingAspect {
public void before() {
System.out.println("Logging before method execution...");
}
public void after() {
System.out.println("Logging after method execution...");
}
}
// InvocationHandler 구현
class MyInvocationHandler implements InvocationHandler {
private Object target;
private LoggingAspect aspect;
public MyInvocationHandler(Object target, LoggingAspect aspect) {
this.target = target;
this.aspect = aspect;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
aspect.before(); // 메서드 실행 전에 로깅
Object result = method.invoke(target, args); // 원본 메서드 호출
aspect.after(); // 메서드 실행 후에 로깅
return result;
}
}
// 클라이언트 클래스
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
public void sayHello() {
System.out.println("Hello, world!");
}
}
public class Main {
public static void main(String[] args) {
LoggingAspect aspect = new LoggingAspect();
Hello hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello, aspect);
Hello proxyHello = (Hello) Proxy.newProxyInstance(
Main.class.getClassLoader(),
new Class[] { Hello.class },
handler
);
proxyHello.sayHello(); // 프록시를 통해 메서드 호출
}
}
코드의 내용은 간단합니다. Aspect 클래스에는 로깅 관련 작업을 정의하고, InvocationHandler에서는 메서드 호출 전후에 Aspect의 작업을 실행합니다. 클라이언트 코드는 프록시 객체를 통해 메서드를 호출하며, 이를 통해 Aspect가 적용되는 간단한 예제입니다.
다음은 CGlib Proxy입니다.
CGlib Proxy 는 Enhancer를 바탕으로 Proxy를 구현하는 방식으로 이 방식은 JDK Dynamic Proxy와는 다르게 Reflection을 사용하지 않고, Extends(상속) 방식을 이용해서 Proxy화 할 메서드를 오버라이딩 하는 방식입니다.
위의 예제를 CGlib Proxy로 구현하면 다음과 같습니다.
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.Enhancer;
import java.lang.reflect.Method;
// Aspect 클래스
class LoggingAspect implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Logging before method execution...");
Object result = proxy.invokeSuper(obj, args); // 원본 메서드 호출
System.out.println("Logging after method execution...");
return result;
}
}
// 클라이언트 클래스
class Hello {
public void sayHello() {
System.out.println("Hello, world!");
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Hello.class);
enhancer.setCallback(new LoggingAspect());
Hello proxyHello = (Hello) enhancer.create();
proxyHello.sayHello(); // 프록시를 통해 메서드 호출
}
}
여기까지 Aop를 구현하는 방식으로 2가지의 방식을 봤습니다. 그럼 위의 2가지 방법은 어떻게 스프링에 적용을 하는 것인가??
JDK 프록시의 InvocationHandler , CGlib의 MethodInterceptor는 스프링 AOP에서 JointPoint의 개념입니다.
JDK 프록시의 조건문, CGlib의 MethodMatcher는 스프링 AOP의 PointCut 개념입니다.
JDK invoke 메서드 내용, CGlib 의 Intercept 메서드 내용은 스프링 AOP의 Advice 개념입니다.
참고
https://huisam.tistory.com/entry/springAOP#JDK%20Dynamic%20Proxy-1
'웹개발 > Spring' 카테고리의 다른 글
TestContainer를 활용한 테스트 코드 작성하기. (0) | 2025.01.22 |
---|---|
Spring Batch?? (0) | 2024.05.12 |
스프링 Di (의존성 주입) (0) | 2024.04.15 |
Spring Security의 구조 및 흐름 (0) | 2023.09.21 |
스프링 프레임 워크(Spring Frame Work) (0) | 2023.07.22 |