ダイナミックエージェント実装の3つの方法

11583 ワード

動的エージェント実装には、jdk動的エージェント(インタフェースベース)、cglib動的エージェント(継承ベース)、javassist(hibernateで使用)の3つの方法があります.
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では多く継承できないからです.