DIとAOPの仕組みを知るにはリフレクションを試すのがいいと思ってサンプルを準備してみました。
1. クラス名をもとにインスタンスを作れるか実験
まずはリフレクションを使うことでクラス情報をもとにインスタンスを制御できることを確認します。
package test;
public class ReflectionSampleService {
public void execute() {
System.out.println("メソッドが呼ばれた。");
}
}
package test;
import java.lang.reflect.Method;
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// クラス名をもとにクラス情報を得る
Class<?> clazz = Class.forName("test.ReflectionSampleService");
// クラス情報をもとにメソッド情報が得る
Method method = clazz.getMethod("execute");
// クラス情報をもとにインスタンスを生成
Object sampleService = clazz.getDeclaredConstructor().newInstance();
// メソッド情報とインスタンスをもとに、インスタンスメソッドを実行する
// 実質: sampleService.execute()
method.invoke(sampleService);
}
}
メソッドが呼ばれた。
2. メソッドが呼ばれたことを検知できるか実験
次に、インスタンスを制御できると、メソッドが呼ばれたことを検知して前後処理が仕込めることを確認します。
public interface SomeService {
void someMethod();
}
public class SomeServiceImpl implements SomeService {
@Override
public void someMethod() {
System.out.println("メソッドが呼ばれた。");
}
}
public interface OtherService {
void otherMethod();
}
public class OtherServiceImpl implements OtherService {
@Override
public void otherMethod() {
System.out.println("メソッドが呼ばれた。");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AopInvocationHandler implements InvocationHandler {
private final Object target;
public AopInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "() Before");
Object result = method.invoke(target, args);
System.out.println(method.getName() + "() After");
return result;
}
}
import java.lang.reflect.Proxy;
public class AopDemo {
public static void main(String[] args) {
SomeService someService = create(SomeService.class, new SomeServiceImpl());
OtherService otherService = create(OtherService.class, new OtherServiceImpl());
someService.someMethod();
otherService.otherMethod();
}
public static <T> T create(Class<T> interfaceType, T target) {
Class<?> targetClass = target.getClass();
// チェックすべき
// 1. interfaceTypeがインターフェースであること
// 2. targetClassがインターフェースの実装であること
Object proxy = Proxy.newProxyInstance(
targetClass.getClassLoader(),
new Class<?>[] { interfaceType },
new AopInvocationHandler(target));
return interfaceType.cast(proxy);
}
}
someMethod() Before
メソッドが呼ばれた。
someMethod() After
otherMethod() Before
メソッドが呼ばれた。
otherMethod() After
3. まとめ
- DIにクラス情報を登録しておく(このページでは実験なし)
- 登録されたクラス情報をもとにインスタンスをつくる
- メソッドの実行をハンドリングし、呼ばれたメソッドの前後に処理を挟む
この2つのサンプルを確認によって、DIやAOPで使われるリフレクションの考え方が理解できると幸いです。