快来,一起复习一下JDK动态代理和CGLib动态代理的区别

文章对比了JDK动态代理和CGLIB在Java中的应用,JDK动态代理基于接口实现,适用于已实现接口的类,而CGLIB通过字节码生成子类实现代理,适用于未实现接口的类。JDK代理效率在创建时高,执行时低;CGLIB则相反。Spring会在两者间自动选择,若需强制使用CGLIB,需配置相关参数。
摘要由CSDN通过智能技术生成
背景

工作也有四年了,基础的东西许久不看有些遗忘。一起来复习一下吧

JDK动态代理和CGLib的区别

JDK动态代理主要是针对类实现了某个接口,AOP则会使用JDK动态代理。它基于反射的机制实现,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。

而如果某个类没有实现接口,AOP则会使用CGLIB代理。它的底层原理是基于asm第三方框架,通过修改字节码生成成一个子类,然后重写父类的方法,实现对代码的增强。

JDK创建代理对象效率较高,执行效率较低;
CGLIB创建代理对象效率较低,执行效率高。

JDK动态代理机制是委托机制,只能对实现接口的类生成代理,通过反射动态实现接口类;
CGLIB则使用的继承机制,针对类实现代理,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,因为是继承机制,不能代理final修饰的类。

代码实现区别
  • JDK动态代理实现方式

接口层

package com.springboot.demo.base.service;

public interface UserService {
    /**
     * 新增用户
     * @param name
     */
    void addUser(String name);
}

实现类

package com.springboot.demo.base.service;

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.println("yes i am add one user");
    }
}

代理类

package com.springboot.demo.base.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UserProxy implements InvocationHandler {
    private Object target;

    public UserProxy(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


        Object result = method.invoke(target, args);

        System.out.println("记录日志");
        return result;
    }
}

测试类

 public static void main(String[] args) {
        //jdk
            UserServiceImpl impl = new UserServiceImpl();
            UserProxy userProxy = new UserProxy(impl);
            UserService userService = (UserService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),userProxy);
            userService.addUser("aaaaa");
    }

执行结果

在这里插入图片描述

  • CDLib动态代理实现方式

实现类和接口类与JDK一致,这里就不重复贴了。

不一样的是CGLib还依赖一个包

<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.5</version>
		</dependency>

代理类

package com.springboot.demo.base.utils;

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

import java.lang.reflect.Method;

public class UserCGLib implements MethodInterceptor {
    private Object target;

    public UserCGLib() {
    }

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

    //返回一个代理对象:    是 target对象的代理对象
    public Object getProxyInstance() {
        //1. 创建一个工具类
        Enhancer enhancer = new Enhancer();
        //2. 设置父类
        enhancer.setSuperclass(target.getClass());
        //3. 设置回调函数
        enhancer.setCallback(this);
        //4. 创建子类对象,即代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("增强开始~~~");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("增强结束~~~");
        return result;
    }


}

测试类

 public static void main(String[] args) {
   
            //cglib

        UserCGLib serviceCGlib = new UserCGLib(new UserServiceImpl());
        UserServiceImpl userServic1e = (UserServiceImpl)serviceCGlib.getProxyInstance();
        userServic1e.addUser("add");
        System.out.println();
    }

执行结果

在这里插入图片描述

总结

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理
2、如果目标对象实现了接口,也可以强制使用CGLIB
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如果需要强制使用CGLIB来实现AOP,需要配置spring.aop.proxy-target-class=true或@EnableAspectJAutoProxy(proxyTargetClass = true

参考
https://zhuanlan.zhihu.com/p/440452860
https://blog.csdn.net/qq_59527118/article/details/127386305

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值