DIとAOPの仕組みを知るにはリフレクションを試すのがいいと思ってサンプルを準備してみました。
1. クラス名をもとにインスタンスを作れるか実験
まずはリフレクションを使うことでクラス情報をもとにインスタンスを制御できることを確認します。
package test;
public class Student {
public void print() {
System.err.println("うごいた");
}
}
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class TestRefect {
public static void main(String[] args) throws Exception {
// クラス名がわかるとクラス情報をつくれる
Class clazz = Class.forName("test.Student");
Constructor constructor = clazz.getConstructor(null);
// クラス情報がわかるとインスタンスがつくれる
Object taro = constructor.newInstance();
Method method = clazz.getMethod("print", null);
System.out.println("まえしょり");
// インスタンスを制御できるとメソッドが呼び出せる
method.invoke(taro, null);
System.out.println("あとしょり");
}
}
まえしょり
うごいた
あとしょり
2. メソッドが呼ばれたことを検知できるか実験
次に、インスタンスを制御できると、メソッドが呼ばれたことを検知して前後処理が仕込めることを確認します。
public interface SomeService {
public void someMethod();
}
class SomeServiceImpl implements SomeService {
public void someMethod() {
System.out.println("メソッドが呼ばれた: someMethod");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
class AOPHandler implements InvocationHandler {
private final Object target;
public AOPHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前処理: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("後処理: " + method.getName());
return result;
}
}
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
// クラス情報やインスタンスを登録しておく
SomeService target = new SomeServiceImpl();
SomeService proxy = (SomeService) Proxy.newProxyInstance(
SomeService.class.getClassLoader(),
new Class[]{SomeService.class},
new AOPHandler(target)
);
// メソッドの呼び出しを検知できる
proxy.someMethod();
}
}
処理: someMethod
メソッドが呼ばれた: someMethod
後処理: someMethod
3. まとめ
- DIにクラス情報を登録しておく
- 登録されたクラス情報をもとにインスタンスをつくる
- メソッドの実行をハンドリングし、呼ばれたメソッドの前後に処理を挟む
この2つのサンプルを確認によって、DIの仕組みが理解できると幸いです。