Spring的动态代理-【JDK动态代理以及CGLIB动态代理】

发布时间:2023-03-16 18:30

在这里插入图片描述

目录

  • 概述
    • 原理区别
    • 如何强制使用CGLIB实现AOP?
    • JDK动态代理和CGLIB字节码生成的区别?
  • Spring的两种动态代理实现
    • 方法接口
    • 方法实现
      • Jdk动态代理调用
      • cglib动态代理调用
  • 总结:

又从同学那里听到一个好东西,于时着手看看是啥。。。

概述

原理区别

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP

3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP?

(1)添加CGLIB库,SPRING_HOME/cglib/*.jar
(2)在spring配置文件中加入

JDK动态代理和CGLIB字节码生成的区别?

(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final

Spring的两种动态代理实现

方法接口

/**
 * 用户管理接口
 */
public interface IUserManager {
    void addUser(User user);
    void delUser(Long userId);
}

方法实现

/**
 * 管理类的实现
 */
public class UserManagerImpl implements IUserManager {
    @Override
    public void addUser(User user) {
        System.out.println("执行了添加用户方法:"+user);
    }

    @Override
    public void delUser(Long userId) {
        System.out.println("执行了删除用户方法:"+userId);
    }
}

Jdk动态代理调用

@Slf4j
//jdk动动态代理,需要实现接口[InvocationHandler]
public class JdkProxy implements InvocationHandler {

    private Object target;// 需要我们进行代理的目标对象

    // 调用方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("jdk动态代理,监听ing....");
        // 执行代理后的方法,传入参数,获得执行结果,将结果返回
        Object result = method.invoke(target, args);
        log.info("jdk动态代理,监听end....");
        return result;
    }


    /**
     * 准备一个获取代理对象的方法
     * @param targetObject 需要把对象转为代理对象的原对象
     * @return 代理对象
     */
    private Object getJDKProxy(Object targetObject){
        // 将传入的对象写入本类的目标对象
        this.target=targetObject;
        // JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
        //参数,需要实例化的对象的class的加载器,需要实例化的对象的接口,以及实现了InvocationHandler的类(本类)
        Object proxyInstance = Proxy.newProxyInstance(
                targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),
                this);
        log.info("获取到了实例化对象:{}",proxyInstance);
        return proxyInstance;
    }

    // 测试方法
    public static void main(String[] args) {
        // 先实例化JdkProxy对象,就是我们实现了InvocationHandler的对象,通过他来创建代理对象
        JdkProxy jdkProxy = new JdkProxy();
        // 传入我们需要代理的对象,获取代理对象,转型为实现类的接口,然后我们就能够通过接口进行调用
        IUserManager proxyObject = (IUserManager)jdkProxy.getJDKProxy(new UserManagerImpl());
        // 调用方法
        proxyObject.addUser(new User(1982L,"Kira"));
    }
}

JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
在这里插入图片描述
在这里插入图片描述

cglib动态代理调用

@Slf4j
//Cglib动态代理,实现MethodInterceptor接口
public class CglibProxy implements MethodInterceptor {

    private Object target;

    //重写拦截方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        log.info("cglib动态代理,监听ing....");
        Object invoke = method.invoke(target, objects);//方法执行,参数:target 目标对象 objects参数数组
        log.info("cglib动态代理,监听end....");
        return invoke;
    }

    // 定义获取代理对象的方法
    public Object getCglibProxy(Object objectTarget){
        // 给成员中的目标对象赋值
        this.target=objectTarget;
        Enhancer enhancer = new Enhancer();
        //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(target.getClass());
        // 设置回调
        enhancer.setCallback(this);
        // 创建代理对象
        Object result = enhancer.create();
        log.info("获取到了实例化对象:{}",result);
        return result;
    }

    // 调用测试
    public static void main(String[] args) {
        // 创建cglib代理对象
        CglibProxy cglibProxy = new CglibProxy();
        log.info("接口调用");
        // 获取代理对象。由于这里是直接生成了一个确实的实体类,我们依然会把他转型成他的接口类进行调用
        IUserManager userManage =(IUserManager) cglibProxy.getCglibProxy(new UserManagerImpl());
        userManage.delUser(12865L);

        // 由于是生成了一个子类,所以使用子类型调用也可以
        UserManagerImpl userManageImpl =(UserManagerImpl) cglibProxy.getCglibProxy(new UserManagerImpl());
        userManageImpl.addUser(new User(12312L,"法外狂徒张三"));
        log.info("子类调用");
    }
}

Spring的动态代理-【JDK动态代理以及CGLIB动态代理】_第1张图片

总结:

Demo是做出来了。。。但是不知道能干啥。。。。
执行步骤:
1.创建代理类对象,
2.将传入的实现设置进成员变量,重写的方法中调用成员变量实现类的方法,然后使用Proxy.newProxyInstance 创建代理实例化对象返回;
3.获得代理对象以后可以调用执行

被spring惯坏了吗。。。。

之前好像是:
1.在类里注入接口,然后方法调用接口的抽象方法就可以了;
2.创建类的时候通过各种构造指定上面注入接口的具体实现,然后实现可以动态的变更;

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号