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
,又叫类加载器,主要作用有两个:
- 可以通过类加载器把字节码文件加载到虚拟机
- 可以通过类加载器创建类的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
- 点赞
- 收藏
- 关注作者
评论(0)