Spring 从入门到精通 (十六) AOP底层如何创建动态代理类

举报
周棋洛 发表于 2022/07/27 00:03:06 2022/07/27
【摘要】 关键词:Spring | AOP | 创建代理类 | 底层 本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨ 目录...

关键词:Spring | AOP | 创建代理类 | 底层

本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨

在这里插入图片描述

一、创建对象三要素

  • 原始对象
  • 额外功能
  • 原始对象要和代理对象实现同一个接口

二、动态代理类的创建

  • JDK 动态代理
  • cglib 动态代理

2.1、JDK 动态代理

public static void main(String[] args) {
    //1. 创建原始对象
    UserService userService = new UserServiceImpl();
    //2. 创建动态代理,使用JDK
    Proxy.newProxyInstance(loader, interfaces, InvocationHandler);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.1.1、第三个参数,完成附加操作

JDK的动态代理是实现的第三个参数, InvocationHandler 接口中的 invoke()

UserService userService = new UserServiceImpl();
/**
 * 作用:用于编写额外功能,可以运行在原始方法前,后,前后,异常等情况
 * @param proxy 表示代理对象,可以忽略
 * @param method 额外功能加给哪个原始方法
 * @param args 原始方法参数
 * @return 原始方法的返回值
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //额外功能
    //反射调用,更灵活
    Object invoke = method.invoke(userService, args);
    return invoke;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

接口实现和之前学习的 MethodInterceptor很像,其实方法拦截器就是由这个方法封装过的


在这里插入图片描述


2.1.2、第二个参数,实现同一接口

第二个参数是 Class<?>[] interfaces ,原始对象所实现的接口,只有拿到相同的接口,才能根据接口进一步代理

UserService.getClass().getInterfaces()

  
 
  • 1

2.1.3、第一个参数,类加载器

第一个参数是 ClassLoader loader,又叫类加载器,主要作用有两个:

  1. 可以通过类加载器把字节码文件加载到虚拟机
  2. 可以通过类加载器创建类的Class对象,进而创建类对象

如何获得类加载器?

每一个类的.class文件,都会被自动分配与之对应的类加载器(Class Loader)

但是动态代理类使用了动态字节码技术来创建字节码,没有源文件和字节码文件,直接将字节码写入虚拟机,没有加载的字节码的过程,那我们要获得代理对象,前面拿到原始类对象的字节码文件后,可以创建代理类对象了吗?

不可以,因为想要创建代理类对象,必须先获得代理类 Class 对象,就需要类加载器的帮助,但是动态代理没有 .clsss 文件,也就没有与之分配的类加载器

但是此时需要类加载器,怎么办?借一个,完成代理类 Class 对象的创建,进而完成代理类对象的创建

2.1.4、编码

TestJDKProxy

public class TestJDKProxy {
    public static void main(String[] args) {
        //1. 创建原始对象
        UserService userService = new UserServiceImpl();
        //2. 创建动态代理,使用JDK
        InvocationHandler handler = (proxy, method, args1) -> {
            System.out.println("--------Proxy log4--------");
            // 执行方法
            Object reg = method.invoke(userService, args1);
            return reg;
        };
        UserService useServiceProxy = (UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        useServiceProxy.login("哈哈", "123");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Result

--------Proxy log4--------
UserServiceImpl login + DAO

  
 
  • 1
  • 2

没有任何问题

2.2、Cglib 动态代理

Cglib是通过父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证既可以保证方法一致的情况下,在代理类中提供新的实现(原始方法 + 额外功能)

2.2.1、编码

TestCglib

public class TestCglib {
    public static void main(String[] args) {
        //1.创建原始对象 UserService
        UserService userService = new UserService();
        //2.通过Cglib创建动态代理对象
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TestCglib.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());
        MethodInterceptor methodInterceptor = new MethodInterceptor(){
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("---Cglib log---");
                Object ret = method.invoke(userService, objects);
                return ret;
            }
        };
        enhancer.setCallback(methodInterceptor);
        UserService userServiceProxy = (UserService) enhancer.create();
        userServiceProxy.login("哈哈", "12312312");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

Result

---Cglib log---
核心功能,登录操作

  
 
  • 1
  • 2

三、总结

JDK: 通过接口创建代理类对象
Cglib: 通过继承创建代理类对象

有接口使用 JDK ,没有就是用 Cglib

四、写在最后

座右铭:不要在乎别人如何看你,要在乎你自己如何看未来,看梦想,看世界…!

一起学习的可以私信博主或添加博主微信哦。

专栏:订阅专栏 ✅
关注:关注博主 🆙

文章来源: blog.csdn.net,作者:王子周棋洛,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/m0_53321320/article/details/125971724

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。