エージェントモード-CGLIBダイナミックエージェント


1.JDK                ,Cglib         。
2.JDK Cglib           ,JDK    Class   ,Cglib  ASM   Class   ,Cglib       ,      JDK   。
3.JDK      ,         ,Cglib   FastClass        。

CGLIBダイナミックエージェント:
JDKのProxy実装エージェントを使用して,ターゲットクラスとエージェントクラスが同じインタフェースを実装することを要求する.ターゲットクラスにインタフェースが存在しない場合は、この方法では実現できません.
ただし、インタフェースのないクラスでは、動的エージェントクラスを作成するには、CGLIBを使用して実装します.CGLIBエージェントの生成原理はターゲットクラスのサブクラスを生成することであり,サブクラスは強化されており,このサブクラスオブジェクトがエージェントオブジェクトである.したがって,CGLIBを用いて動的エージェントを生成するには,ターゲットクラスが継承可能であること,すなわちfinalのクラスではないことが要求される.
CGLIB(Code GenerationLibrary)はオープンソースプロジェクトであり、強力で高性能で高品質なコード生成クラスライブラリである.実行期間中にJavaクラスを拡張することができます.Hibernateはそれを用いて永続オブジェクトのバイトコードの動的生成を実現し,Springはそれを用いてAOPプログラミングを実現する.
CGLIBパケットの下位層は、小さな高速バイトコード処理フレームワークASM(Javaバイトコード操作フレームワーク)を用いてバイトコードを変換し、新しいクラスを生成する.CGLIBは、バイトコードを強化することによってエージェントを生成する.
エージェントの実装と解析:
CGLIBを使用してプロキシを作成する手順は、次のとおりです.
ステップ1:CGLIBのJarパッケージ:cglib-fullをインポートする.jar.
手順2:ターゲットクラスを定義します.注意インタフェースは実装されません.
public class AccountService {
	//    
	public void transfer(){
		System.out.println("  Dao ,       。");
	}
	//    
	public void getBalance(){
		System.out.println("  Dao ,         。");
	}
	
	//          ,Cglib     final      
	final public void others() {
		System.out.println("  Dao ,       。");
	}
	
}

手順3:エージェントクラスのファクトリを作成します.このクラスはMethodInterceptorインタフェースを実装します.
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

//   MethodInterceptor
public class CglibProxyDemo implements MethodInterceptor {
    /*
     * All generated proxied methods call this method instead of the original method. The original method may either be invoked by normal reflection using the Method object, or by using the MethodProxy (faster).     
     * @param obj "this", the enhanced object     
     * @param method intercepted Method     * @param args argument array; primitive types are wrapped     
     * @param proxy used to invoke super (non-intercepted method); may be called as many times as needed     
     * @throws Throwable any exception may be thrown; if so, super method will not be invoked     
     * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.     
     * @see MethodProxy
     * 
     * intercept()         
     * proxy:    ;       ,             ,cglib       ;
     * method:        
     * args[]:    ;       
     * methodProxy:           
     * */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		
		System.out.println("=========  CGLIB  =========");
		
		Object result = null;
		//   transfer  ,     
		if("transfer".equals(method.getName())){
			System.out.println("===      :" + System.currentTimeMillis());
			result = methodProxy.invokeSuper(proxy, args);
			System.out.println("===      :" + System.currentTimeMillis());
			return result;
		}
		return methodProxy.invokeSuper(proxy, args);
	}
}

手順4:テストクラスを作成します.
import net.sf.cglib.core.DebuggingClassWriter;
import java.io.IOException;
import net.sf.cglib.proxy.Enhancer;
import com.proxyDemo.cglibProxy.service.TargetService;
import com.proxyDemo.cglibProxy.service.CglibProxyDemo;

public class CglibMainDemo {
	public static void main(String[] args) throws IOException {
		//    class                   
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
		
		//     
    	Enhancer enhancer = new Enhancer();
    	//      :         
    	enhancer.setSuperclass(new TargetService().getClass());
    	//      :    
    	enhancer.setCallback(new CglibProxyDemo());
    	//  Enhancer.create()        
    	TargetService service = (TargetService) enhancer.create();
    	//            
    	service.transfer();
    	service.getBalance();
		service.others();
	}
}

生成されたプロキシオブジェクトの逆コンパイル後のコードを表示します.
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TargetService$$EnhancerByCGLIB$$bde35d74 extends TargetService
  implements Factory
{
  private boolean CGLIB$BOUND;
  private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
  private static Callback[] CGLIB$DEFAULT_CALLBACKS;
  private MethodInterceptor CGLIB$CALLBACK_0;
  private static final Method CGLIB$transfer$0$0$Method;
  private static final MethodProxy CGLIB$transfer$0$0$Proxy;
  private static final Object[] CGLIB$emptyArgs;
  private static final Method CGLIB$getBalance$0$1$Method;
  private static final MethodProxy CGLIB$getBalance$0$1$Proxy;
  private static final Method CGLIB$finalize$0$2$Method;
  private static final MethodProxy CGLIB$finalize$0$2$Proxy;
  private static final Method CGLIB$equals$0$3$Method;
  private static final MethodProxy CGLIB$equals$0$3$Proxy;
  private static final Method CGLIB$toString$0$4$Method;
  private static final MethodProxy CGLIB$toString$0$4$Proxy;
  private static final Method CGLIB$hashCode$0$5$Method;
  private static final MethodProxy CGLIB$hashCode$0$5$Proxy;
  private static final Method CGLIB$clone$0$6$Method;
  private static final MethodProxy CGLIB$clone$0$6$Proxy;

  static void CGLIB$STATICHOOK1()
  {
    CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    Class localClass;
    CGLIB$emptyArgs = new Object[0];
    ClassLoader tmp27_17 = (localClass = Class.forName("com.proxyDemo.cglibProxy.service.TargetService$$EnhancerByCGLIB$$bde35d74")).getClassLoader();
    CGLIB$transfer$0$0$Proxy = MethodProxy.create(tmp27_17, (bde35d74.CGLIB$transfer$0$0$Method = Class.forName("com.proxyDemo.cglibProxy.service.TargetService").getDeclaredMethod("transfer", new Class[0])).getDeclaringClass(), localClass, "()V", "transfer", "CGLIB$transfer$0$0");
    ClassLoader tmp62_27 = tmp27_17;
    CGLIB$getBalance$0$1$Proxy = MethodProxy.create(tmp62_27, (bde35d74.CGLIB$getBalance$0$1$Method = Class.forName("com.proxyDemo.cglibProxy.service.TargetService").getDeclaredMethod("getBalance", new Class[0])).getDeclaringClass(), localClass, "()V", "getBalance", "CGLIB$getBalance$0$1");
    ClassLoader tmp97_62 = tmp62_27;
    CGLIB$finalize$0$2$Proxy = MethodProxy.create(tmp97_62, (bde35d74.CGLIB$finalize$0$2$Method = Class.forName("java.lang.Object").getDeclaredMethod("finalize", new Class[0])).getDeclaringClass(), localClass, "()V", "finalize", "CGLIB$finalize$0$2");
    ClassLoader tmp132_97 = tmp97_62;
    CGLIB$equals$0$3$Proxy = MethodProxy.create(tmp132_97, (bde35d74.CGLIB$equals$0$3$Method = Class.forName("java.lang.Object").getDeclaredMethod("equals", new Class[] { Class.forName("java.lang.Object") })).getDeclaringClass(), localClass, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$0$3");
    ClassLoader tmp175_132 = tmp132_97;
    CGLIB$toString$0$4$Proxy = MethodProxy.create(tmp175_132, (bde35d74.CGLIB$toString$0$4$Method = Class.forName("java.lang.Object").getDeclaredMethod("toString", new Class[0])).getDeclaringClass(), localClass, "()Ljava/lang/String;", "toString", "CGLIB$toString$0$4");
    ClassLoader tmp210_175 = tmp175_132;
    CGLIB$hashCode$0$5$Proxy = MethodProxy.create(tmp210_175, (bde35d74.CGLIB$hashCode$0$5$Method = Class.forName("java.lang.Object").getDeclaredMethod("hashCode", new Class[0])).getDeclaringClass(), localClass, "()I", "hashCode", "CGLIB$hashCode$0$5");
    CGLIB$clone$0$6$Proxy = MethodProxy.create(tmp210_175, (bde35d74.CGLIB$clone$0$6$Method = Class.forName("java.lang.Object").getDeclaredMethod("clone", new Class[0])).getDeclaringClass(), localClass, "()Ljava/lang/Object;", "clone", "CGLIB$clone$0$6");
    return;
  }

  final void CGLIB$transfer$0$0()
  {
    super.transfer();
  }

  public final void transfer()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null)
      return;
    super.transfer();
  }
      ......
  public final void getBalance()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null)
      return;
    super.getBalance();
  }
      ......
      ......
  static
  {
    CGLIB$STATICHOOK1();
  }
}

プロキシオブジェクトからソースコードを逆コンパイルすると、プロキシオブジェクトがTargetServiceに継承されていることがわかります.
あなたに役に立つことを望んで、あなたが1つの良い気持ちがあることを祈って、頑張ります!
誤り、不完全、最適化可能な点があれば、是正と補充を歓迎します.