ダイナミックエージェント実装の3つの方法
11583 ワード
動的エージェント実装には、jdk動的エージェント(インタフェースベース)、cglib動的エージェント(継承ベース)、javassist(hibernateで使用)の3つの方法があります.
jdk動的エージェントの実装
テスト
出力:say前wang wang wang!say後
生成されたバイトコードファイルの逆コンパイル後
生成されたエージェントクラスはProxyクラスを継承していることがわかります.これもjdkダイナミックエージェントがインタフェースに基づいてのみ継承に基づいてダイナミックエージェントを実現できない理由です.javaでは多く継承できないからです.
jdk動的エージェントの実装
package com.lzzl.jdkproxy;
public interface Pet {
public void say();
}
package com.lzzl.jdkproxy;
public class Dog implements Pet{
public void say(){
System.out.println("wang wang wang !");
}
}
package com.lzzl.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory implements InvocationHandler{
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result;
if(proxy instanceof Pet){
if("say".equals(method.getName())){
System.out.println(" say ");
result = method.invoke(target, args);
System.out.println(" say ");
return result;
}
}
return method.invoke(target, args);
}
public Object createProxy(){
Class[] interfaces = target.getClass().getInterfaces();
if(interfaces.length==0){
System.out.println(" , jdk ");
throw new RuntimeException(" , jdk ");
}
return Proxy.newProxyInstance(ProxyFactory.class.getClassLoader(), interfaces, this);
}
}
テスト
package com.lzzl.jdkproxy;
import java.io.FileOutputStream;
import java.io.OutputStream;
import sun.misc.ProxyGenerator;
public class runjdkproxytest {
public static void main(String[] args) throws Exception{
Dog dog = new Dog();
ProxyFactory proxyfc = new ProxyFactory();
proxyfc.setTarget(dog);
Pet proxy = (Pet) proxyfc.createProxy();
proxy.say();
//
byte[] bts = ProxyGenerator.generateProxyClass("DogProxy", new Class[]{Pet.class});
OutputStream out = new FileOutputStream("E:\\work\\myeclipsework\\DynamicProxy\\generateFile\\DogProxy.class");
out.write(bts);
}
}
出力:say前wang wang wang!say後
生成されたバイトコードファイルの逆コンパイル後
import com.lzzl.jdkproxy.Pet;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class DogProxy extends Proxy
implements Pet
{
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;
public DogProxy(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final void say()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m3 = Class.forName("com.lzzl.jdkproxy.Pet").getMethod("say", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
生成されたエージェントクラスはProxyクラスを継承していることがわかります.これもjdkダイナミックエージェントがインタフェースに基づいてのみ継承に基づいてダイナミックエージェントを実現できない理由です.javaでは多く継承できないからです.