AOP 용어들과 DynamicProxy를 사용한 간단한 예제
- 구준근(기술위원회 PiLab팀), 2006년 11월
서론 #
- AOP에서 사용되는 용어들을 이해하고 JDK DynamicProxy를 이용하여 간단히 예제를 만들어 본다.
본론 #
- AOP에서 새롭게 등장한 용어
- Target : 주가 되는 비지니스 로직을 구현하고 있는 클래스를 말합니다.
- JointPoint : Target 즉, 주가 되는 비지니스 로직을 가지는 인스턴스에 이벤트가 발생하는 시점을 말합니다.
예를 들면 인스턴스가 생성되거나, 인스턴스의 특정 메소드가 호출되는 시점 또는 Exception이 발생하는 시점 등이 예가 됩니다.
- Advice : target의 주된 비지니스 로직에 추가로 실행되어질 로직이 구현된 부분 입니다.
- PointCut : Target의 JointPoint에 Advice를 결합하기 위해서 필요한 패턴을 말합니다.
- Weaving : Target에 Advice 기능을 결합시키는 것을 말합니다. JAVA JDK에서는 1.3 버전부터 reflect API를 사용한
DynamicProxy 클래스를 지원하여 부분적인 AOP를 구현하고 있으며, AspectJ 등의 툴은 바이너리 파일을 재 컴파일하여 AOP를 완벽히 지원하고 있습니다.
- Aspect : Target의 JointPoint에 Advice 기능이 Weaving 되어 Target에 주된 비지니스 로직에 Advice 기능을 지원할 수 있도록 하는 완성된 클래스 입니다.
- DynamicProxy를 통한 예제
- DynamicProxy를 통한 AOP 맛보기 JDK에 포함된 DynamicProxy를 통해서 간단한 AOP를 구현해 보겠습니다.
- Orc라는 인터페이스와 이를 구현한 OrcImpl이 있습니다. Orc가 가지는 주된 비지니스 로직은 다음과 같습니다.
- orc에게는 인사를 하는 sayHell() 메소드와 이동하는 orcGo()라는 메소드가 있습니다.
- 특히 orcGo() 메소드는 방향을 뜻하는 parameter가 필요합니다. 방향은 동,서,남,북 이렇게 4가지 이며, 실행시키면 다음과 같은 메세지를 찍습니다.
public interface Orc
{
public final static int __DIRECTION_NORTH = 1;
public final static int __DIRECTION_SOUTH = 2;
public final static int __DIRECTION_EAST = 3;
public final static int __DIRECTION_WEST = 4;
public void sayHello(String name);
public void orcGo(int direction);
}
OrcImpl.java
public class OrcImpl implements Orc
{
public void sayHello(String name)
{
System.out.println("hello~ " + name);
}
public void orcGo(int direction)
{
switch (direction)
{
case __DIRECTION_NORTH:
System.out.println("orc go NORTH..");
break;
case __DIRECTION_SOUTH:
System.out.println("orc go SOUTH..");
break;
case __DIRECTION_EAST:
System.out.println("orc go EAST..");
break;
case __DIRECTION_WEST:
System.out.println("orc go WEST..");
break;
}
}
}
main Method
public class RunTest
{
public static void main(String[] args)
{
Orc orc = new OrcImpl();
orc.sayHello("xxx");
orc.orcGo(Orc.__DIRECTION_EAST);
}
}
실행결과
hello~ xxx orc go EAST..
- 그런데 문제가 생겼습니다. 오크의 대도시인 오그리마 동쪽에 전쟁이 터졌습니다.!!
- 오크에게 동쪽으로 이동할때 주의를 주는 메세지를 포함해야 합니다.
- 이것을 DynamicProxy를 사용하여 구현하기 위해 다음과 같은 goEastAlertProxy를 구현합니다.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class goEastAlertProxy implements java.lang.reflect.InvocationHandler
{
private Object obj;
private goEastAlertProxy(Object obj)
{ this.obj = obj; }
public static Object newInstance(Object obj)
{
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
.getClassLoader(), obj.getClass().getInterfaces(),
new goEastAlertProxy(obj));
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
Object result;
try
{
result = m.invoke(obj, args);
if(m.getName().equals("orcGo"))
{
if(String.valueOf(args[0]).equals((String.valueOf(Orc.__DIRECTION_EAST))))
{
System.out.println("No! East!!");
}
}
}
catch (InvocationTargetException e)
{
throw e.getTargetException();
}
catch (Exception e)
{
throw new RuntimeException("unexpected invocation exception:"
+ e.getMessage());
}
finally
{
}
return result;
}
}
실행코드
public class RunTest
{
public static void main(String[] args)
{
Orc orc = new OrcImpl();
orc.sayHello("xxx");
orc.orcGo(Orc.__DIRECTION_EAST);
System.out.println("======================================");
Orc orcProxy = (Orc)goEastAlertProxy.newInstance(new OrcImpl());
orcProxy.sayHello("xxx");
orcProxy.orcGo(Orc.__DIRECTION_EAST);
}
}
결과
hello~ xxx orc go EAST.. ====================================== hello~ xxx orc go EAST.. No! East!!
- 여기서 Target은 OrcImpl
- JointPoint는 메소드가 끝나는 지점
- PointCut은 goOrc 라는 이름을 가진 메소드
- Advice는 "No! East!! 라는 메세지를 남기는 부분
- Aspect는 goEastAlertProxy 정도로 살펴 볼 수 있습니다.
- weaving은 내부적으로 JDK reflect API들이 해주고 있구요.
- AOP에 필요한 개념을 간단한 DynamicProxy 예제로 살펴봤습니다.