代理模式-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 Generation Library)是一个开源项目,是一个强大的、高性能的、高质量的代码生成类库。它可以在运行期扩展喝增强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

希望对你有帮助,祝你有一个好心情,加油!

若有错误、不全、可优化的点,欢迎纠正与补充!

 

你可能感兴趣的:(设计模式)