【Javaベース】エージェント-Proxy
5482 ワード
エージェントを使用すると、実行時に特定のインタフェースのセットを実装した新しいクラスを作成できます.この機能は、コンパイル時にどのインタフェースを実装する必要があるか分からない場合にのみ使用する必要があります.
エージェントクラスは、プログラムの実行中に作成されます.しかし、作成されると、通常のクラスになり、仮想マシン内の他のクラスと変わらない.
特定のクラス・ローダとプリセットのインタフェースのセットには、プロキシ・クラスは1つしかありません.すなわち,同じクラスローダとインタフェース配列を用いてnewProxyInstanceメソッドを2回呼び出すと,同じクラスの2つのオブジェクトしか得られない.
エージェントは実際にjava.lang.reflect.Proxyが指定したインタフェースに基づいて動的に生成するclass byteである.このクラスはProxyクラスを継承し、指定したすべてのインタフェース(interfacesパラメータ)を実装し、最後にチェックインしたclass loaderを使用してclass byteをシステムのようにロードし、このようなクラスのオブジェクトを生成します.
最後の例では、生成されたエージェントクラスの継承アーキテクチャおよび実装インタフェースが表示される.
エージェントクラス-Proxy
プロキシオブジェクトを作成するには、ProxyクラスのnewProxyInstanceメソッドを使用する必要があります.このメソッドには3つのパラメータがあります.
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.クラス・ローダ:Javaセキュリティ・モデルの一部として、システム・クラスとインターネットからダウンロードされたクラスに対して、異なるクラス・ローダを使用できます.nullを使用すると、デフォルトのクラス・ローダ(システム・クラスのローダ)が使用されます. Classオブジェクト配列で、各要素は実装する必要があるインタフェースです. 呼び出しプロセッサ.
呼び出しプロセッサ-InvocationHandler
Modifier and Type
Method and Description
Processes a method invocation on a proxy instance and returns the result.
このメソッドは、プロキシオブジェクトがメソッドを呼び出すときに実行するアクションを定義します.
エージェントクラスを呼び出すと、エージェントクラスはInvocationHandlerのinvokeメソッドのみを呼び出すので、実際に実装されるメソッドはinvokeメソッドで呼び出さなければなりません.
例
システムインタフェースエージェント
IntegerクラスはComparableインタフェースを実現した.
カスタムインタフェースエージェント
プロキシクラスの印刷
反射でクラス情報を印刷する方法を使用して、上記の例で生成したプロキシクラスの定義を確認します.
出力:
エージェントクラスは、プログラムの実行中に作成されます.しかし、作成されると、通常のクラスになり、仮想マシン内の他のクラスと変わらない.
特定のクラス・ローダとプリセットのインタフェースのセットには、プロキシ・クラスは1つしかありません.すなわち,同じクラスローダとインタフェース配列を用いてnewProxyInstanceメソッドを2回呼び出すと,同じクラスの2つのオブジェクトしか得られない.
エージェントは実際にjava.lang.reflect.Proxyが指定したインタフェースに基づいて動的に生成するclass byteである.このクラスはProxyクラスを継承し、指定したすべてのインタフェース(interfacesパラメータ)を実装し、最後にチェックインしたclass loaderを使用してclass byteをシステムのようにロードし、このようなクラスのオブジェクトを生成します.
最後の例では、生成されたエージェントクラスの継承アーキテクチャおよび実装インタフェースが表示される.
エージェントクラス-Proxy
public class Proxy extends Object implements Serializable (java.lang.reflect)
プロキシオブジェクトを作成するには、ProxyクラスのnewProxyInstanceメソッドを使用する必要があります.このメソッドには3つのパラメータがあります.
static Object
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
呼び出しプロセッサ-InvocationHandler
public interface InvocationHandler (java.lang.reflect)
Modifier and Type
Method and Description
Object
invoke(Object proxy, Method method, Object[] args)
Processes a method invocation on a proxy instance and returns the result.
このメソッドは、プロキシオブジェクトがメソッドを呼び出すときに実行するアクションを定義します.
エージェントクラスを呼び出すと、エージェントクラスはInvocationHandlerのinvokeメソッドのみを呼び出すので、実際に実装されるメソッドはinvokeメソッドで呼び出さなければなりません.
例
システムインタフェースエージェント
IntegerクラスはComparableインタフェースを実現した.
import java.util.*;
import java.lang.reflect.*;
public class ProxyTest {
public static void main(String[] args){
Object[] elements = new Object[100];
// fill elements with proxies for the integer
for (int i = 0; i < elements.length; i++){
Integer value = i + 1;
Class[] interfaces = value.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(null, interfaces, handler);
elements[i] = proxy;
}
// construct a random integer
Integer key = new Random().nextInt(elements.length) + 1;
// search for the key
int result = Arrays.binarySearch(elements, key);
if (result >= 0){
System.out.println(elements[result]);
}
}
}
class TraceHandler implements InvocationHandler{
private Object target;
public TraceHandler(Object t){
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
// print the invoked method info
System.out.print("Proxy invoke: ");
System.out.print(target);
System.out.print("." + m.getName() + "(");
if (args != null){
for (int i = 0; i < args.length; i++){
System.out.print(args[i]);
if (i < args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
カスタムインタフェースエージェント
import java.util.*;
import java.lang.reflect.*;
public class ProxyTest2 {
public static void main(String[] args){
TestClass testClass = new TestClass();
Class[] interfaces = testClass.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler2(testClass);
Object proxy = Proxy.newProxyInstance(testClass.getClass().getClassLoader(), interfaces, handler);
((TestInterface)proxy).test();
//((TestClass)proxy).test(); error; Proxy cannot be cast to TestClass
//((TestClass)proxy).test2(); error; Proxy cannot be cast to TestClass
}
}
interface TestInterface{
void test();
}
class TestClass implements TestInterface{
public void test(){
System.out.println("TestClass.test");
}
public void test2(){
System.out.println("TestClass.test2");
}
public String toString(){
return "TestClass Instance";
}
}
class TraceHandler2 implements InvocationHandler{
private Object target;
public TraceHandler2(Object t){
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
// print the invoked method info
System.out.print("Proxy invoke: ");
System.out.print(target);
System.out.print("." + m.getName() + "(");
if (args != null){
for (int i = 0; i < args.length; i++){
System.out.print(args[i]);
if (i < args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
プロキシクラスの印刷
反射でクラス情報を印刷する方法を使用して、上記の例で生成したプロキシクラスの定義を確認します.
public class ReflectionTest{
public static void main(String[] args){
TestClass testClass = new TestClass();
Class[] interfaces = testClass.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler2(testClass);
Object proxy = Proxy.newProxyInstance(testClass.getClass().getClassLoader(), interfaces, handler);
ClassAnalyzer.printClass(proxy.getClass());
}
}
出力: