反射の代わりに動的クラスを生成
4654 ワード
反射効率を高めるにはキャッシュを利用することができ、もう一つの方法は、ダイナミッククラスを生成する方法は直接メソッドを呼び出すことができ、性能は直接変調と同じで、反射の代わりにすることができる.
プラットフォームを作るには、反射やダイナミック生成クラス、汎用、などの特性を大量に使用すると、プラットフォームの汎用行を大幅に向上させ、多くのコードを節約するだけでなく、柔軟性が高く、性能を向上させ、コードも非常に優雅に見えます.
1,まず抽象クラスを定義する必要があります.なぜ抽象クラスを定義するのか.ターゲットオブジェクトの和関数を直接呼び出す必要があるので、明確に定義して参照しますか.
2、そして、エージェントMethodInvokerクラスを作成するための工場に向かいます.
説明すると、ここでは反射によって、ターゲットクラスのすべての方法、パラメータタイプ、パラメータ個数、戻り値タイプを分析し、入力された文字列に基づいてマッチングし、マッチングしたら直接その方法を呼び出すことができます.
たとえば,Userというクラスにとっては,このような動的メソッドが生成される.
私の意味はもう一目瞭然でしょう.ok、私たちは実際にjavassistでクラスと方法を生み出しました.このクラスはMethodInvoker抽象クラスを継承し、invoke方法を実現しました.次に、生成したクラスに基づいてオブジェクトをインスタンス化し、MethodInvokerリファレンスに強制的に変換するだけで、呼び出すことができます.
便利ではないでしょうか.注意、このinvokeメソッドは、呼び出された関数に戻り値がある場合はreturn、戻り値がない場合はnullを返します.それから入ってきたパラメータは順番にパラメータ配列を構築して、今のところ私のこの例はまだ配列パラメータと配列の戻りをサポートしていません.皆さんは改善することができます.invoke関数を生成する時、いくつかの特殊な状況を判断することに注意してください.
そして、MethodFactoryにプール化オブジェクトmapを追加することをお勧めします.このmethodInvokerを生成するにも時間がかかるので、これは通用するので、保存したほうがいいです.本当の意味で性能を向上させることができます.
パフォーマンステストをしました
ダイレクトコールダイレクトコール:ダイナミックジェネレーションコールダイナミックジェネレーションコール:反射=1:1:30
プラットフォームを作るには、反射やダイナミック生成クラス、汎用、などの特性を大量に使用すると、プラットフォームの汎用行を大幅に向上させ、多くのコードを節約するだけでなく、柔軟性が高く、性能を向上させ、コードも非常に優雅に見えます.
1,まず抽象クラスを定義する必要があります.なぜ抽象クラスを定義するのか.ターゲットオブジェクトの和関数を直接呼び出す必要があるので、明確に定義して参照しますか.
public abstract class MethodInvoker {
public abstract Object invoke(Object instance, String method,Object[] params);
}
2、そして、エージェントMethodInvokerクラスを作成するための工場に向かいます.
public class InvokerFactory {
public static MethodInvoker createInvoker(Class clazz) throws Exception{
Method[] methods = clazz.getDeclaredMethods();
String className = clazz.getName();
//
ClassPool pool = ClassPool.getDefault();
CtClass methodInvoker = pool.makeClass("test.MethodInvokerImpl",pool.getCtClass("test.MethodInvoker"));
String methodString = "public Object invoke(Object instance, String method,Object[] params)
"
+ "{
"
+ " if(method==null||method==\"\")
"
+ " return null;
" ;
//
for(int i=0;i<methods.length;i++){
Method method = methods[i];
Class returnType = method.getReturnType();
String methodName = method.getName();
int paramCount = method.getParameterCount();
Class[] parameterTypes = method.getParameterTypes();
methodString = methodString + " if(method.equals(\""+methodName+"\"))
";
if(returnType.getName().equals("void")){
methodString = methodString + " {
";
methodString = methodString + " (("+className+")instance)."+methodName+"(";
}
else
methodString = methodString + " return (("+className+")instance)."+methodName+"(";
for(int j=0;j<paramCount;j++){
Class cls = parameterTypes[j];
methodString = methodString +"("+cls.getName()+")params["+j+"]";
if((j+1)<paramCount)
methodString = methodString +",";
}
methodString = methodString +");
";
if(returnType.getName().equals("void")){
methodString = methodString + " return null;
";
methodString = methodString + " }
";
}
}
methodString = methodString + " return null;
"
+ "}
";
//
methodInvoker.addMethod(CtNewMethod.make(methodString, methodInvoker));
//
Object instance = methodInvoker.toClass().newInstance();
MethodInvoker invoker = (MethodInvoker)instance;
return invoker;
}
}
説明すると、ここでは反射によって、ターゲットクラスのすべての方法、パラメータタイプ、パラメータ個数、戻り値タイプを分析し、入力された文字列に基づいてマッチングし、マッチングしたら直接その方法を呼び出すことができます.
たとえば,Userというクラスにとっては,このような動的メソッドが生成される.
public Object invoke(Object instance, String method,Object[] params)
{
if(method==null||method=="")
return null;
if(method.equals("setUsername"))
{
((test.User)instance).setUsername((java.lang.String)params[0]);
return null;
}
if(method.equals("getUsername"))
return ((test.User)instance).getUsername();
if(method.equals("getPassword"))
return ((test.User)instance).getPassword();
if(method.equals("setPassword"))
{
((test.User)instance).setPassword((java.lang.String)params[0]);
return null;
}
return null;
}
私の意味はもう一目瞭然でしょう.ok、私たちは実際にjavassistでクラスと方法を生み出しました.このクラスはMethodInvoker抽象クラスを継承し、invoke方法を実現しました.次に、生成したクラスに基づいてオブジェクトをインスタンス化し、MethodInvokerリファレンスに強制的に変換するだけで、呼び出すことができます.
// ,
public static void main(String[] args) throws Exception {
User user = new User();
MethodInvoker invoker = InvokerFactory.createInvoker(user.getClass());
Object[] array = {"xingzai"};
invoker.invoke(user, "setUsername",array );
}
便利ではないでしょうか.注意、このinvokeメソッドは、呼び出された関数に戻り値がある場合はreturn、戻り値がない場合はnullを返します.それから入ってきたパラメータは順番にパラメータ配列を構築して、今のところ私のこの例はまだ配列パラメータと配列の戻りをサポートしていません.皆さんは改善することができます.invoke関数を生成する時、いくつかの特殊な状況を判断することに注意してください.
そして、MethodFactoryにプール化オブジェクトmapを追加することをお勧めします.このmethodInvokerを生成するにも時間がかかるので、これは通用するので、保存したほうがいいです.本当の意味で性能を向上させることができます.
パフォーマンステストをしました
ダイレクトコールダイレクトコール:ダイナミックジェネレーションコールダイナミックジェネレーションコール:反射=1:1:30