cglib実習01

いまさらながら簡単なサンプルを作ってみる。

まずはinterceptされちゃうクラス。 aaa()の中からbbb()を呼んでみて、クラス内部からの呼び出しでInterceptorが効くのかどうかを見てみる。

package yamo;

public class Foo {
public void aaa() {
Util.log("<aaa> start");
bbb();
Util.log("<aaa> end");
}

public void bbb() {
Util.log("<bbb> start");
Util.log("<bbb> end");
}
}

次にinterceptorクラス。 対象メソッドの前後でinterceptor用のログを出力する。 MethodProxyの「invokeSuper」っていうネーミングあたりでinterceptorの仕組みを窺い知ることができる。

package yamo;

import java.lang.reflect.*;
import net.sf.cglib.proxy.*;

public class LogInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {

Object ret = null;
try {
Util.log(obj.getClass(), method, "start Intercepter");
if(!Modifier.isAbstract(method.getModifiers())) {
ret = proxy.invokeSuper(obj, args);
}
} finally {
Util.log(obj.getClass(), method, "end Intercepter");
}

return ret;
}
}

そしてログ用のユーティリティクラス。

package yamo;

import java.lang.reflect.*;

public final class Util {
public static void log(Class clazz, Method method, String msg) {
log("[" + clazz.getName() +"][" + method.getName() + "]" + msg);
}

public static void log(String msg) {
System.out.println(msg);
}
}

いよいよメイン処理のクラス。

package yamo;

import net.sf.cglib.proxy.*;

public class Main {
public static void main(String[] args) {
Foo foo = (Foo)newInstance(Foo.class);
Util.log("========================================");
Util.log("<<" + foo.getClass().getName() + ">>");
Util.log("========================================");
foo.aaa();

foo = new Foo();
Util.log("========================================");
Util.log("<<" + foo.getClass().getName() + ">>");
Util.log("========================================");
foo.aaa();
}

public static Object newInstance(Class clazz) {
try {
LogInterceptor interceptor = new LogInterceptor();
Enhancer en = new Enhancer();
en.setSuperclass(clazz);
en.setCallback(interceptor);
Object target = en.create();
return target;
} catch(Throwable e) {
e.printStackTrace();
throw new Error(e.getMessage());
}
}
}

で、最後に実行結果。

========================================
<<yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf>>
========================================
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][aaa]start Intercepter
<aaa> start
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][bbb]start Intercepter
<bbb> start
<bbb> end
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][bbb]end Intercepter
<aaa> end
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][aaa]end Intercepter
========================================
<<yamo.Foo>>
========================================
<aaa> start
<bbb> start
<bbb> end
<aaa> end
「クラスEnhancer越しに生成したインスタンスはFooを拡張したクラスのインスタンスであり、クラスの内部でメソッドを呼んだ場合でもきちんとinterceptされる」ということですね。

教訓:はてなダイアリーに載せるつもりなら「<」とか「>」の使用は避けよう