CGLIB代理使用与原理详解

CGLIB代理使用与原理详解JDK中提供的生成动态代理类的机制有个鲜明的特点是:某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法。那么如果一个类没有实现接口怎么办呢?这就有CGLIB的诞生了,前面说的JDK的动态代理的实现方式是实现相关的接口成为接口的实现类,那么我们自然可以想到用继承的方式实现相关的代理类。【1】CGLIB简单实现①pom依赖如下<!–https://…

大家好,又见面了,我是你们的朋友全栈君。

相关博文
Java中动态代理使用与原理详解
Java中静态代理使用与原理详解

【1】CGLIB概述

① Cglib代理

静态代理和JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是Cglib 代理。

JDK中提供的生成动态代理类的机制有个鲜明的特点是:

  • 某个类必须有实现的接口
  • 生成的代理类也只能代理某个类接口定义的方法。

那么如果一个类没有实现接口怎么办呢?

这就有CGLIB的诞生了,前面说的JDK的动态代理的实现方式是实现相关的接口成为接口的实现类,那么我们自然可以想到用继承的方式实现相关的代理类。

Cglib 代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib 代理归属到动态代理。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final, static方法,private方法,final方法是不能被代理的

Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展java 类与实现java 接口.它广泛的被许多AOP 的框架使用,例如Spring AOP,实现方法拦截。

在AOP 编程中如何选择代理模式:

  • 目标对象需要实现接口,用JDK 代理
  • 目标对象不需要实现接口,用Cglib 代理

Cglib 包的底层是通过使用字节码处理框架ASM 来转换字节码并生成新的类


② 应用案例

pom依赖

 <!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.5</version>
</dependency>

JDK动态代理的代码基础上进行修改

① 测试客户端

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TestCglibProxy { 
   
	
	public static void main(String[] args) { 
   
		//创建一个被代理类的对象
		SuperMan man = new SuperMan();
		CGLibProxy cgLibProxy = new CGLibProxy();
		//返回一个代理类的对象--注意这里现在传入的是实现类
		Object obj = cgLibProxy.getProxyInstance(man);
		System.out.println(obj.getClass());
		//class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
		Human hu = (Human)obj;
		//通过代理类的对象调用重写的抽象方法
		hu.info();
		
		System.out.println();
		
		hu.fly();
	}
}

② 自定义CGLibProxy

class CGLibProxy implements MethodInterceptor { 
     
  
	 // CGLib需要代理的目标对象 
    private Object targetObject;
  
    public Object getProxyInstance(Object obj) { 
     
        this.targetObject = obj;  
        //1. 创建一个工具类
        Enhancer enhancer = new Enhancer();  
        // 2.设置父类--可以是类或者接口
        enhancer.setSuperclass(obj.getClass());  
        //3. 设置回调函数
        enhancer.setCallback(this);  
        //4. 创建子类对象,即代理对象
        Object proxyObj = enhancer.create();  
        // 返回代理对象 
        return proxyObj;
    }  
  
    public Object intercept(Object proxy, Method method, Object[] args,  
            MethodProxy methodProxy) throws Throwable { 
     
        Object obj = null;  
        //模拟功能增强
        HumanUtil humanUtil = new HumanUtil();
        humanUtil.method1();
        // 执行目标目标对象方法
        obj = method.invoke(targetObject, args);
        //模拟功能增强
        humanUtil.method2();
        return obj;  
    }  
}

HumanUtil 如下:

class HumanUtil { 
   
	public void method1() { 
   
		System.out.println("=======方法一=======");
	}

	public void method2() { 
   
		System.out.println("=======方法二=======");
	}
}

测试结果

如下所示:

class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
=======方法一=======
我是超人!我怕谁!
=======方法二=======

=======方法一=======
I believe I can fly!
=======方法二=======

【2】获取代理类源码

有了源码才好分析验证cglib生成的代理类究竟是个什么样子?这里主要用到下面代码:

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);

修改上面的main方法如下:

public static void main(String[] args) { 
   
		SuperMan man = new SuperMan();//创建一个被代理类的对象

		// 添加如下代码,获取代理类源文件
		String path = CGLibProxy.class.getResource(".").getPath();  
		System.out.println(path);
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
		
		CGLibProxy cgLibProxy = new CGLibProxy();
		Object obj = cgLibProxy.bind(man);//返回一个代理类的对象
		System.out.println(obj.getClass());
		//class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
		Human hu = (Human)obj;
		hu.info();//通过代理类的对象调用重写的抽象方法
		
		System.out.println();
		
		hu.fly();
	}

测试结果如下:

这里写图片描述


生成的代理类名字SuperMan$$EnhancerByCGLIB$$3be74240,源码如下:

可以直接在http://javare.cn/网站下在线反编译。

package com.web.test;

import com.web.test.SuperMan;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
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 SuperMan$$EnhancerByCGLIB$$3be74240 extends SuperMan implements Factory { 
   

   private boolean CGLIB$BOUND;
   public static Object CGLIB$FACTORY_DATA;
   private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
   private static final Callback[] CGLIB$STATIC_CALLBACKS;
   private MethodInterceptor CGLIB$CALLBACK_0;
   private static Object CGLIB$CALLBACK_FILTER;
   private static final Method CGLIB$info$0$Method;
   private static final MethodProxy CGLIB$info$0$Proxy;
   private static final Object[] CGLIB$emptyArgs;
   private static final Method CGLIB$fly$1$Method;
   private static final MethodProxy CGLIB$fly$1$Proxy;
   private static final Method CGLIB$equals$2$Method;
   private static final MethodProxy CGLIB$equals$2$Proxy;
   private static final Method CGLIB$toString$3$Method;
   private static final MethodProxy CGLIB$toString$3$Proxy;
   private static final Method CGLIB$hashCode$4$Method;
   private static final MethodProxy CGLIB$hashCode$4$Proxy;
   private static final Method CGLIB$clone$5$Method;
   private static final MethodProxy CGLIB$clone$5$Proxy;
// 一系列私有静态常量定义


// 常量初始化
   static void CGLIB$STATICHOOK1() { 
   
      CGLIB$THREAD_CALLBACKS = new ThreadLocal();
      CGLIB$emptyArgs = new Object[0];
      Class var0 = Class.forName("com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240");
      Class var1;
      Method[] var10000 = ReflectUtils.findMethods(new String[]{ 
   "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
      CGLIB$equals$2$Method = var10000[0];
      CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
      CGLIB$toString$3$Method = var10000[1];
      CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
      CGLIB$hashCode$4$Method = var10000[2];
      CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
      CGLIB$clone$5$Method = var10000[3];
      CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
      var10000 = ReflectUtils.findMethods(new String[]{ 
   "info", "()V", "fly", "()V"}, (var1 = Class.forName("com.web.test.SuperMan")).getDeclaredMethods());
      CGLIB$info$0$Method = var10000[0];
      CGLIB$info$0$Proxy = MethodProxy.create(var1, var0, "()V", "info", "CGLIB$info$0");
      CGLIB$fly$1$Method = var10000[1];
      CGLIB$fly$1$Proxy = MethodProxy.create(var1, var0, "()V", "fly", "CGLIB$fly$1");
   }

//绑定MethodInterceptor callback的方法会额外实现一个和原方法一模一样的方法
   final void CGLIB$info$0() { 
   
      super.info();
   }

// 代理对象的方法调用将会转发到代理对象的intercept方法
   public final void info() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$info$0$Method, CGLIB$emptyArgs, CGLIB$info$0$Proxy);
      } else { 
   
         super.info();
      }
   }

   final void CGLIB$fly$1() { 
   
      super.fly();
   }

   public final void fly() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$fly$1$Method, CGLIB$emptyArgs, CGLIB$fly$1$Proxy);
      } else { 
   
         super.fly();
      }
   }

   final boolean CGLIB$equals$2(Object var1) { 
   
      return super.equals(var1);
   }

   public final boolean equals(Object var1) { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{ 
   var1}, CGLIB$equals$2$Proxy);
         return var2 == null?false:((Boolean)var2).booleanValue();
      } else { 
   
         return super.equals(var1);
      }
   }

   final String CGLIB$toString$3() { 
   
      return super.toString();
   }

   public final String toString() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy):super.toString();
   }

   final int CGLIB$hashCode$4() { 
   
      return super.hashCode();
   }

   public final int hashCode() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
         return var1 == null?0:((Number)var1).intValue();
      } else { 
   
         return super.hashCode();
      }
   }

   final Object CGLIB$clone$5() throws CloneNotSupportedException { 
   
      return super.clone();
   }

   protected final Object clone() throws CloneNotSupportedException { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      return var10000 != null?var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy):super.clone();
   }

// 获取方法的 MethodProxy
   public static MethodProxy CGLIB$findMethodProxy(Signature var0) { 
   
      String var10000 = var0.toString();
      switch(var10000.hashCode()) { 
   
      case -1271409118:
         if(var10000.equals("fly()V")) { 
   
            return CGLIB$fly$1$Proxy;
         }
         break;
      case -508378822:
         if(var10000.equals("clone()Ljava/lang/Object;")) { 
   
            return CGLIB$clone$5$Proxy;
         }
         break;
      case 1826985398:
         if(var10000.equals("equals(Ljava/lang/Object;)Z")) { 
   
            return CGLIB$equals$2$Proxy;
         }
         break;
      case 1913648695:
         if(var10000.equals("toString()Ljava/lang/String;")) { 
   
            return CGLIB$toString$3$Proxy;
         }
         break;
      case 1945358343:
         if(var10000.equals("info()V")) { 
   
            return CGLIB$info$0$Proxy;
         }
         break;
      case 1984935277:
         if(var10000.equals("hashCode()I")) { 
   
            return CGLIB$hashCode$4$Proxy;
         }
      }

      return null;
   }

	//无参构造器
   public SuperMan$$EnhancerByCGLIB$$3be74240() { 
   
      CGLIB$BIND_CALLBACKS(this);
   }

   public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { 
   
      CGLIB$THREAD_CALLBACKS.set(var0);
   }

   public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { 
   
      CGLIB$STATIC_CALLBACKS = var0;
   }

   private static final void CGLIB$BIND_CALLBACKS(Object var0) { 
   
      SuperMan$$EnhancerByCGLIB$$3be74240 var1 = (SuperMan$$EnhancerByCGLIB$$3be74240)var0;
      if(!var1.CGLIB$BOUND) { 
   
         var1.CGLIB$BOUND = true;
         Object var10000 = CGLIB$THREAD_CALLBACKS.get();
         if(var10000 == null) { 
   
            var10000 = CGLIB$STATIC_CALLBACKS;
            if(CGLIB$STATIC_CALLBACKS == null) { 
   
               return;
            }
         }

         var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
      }

   }

   public Object newInstance(Callback[] var1) { 
   
      CGLIB$SET_THREAD_CALLBACKS(var1);
      SuperMan$$EnhancerByCGLIB$$3be74240 var10000 = new SuperMan$$EnhancerByCGLIB$$3be74240();
      CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
      return var10000;
   }

   public Object newInstance(Callback var1) { 
   
      CGLIB$SET_THREAD_CALLBACKS(new Callback[]{ 
   var1});
      SuperMan$$EnhancerByCGLIB$$3be74240 var10000 = new SuperMan$$EnhancerByCGLIB$$3be74240();
      CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
      return var10000;
   }

   public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { 
   
      CGLIB$SET_THREAD_CALLBACKS(var3);
      SuperMan$$EnhancerByCGLIB$$3be74240 var10000 = new SuperMan$$EnhancerByCGLIB$$3be74240;
      switch(var1.length) { 
   
      case 0:
         var10000.<init>();
         CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
         return var10000;
      default:
         throw new IllegalArgumentException("Constructor not found");
      }
   }

   public Callback getCallback(int var1) { 
   
      CGLIB$BIND_CALLBACKS(this);
      MethodInterceptor var10000;
      switch(var1) { 
   
      case 0:
         var10000 = this.CGLIB$CALLBACK_0;
         break;
      default:
         var10000 = null;
      }

      return var10000;
   }

   public void setCallback(int var1, Callback var2) { 
   
      switch(var1) { 
   
      case 0:
         this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
      default:
      }
   }

   public Callback[] getCallbacks() { 
   
      CGLIB$BIND_CALLBACKS(this);
      return new Callback[]{ 
   this.CGLIB$CALLBACK_0};
   }

// 初始化定义的callback
   public void setCallbacks(Callback[] var1) { 
   
      this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
   }

// 这里,类加载的时候首先执行!!!
   static { 
   
      CGLIB$STATICHOOK1();
   }
}

可以发现这个类继承自接口实现类–SuperMan,其在加载的时候会先进行一系列静态常量的初始化且在实例化的时候调用CGLIB$BIND_CALLBACKS(this);进行call back的绑定。

那么现在的情况就是我们的生成了一个代理类,这个代理类是我们需要代理的实现类的继承类。我们的被代理类的方法在这个代理类中帮我们重写了,并且全部变成了final的。同时覆盖了一些Object类中的方法。

info这个方法举例,方法中会调用MethodInterceptor类中的intercept方法(也就是我们实现的逻辑的地方),同时把自己的Method对象,参数列表等传入进去。


【3】两个小问题


如果代理的目标对象为接口行不行?·

接口中的方法代理类实现了,那么类中自定义的方法代理类是否也可以实现?

毫无疑问,cglib是基于类的动态代理,代理类继承自目标类,类中的方法除了final自然可以继承

① 传入接口为代理对象进行测试

public class TestCglibProxy2 { 
   
	
	public static void main(String[] args) { 
   
		String path = CGLibProxy.class.getResource(".").getPath();  
		System.out.println(path);
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
		CGLibProxy2 cgLibProxy = new CGLibProxy2();
		//返回一个代理类的对象--这里直接传入Human接口 Class!!!
		Object obj = cgLibProxy.getProxyInstance(Human.class);
		System.out.println(obj.getClass());
		//class com.web.test.Human$$EnhancerByCGLIB$$9fc9106
		Human hu = (Human)obj;
		hu.info();//通过代理类的对象调用重写的抽象方法
		
		System.out.println();
		
		hu.fly();
	}
}

class CGLibProxy2 implements MethodInterceptor { 
     
  
    public Object getProxyInstance(Class<?> obj) { 
     
        Enhancer enhancer = new Enhancer();  
        // 这里传入Class
        enhancer.setSuperclass(obj);  
        enhancer.setCallback(this);  
        Object proxyObj = enhancer.create();  
        return proxyObj;// 返回代理对象 
    }  
  
    public Object intercept(Object proxy, Method method, Object[] args,  
            MethodProxy methodProxy) throws Throwable { 
     
        Object obj = null;  
        //模拟功能增强
        HumanUtil humanUtil = new HumanUtil();
        humanUtil.method1();
        // 执行目标目标对象方法--这里直接传入目标对象
        obj = method.invoke(new SuperMan(), args);
        //模拟功能增强
        humanUtil.method2();
        return obj;  
    }  
}

测试结果如下图:

这里写图片描述


此时生成的源码Human$$EnhancerByCGLIB$$9fc9106如下所示:

package com.web.test;

import com.web.test.Human;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
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;
//注意,这里变为了实现Human接口形式
public class Human$$EnhancerByCGLIB$$9fc9106 implements Human, Factory { 
   

   private boolean CGLIB$BOUND;
   public static Object CGLIB$FACTORY_DATA;
   private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
   private static final Callback[] CGLIB$STATIC_CALLBACKS;
   private MethodInterceptor CGLIB$CALLBACK_0;
   private static Object CGLIB$CALLBACK_FILTER;
   private static final Method CGLIB$equals$0$Method;
   private static final MethodProxy CGLIB$equals$0$Proxy;
   private static final Object[] CGLIB$emptyArgs;
   private static final Method CGLIB$toString$1$Method;
   private static final MethodProxy CGLIB$toString$1$Proxy;
   private static final Method CGLIB$hashCode$2$Method;
   private static final MethodProxy CGLIB$hashCode$2$Proxy;
   private static final Method CGLIB$clone$3$Method;
   private static final MethodProxy CGLIB$clone$3$Proxy;
   private static final Method CGLIB$info$4$Method;
   private static final MethodProxy CGLIB$info$4$Proxy;
   private static final Method CGLIB$fly$5$Method;
   private static final MethodProxy CGLIB$fly$5$Proxy;


   static void CGLIB$STATICHOOK1() { 
   
      CGLIB$THREAD_CALLBACKS = new ThreadLocal();
      CGLIB$emptyArgs = new Object[0];
      Class var0 = Class.forName("com.web.test.Human$$EnhancerByCGLIB$$9fc9106");
      Class var1;
      Method[] var10000 = ReflectUtils.findMethods(new String[]{ 
   "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
      CGLIB$equals$0$Method = var10000[0];
      CGLIB$equals$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$0");
      CGLIB$toString$1$Method = var10000[1];
      CGLIB$toString$1$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$1");
      CGLIB$hashCode$2$Method = var10000[2];
      CGLIB$hashCode$2$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$2");
      CGLIB$clone$3$Method = var10000[3];
      CGLIB$clone$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$3");
      var10000 = ReflectUtils.findMethods(new String[]{ 
   "info", "()V", "fly", "()V"}, (var1 = Class.forName("com.web.test.Human")).getDeclaredMethods());
      CGLIB$info$4$Method = var10000[0];
      CGLIB$info$4$Proxy = MethodProxy.create(var1, var0, "()V", "info", "CGLIB$info$4");
      CGLIB$fly$5$Method = var10000[1];
      CGLIB$fly$5$Proxy = MethodProxy.create(var1, var0, "()V", "fly", "CGLIB$fly$5");
   }

   final boolean CGLIB$equals$0(Object var1) { 
   
      return super.equals(var1);
   }

   public final boolean equals(Object var1) { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         Object var2 = var10000.intercept(this, CGLIB$equals$0$Method, new Object[]{ 
   var1}, CGLIB$equals$0$Proxy);
         return var2 == null?false:((Boolean)var2).booleanValue();
      } else { 
   
         return super.equals(var1);
      }
   }

   final String CGLIB$toString$1() { 
   
      return super.toString();
   }

   public final String toString() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$1$Method, CGLIB$emptyArgs, CGLIB$toString$1$Proxy):super.toString();
   }

   final int CGLIB$hashCode$2() { 
   
      return super.hashCode();
   }

   public final int hashCode() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         Object var1 = var10000.intercept(this, CGLIB$hashCode$2$Method, CGLIB$emptyArgs, CGLIB$hashCode$2$Proxy);
         return var1 == null?0:((Number)var1).intValue();
      } else { 
   
         return super.hashCode();
      }
   }

   final Object CGLIB$clone$3() throws CloneNotSupportedException { 
   
      return super.clone();
   }

   protected final Object clone() throws CloneNotSupportedException { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      return var10000 != null?var10000.intercept(this, CGLIB$clone$3$Method, CGLIB$emptyArgs, CGLIB$clone$3$Proxy):super.clone();
   }

   final void CGLIB$info$4() { 
   
      super.info();
   }

   public final void info() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$info$4$Method, CGLIB$emptyArgs, CGLIB$info$4$Proxy);
      } else { 
   
         super.info();
      }
   }

   final void CGLIB$fly$5() { 
   
      super.fly();
   }

   public final void fly() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$fly$5$Method, CGLIB$emptyArgs, CGLIB$fly$5$Proxy);
      } else { 
   
         super.fly();
      }
   }

   public static MethodProxy CGLIB$findMethodProxy(Signature var0) { 
   
      String var10000 = var0.toString();
      switch(var10000.hashCode()) { 
   
      case -1271409118:
         if(var10000.equals("fly()V")) { 
   
            return CGLIB$fly$5$Proxy;
         }
         break;
      case -508378822:
         if(var10000.equals("clone()Ljava/lang/Object;")) { 
   
            return CGLIB$clone$3$Proxy;
         }
         break;
      case 1826985398:
         if(var10000.equals("equals(Ljava/lang/Object;)Z")) { 
   
            return CGLIB$equals$0$Proxy;
         }
         break;
      case 1913648695:
         if(var10000.equals("toString()Ljava/lang/String;")) { 
   
            return CGLIB$toString$1$Proxy;
         }
         break;
      case 1945358343:
         if(var10000.equals("info()V")) { 
   
            return CGLIB$info$4$Proxy;
         }
         break;
      case 1984935277:
         if(var10000.equals("hashCode()I")) { 
   
            return CGLIB$hashCode$2$Proxy;
         }
      }

      return null;
   }

   public Human$$EnhancerByCGLIB$$9fc9106() { 
   
      CGLIB$BIND_CALLBACKS(this);
   }

   public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { 
   
      CGLIB$THREAD_CALLBACKS.set(var0);
   }

   public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { 
   
      CGLIB$STATIC_CALLBACKS = var0;
   }

   private static final void CGLIB$BIND_CALLBACKS(Object var0) { 
   
      Human$$EnhancerByCGLIB$$9fc9106 var1 = (Human$$EnhancerByCGLIB$$9fc9106)var0;
      if(!var1.CGLIB$BOUND) { 
   
         var1.CGLIB$BOUND = true;
         Object var10000 = CGLIB$THREAD_CALLBACKS.get();
         if(var10000 == null) { 
   
            var10000 = CGLIB$STATIC_CALLBACKS;
            if(CGLIB$STATIC_CALLBACKS == null) { 
   
               return;
            }
         }

         var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
      }

   }

   public Object newInstance(Callback[] var1) { 
   
      CGLIB$SET_THREAD_CALLBACKS(var1);
      Human$$EnhancerByCGLIB$$9fc9106 var10000 = new Human$$EnhancerByCGLIB$$9fc9106();
      CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
      return var10000;
   }

   public Object newInstance(Callback var1) { 
   
      CGLIB$SET_THREAD_CALLBACKS(new Callback[]{ 
   var1});
      Human$$EnhancerByCGLIB$$9fc9106 var10000 = new Human$$EnhancerByCGLIB$$9fc9106();
      CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
      return var10000;
   }

   public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { 
   
      CGLIB$SET_THREAD_CALLBACKS(var3);
      Human$$EnhancerByCGLIB$$9fc9106 var10000 = new Human$$EnhancerByCGLIB$$9fc9106;
      switch(var1.length) { 
   
      case 0:
         var10000.<init>();
         CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
         return var10000;
      default:
         throw new IllegalArgumentException("Constructor not found");
      }
   }

   public Callback getCallback(int var1) { 
   
      CGLIB$BIND_CALLBACKS(this);
      MethodInterceptor var10000;
      switch(var1) { 
   
      case 0:
         var10000 = this.CGLIB$CALLBACK_0;
         break;
      default:
         var10000 = null;
      }

      return var10000;
   }

   public void setCallback(int var1, Callback var2) { 
   
      switch(var1) { 
   
      case 0:
         this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
      default:
      }
   }

   public Callback[] getCallbacks() { 
   
      CGLIB$BIND_CALLBACKS(this);
      return new Callback[]{ 
   this.CGLIB$CALLBACK_0};
   }

   public void setCallbacks(Callback[] var1) { 
   
      this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
   }

   static { 
   
      CGLIB$STATICHOOK1();
   }
}

对比和上面的SuperMan$$EnhancerByCGLIB$$3be74240发现并无差别(此时类中还无自定义方法)。

需要注意的是,这里只是测试绑定的代理目标对象为接口的可能性,代理类实现类接口的方法,并将方法的调用转发到intercept—具体业务逻辑实现。且在intercept中,obj = method.invoke(new SuperMan(), args);将实际实现类写死了。


② 实际实现类(SuperMan)中添加自定义方法

如下,修改SuperMan:

// 被代理类
class SuperMan implements Human { 
   
	public void info() { 
   
		System.out.println("我是超人!我怕谁!");
	}

	public void fly() { 
   
		System.out.println("I believe I can fly!");
	}
	
	public void self(){ 
   
		System.out.println("this is suman's method--self !");
	}
}

测试代码如下–传入实现类对象:

import java.lang.reflect.Method;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TestCglibProxy { 
   
	
	public static void main(String[] args) { 
   
		//创建一个被代理类的对象
		SuperMan man = new SuperMan();
		String path = CGLibProxy.class.getResource(".").getPath();  
		System.out.println(path);
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
		CGLibProxy cgLibProxy = new CGLibProxy();
		Object obj = cgLibProxy.getProxyInstance(man);//返回一个代理类的对象
		System.out.println(obj.getClass());
		//class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
		Suman su = (Suman)obj;
		su.info();//通过代理类的对象调用重写的抽象方法
		
		System.out.println();
		// 注意,这里调用Suman自定义方法
		su.self();
	}
}

class CGLibProxy implements MethodInterceptor { 
     
  
    private Object targetObject;// CGLib需要代理的目标对象 
  
    public Object getProxyInstance(Object obj) { 
     
        this.targetObject = obj;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(obj.getClass());  
        enhancer.setCallback(this);  
        Object proxyObj = enhancer.create();  
        return proxyObj;// 返回代理对象 
    }  
  
    public Object intercept(Object proxy, Method method, Object[] args,  
            MethodProxy methodProxy) throws Throwable { 
     
        Object obj = null;  
        //模拟功能增强
        HumanUtil humanUtil = new HumanUtil();
        humanUtil.method1();
        // 执行目标目标对象方法
        obj = method.invoke(targetObject, args);
        //模拟功能增强
        humanUtil.method2();
        return obj;  
    }  
}

测试结果如下图:
这里写图片描述
毫无疑问是可以的,因为代理类继承自目标被代理类,故而添加的自定义方法可以被实现。因为CGLIB是继承自目标类-SuperMan,而非实现目标类的上层接口-Human!


此时生成的SuperMan$$EnhancerByCGLIB$$3be74240.class源码如下:

//... 省略代码,这里只表明方法
  final void CGLIB$info$0() { 
   
      super.info();
   }

   public final void info() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$info$0$Method, CGLIB$emptyArgs, CGLIB$info$0$Proxy);
      } else { 
   
         super.info();
      }
   }

   final void CGLIB$fly$1() { 
   
      super.fly();
   }

   public final void fly() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$fly$1$Method, CGLIB$emptyArgs, CGLIB$fly$1$Proxy);
      } else { 
   
         super.fly();
      }
   }

   final void CGLIB$self$2() { 
   
      super.self();
   }

   public final void self() { 
   
      MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
      if(this.CGLIB$CALLBACK_0 == null) { 
   
         CGLIB$BIND_CALLBACKS(this);
         var10000 = this.CGLIB$CALLBACK_0;
      }

      if(var10000 != null) { 
   
         var10000.intercept(this, CGLIB$self$2$Method, CGLIB$emptyArgs, CGLIB$self$2$Proxy);
      } else { 
   
         super.self();
      }
   }

此时如果使用①中的代码–即enhancer.setSuperclass(obj);传入Human.class,intercept中方法反射调用执行Suman.self()是会抛异常的,且生成的代理类源码中无self方法!

测试代码如下:

public class TestCglibProxy2 { 
   
	
	public static void main(String[] args) { 
   
		String path = CGLibProxy.class.getResource(".").getPath();  
		System.out.println(path);
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
		CGLibProxy2 cgLibProxy = new CGLibProxy2();
		//这里传入Human
		Object obj = cgLibProxy.getProxyInstance(Human.class);//返回一个代理类的对象
		System.out.println(obj.getClass());
		// 强转可能会抛异常
		SuperMan su = (SuperMan)obj;
		su.info();
		
		System.out.println();
		// 尝试调用Suman私有方法
		su.self();
	}
}

class CGLibProxy2 implements MethodInterceptor { 
     
  
    public Object getProxyInstance(Class<?> obj) { 
     
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(obj);  
        enhancer.setCallback(this);  
        Object proxyObj = enhancer.create();  
        return proxyObj;// 返回代理对象 
    }  
  
    public Object intercept(Object proxy, Method method, Object[] args,  
            MethodProxy methodProxy) throws Throwable { 
     
        Object obj = null;  
        //模拟功能增强
        HumanUtil humanUtil = new HumanUtil();
        humanUtil.method1();
        // 执行目标目标对象方法
        obj = method.invoke(new SuperMan(), args);
        //模拟功能增强
        humanUtil.method2();
        return obj;  
    }  
}

测试结果如下:

这里写图片描述
生成的代理类Human$$EnhancerByCGLIB$$9fc9106.class并无Suman.self()—很显然的事情!!!


③ Cglib动态代理总结

① CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类。

通常使用Cglib的时候侧重于实际实现类!!

② 由于是继承方式,如果是 static方法,private方法,final方法是不能被代理的。

③ CGLIB会默认代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。


【5】获取JDK/Cglib动态代理对象

至此可以获取动态代理的class 文件,那么如何在项目中获取动态代理的目标对象呢?

示例代码如下:

import java.lang.reflect.Field;  
  
import org.springframework.aop.framework.AdvisedSupport;  
import org.springframework.aop.framework.AopProxy;  
import org.springframework.aop.support.AopUtils;  
  
public class AopTargetUtils {  
  
      
    /** 
     * 获取 目标对象 
     * @param proxy 代理对象 
     * @return  
     * @throws Exception 
     */  
    public static Object getTarget(Object proxy) throws Exception {  
          
        if(!AopUtils.isAopProxy(proxy)) {  
            return proxy;//不是代理对象  
        }  
          
        if(AopUtils.isJdkDynamicProxy(proxy)) {  
            return getJdkDynamicProxyTargetObject(proxy);  
        } else { //cglib  
            return getCglibProxyTargetObject(proxy);  
        }  

    }  
  
  
    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {  
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");  
        h.setAccessible(true);  
        Object dynamicAdvisedInterceptor = h.get(proxy);  
          
        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");  
        advised.setAccessible(true);  
          
        Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();  
          
        return target;  
    }  
  
  
    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {  
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");  
        h.setAccessible(true);  
        AopProxy aopProxy = (AopProxy) h.get(proxy);  
          
        Field advised = aopProxy.getClass().getDeclaredField("advised");  
        advised.setAccessible(true);  
          
        Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();  
          
        return target;  
    }  
      
} 

【6】Spring中动态代理的实现


Spring代理实际上是对JDK代理和CGLIB代理做了一层封装,并且引入了AOP概念:Aspect、advice、joinpoint等等,同时引入了AspectJ中的一些注解@pointCut,@after,@before等等。Spring Aop严格的来说都是动态代理。

Spring在选择用JDK还是CGLiB的依据:

  • 当Bean实现接口时,Spring就会用JDK的动态代理

  • 当Bean没有实现接口时,Spring使用CGlib是实现

如何强制使用CGLIB实现AOP?

  • 添加CGLIB库,SPRING_HOME/cglib/*.jar
  • 可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143025.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 大一新生应该如何学习C语言,书上代码看不懂理解不了怎么办?

    大一新生应该如何学习C语言,书上代码看不懂理解不了怎么办?大家好,我是二哥呀!昨天有个读者问我要C语言的学习路线,他今年刚上大一,书上的代码完全看不懂。讲真,大一新生,一般都是零基础的纯小白,看不懂书上的代码很正常,除非是小学、初中、高中就开始卷计算机的硬核少年;或者是因为教材选的有问题。那刚好二哥之前整理过一些学习C语言的资料和学习方法,今天趁这个机会就再做个汇总和梳理。推荐一本书,两门视频课,若干学习建议,看完后如果还看不懂、理解不了C语言,过来骂我、捶我,只要不要打脸就行。01)阮一峰老师的C语言入门教程这个教程是开源的,采用知识共享许可

  • windows下php7.1安装redis扩展以及redis测试使用全过程

    windows下php7.1安装redis扩展以及redis测试使用全过程

    2021年10月27日
  • Struts2漏洞复现合集

    Struts2漏洞复现合集1.Struts2简介Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts2是Struts的下一代产品,是在struts1和WebWork的技术基础上进行了合并的全新的Struts2框架。其全新的Struts2的体系结构与Struts1的体系结构差别巨大。Struts2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务

  • php工厂模式详解

    php工厂模式详解工厂类就是一个专门用来创建其它对象的类,工厂类在多态性编程实践中是非常重要的。它允许动态替换类,修改配置,会使应用程序更加灵活。掌握工厂模式对Web开发是必不可少的。工厂模式通常用来返回类似接口的不同的类,工厂的一种常见用法就是创建多态的提供者。通常工厂模式有一个关键的构造,即一般被命名为factory的静态方法。这个静态方法可以接受任意数量的参数,并且必须返回一个对象。P

  • 【找规律】CodeForce #258 Problem A——Game With Sticks[通俗易懂]

    【找规律】CodeForce #258 Problem A——Game With Sticks

  • ReadProcessMemory函数的分析「建议收藏」

    ReadProcessMemory函数的分析「建议收藏」ReadProcessMemory函数用于读取其他进程的数据。我们知道自远古时代结束后,user模式下的进程都有自己的地址空间,进程与进程间互不干扰,这叫私有财产神圣不可侵犯。但windows里还真就提供了那么一个机制,让你可以合法的获取别人的私有财产,这就是ReadProcessMemory和WriteProcessMemory。为什么一个进程居然可以访问另一个进程的地址空间呢?因为独立的只是低

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号