티스토리 뷰
스프링에서 AOP를 구현하는 방법중 하나가 dynamic proxy 를 이용하는 방법이다. 특별한 내용은 아니고, dynamic proxy 를 직접 구현해보는 포스팅을 하나 하고자한다.
public interface Inter {
String toMessage();
}
먼저 인터페이스를 하나 정의해준다. 예제를 위한 인터페이스라 대충 만들었다. 이제 proxy 를 구현해주자. Proxy 클래스에있는 팩토리메서드를 호출하면 된다.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
(호출해야할 메서드)
파라미터들을 확인해보자. 클래스로더와 구현해야할 인터페이스, 그리고 호출핸들러를 필요로하고있다. 하나하나 파고들면 너무 어려워지니... 일단은 구현해보자. 뭘 보내야할지 가장 난감한게 클래스로더일텐데, 현재 스레드의 컨텍스트 클래스로더를 보내주면 된다. 두번째는 인터페이스를 받긴하는데 잘 보면 배열이다. 배열로 보내주자.
Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{Inter.class})
이런형태로 넣어주면 된다. 이제 마지막 InvocationHandler 를 넣어줘야하는데
public interface InvocationHandler
얘는 인터페이스다. 고로 구현해줘야한다.
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
익명 클래스형태로 구현해준다. 3개의 파라미터를 받는데 proxy 자신과 method, args 를 받는다. method 객체의 invoke() 메서드를 호출하면 원래 호출하고자하는 메서드가 호출된다. args 는 해당 메서드의 인자이다.
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(new Inter() {
@Override
public String toMessage() {
return "world";
}
}, args);
}
}
안에 구현된 Inter 익명클래스가 proxy 를 이용해 AOP 처리하고자하는 실제 객체이다. 얘를 위에 작성한 Proxy 에 전달하면 된다.
Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {Inter.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(new Inter() {
@Override
public String toMessage() {
return "world";
}
}, args);
}
});
이제 proxy 객체를 담을 변수를 선언해주면 된다. 위에서 확인했다면 알겠지만 팩토리 메서드는 Object 타입을 반환하므로 형변환을 해줘야한다.
Inter inter = (Inter) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] {Inter.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(new Inter() {
@Override
public String toMessage() {
return "world";
}
}, args);
}
});
그리고 호출해주자.
System.out.println(inter.toMessage());
world 라는 문자열이 찍히는걸 볼 수 있다. 이제 AOP 에 걸맞게 실제 호출 메서드 전에 내가 원하는 행위를 하도록 구현해보자.
Inter inter = (Inter) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] {Inter.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("hello");
return method.invoke(new Inter() {
@Override
public String toMessage() {
return "world";
}
}, args);
}
});
world 앞에 hello 가 찍히게된다. 실무에서 직접 proxy 를 이용할 일은 거의 없다. 하지만 스프링을 공부하다보면 AOP 에 대한 공부가 필연적이고, Spring AOP 를 공부하다보면 JDK Dynamic Proxy 라는 말을 여러번 듣고, 보게된다. JDK Dynamic Proxy 가 무엇이고 대략적으로 어떻게 구현하는지 정도는 알고있으면 좋다. 그래야 왜 Spring AOP 에서 Dynamic Proxy 방식을 이용할때는 인터페이스 구현이 필수인지도 이해할수 있기 때문이다.
'Java' 카테고리의 다른 글
spring boot에 jOOQ 적용하기#1 (1) | 2019.05.12 |
---|---|
애노테이션 실습시 error: Could not instantiate an instance of processor 'com.yong.java10.AnnotationProcessor' 1 error 에러 (0) | 2018.09.15 |
java9#01. 추가된 API 들 (0) | 2018.08.15 |
swagger 사용시 objectMapperConfigurer bean create exception 발생 (0) | 2018.07.09 |
jshell 이용하기 (2) | 2018.07.01 |
- Total
- Today
- Yesterday
- code
- spring cloud
- javascript
- servlet
- backend개발환경
- mariadb
- JPA
- OOP
- go-core
- clean code
- frontend개발환경
- generics
- Kotlin
- programming
- Jackson
- DesignPattern
- toby
- MySQL
- java8
- Spring
- JavaScript Core
- frontcode
- Design Pattern
- EffectiveJava
- http
- java
- 정규표현식
- TEST
- Git
- db
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |