动态代理之JDK和CGLIB实现原理对比以及其生成的class的真实面目

JDK动态代理以及CGLIB动态代理

1、Jdk动态代理以及jdk动态代理类的class的真正面目

jdk动态代理是利用反射机制生成的一个实现代理接口InvocationHandler和目标类接口的匿名类,InvocationHandler其中有一个invoke方法,在调用真正的目标方法method.invoke(target,args)之前或者之后做代理操作。

代码:

代理类

public class JdkTargetProxy implements InvocationHandler {

    private Object target;

    public JdkTargetProxy(Object target){
        this.target = target;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> tClass){
        return (T) Proxy.newProxyInstance(tClass.getClassLoader(),
                new Class[]{tClass},
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "jdk动态代理before……");
        Object result = method.invoke(target, args);
        System.out.println(method.getName() + "jdk动态代理after……");
        return result;
    }
}

测试类

/**
 * 接口
 **/
public interface Dao {
    String getTest();
}

/**
 * 目标类
 **/
@Service
public class DaoImpl implements Dao{
    @Override
    public String getTest() {
        System.out.println("from DaoImpl1");
        return "from DaoImpl1";
    }
}

/**
 * 测试函数
 */
public class TestMain {
    public static void main(String[] args) {
        // 生成代理类的同时将class文件输出
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        JdkTargetProxy targetProxy = new JdkTargetProxy(new DaoImpl());
        Dao proxy = targetProxy.getProxy(Dao.class);
        proxy.getTest();
    }
}

结果:

getTestjdk动态代理before……
from DaoImpl1
getTestjdk动态代理after……

生成的代理类

 在其中,重写了目标方法的实现

super.h即为 InvocationHandler的实现,即执行JdkTargetProxy的invoke方法。

2、cglib动态代理以及cglib动态代理类的class的真正面目

cglib封装了asm开源框架,对代理对象类的class文件进行字节码操作,生成代理类。生成的代理类是目标类的子类,重写了目标类的方法。

实现cglib动态代理需要依赖两个jar包,cglib的jar包以及asm的jar包,使用maven引入cglib-nodep即可。

引入依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>3.3.0</version>
</dependency>

cglib代理类:

public class CglibTargetProxy implements MethodInterceptor {

    public <T> T getProxy(Class<T> tClass){
        // 字节码增强类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(tClass);
        // 设置回调类,调用哪个类的intercept的方法
        enhancer.setCallback(this);
        return (T)enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println(method.getName() + "cglib代理逻辑before……");
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println(method.getName() + "cglib切面逻辑after……");
        return result;
    }
}

测试方法:

public static void main(String[] args) {
    // 设置生成代理类的同时输出文件
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:/code");
    CglibTargetProxy targetProxy = new CglibTargetProxy();
    DaoImpl proxy = targetProxy.getProxy(DaoImpl.class);
    proxy.getTest();
}

结果:

CGLIB debugging enabled, writing to 'D:/code'
getTestcglib代理逻辑before……
from DaoImpl1
getTestcglib切面逻辑after……

代理类class的内容:

 继承自目标类,使用字节码提升工具重写目标方法,实现getTest()时指向生成代理类是设置的callBack的类的intercept方法;

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

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

3、jdk动态代理和cglib动态代理的区别

  • jdk动态代理是利用反射机制实现目标接口实现代理,cglib是通过字节码操作生成接口的子类实现代理。
  • jdk动态代理只能实现实现了接口的目标对象,如果对象没有实现接口则无法使用jdk动态代理,因为java是单一继承的,但可以实现多个接口,jdk动态代理生成的代理类继承了一个Proxy,所以只能通过实现接口来实现。如果目标对象实现了接口也可以使用cglib。但是cglib不能对申明了final的类和方法进行代理
  • 在性能上,在jdk6以前,使用字节码技术实现代理的方式比反射的效率要高。但是jdk6、jdk7、jdk8对jdk动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB,当大陆调用的时候,jdk6、jdk7比CGLIB代理效率低,但是jdk8之后使用jdk动态代理的效率比cglib高。

二者优势

  • 使用JDK动态代理,没有额外的依赖,随JDK平滑升级;JDK8之后性能优。
  • CGLIB没有限定目标类必须实现接口,适用性广。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值