探究Java spring中jdk代理和cglib代理!

news2024/9/21 0:39:17

面对新鲜事物,我们要先了解在去探索事物的本质-默

目录

一.介绍二者代理模式

1.1.Jdk代理模式

1.2cglib代理模式

1.3二者区别

1.3.1有无接口

1.3.2灵活性

1.4对于两种代理模式的总结

1.4.1jdk代理模式

1.4.2cglib代理模式

二.两种代理模式应用场景

2.1jdk代理模式应用场景

2.1.1基于接口的代理

2.1.2细粒度的方法拦截

2.2cglib代理模式应用场景

2.2.1非基于接口的代理

2.2.2覆盖父类中的方法 

2.2.3高性能的代理 

三.代码演示 

3.1jdk代理模式

3.1.1源码

 3.2思路解释

3.2cglib代理模式

3.2.1源码

 3.2.1思路解释


一.介绍二者代理模式

1.1.Jdk代理模式

JDK代理是通过接口实现的动态代理方式。当目标类实现了至少一个接口时,Spring AOP会使用JDK代理。JDK代理通过在运行时创建一个实现了目标接口的代理类来实现代理功能。代理对象和目标对象实现了同一个接口,因此只能代理接口中定义的方法

1.2cglib代理模式

CGLIB代理是通过继承实现的动态代理方式。当目标类没有实现任何接口时,Spring AOP会使用CGLIB代理。CGLIB代理通过在运行时创建目标类的子类来实现代理功能。代理对象继承自目标对象,并覆盖了目标对象的非final方法,因此可以代理目标对象的所有方法。

1.3二者区别

1.3.1有无接口

JDK代理要求目标类必须实现接口,而CGLIB代理不需要,可以代理普通的Java类。 

1.3.2灵活性

JDK代理基于接口,适用于对接口的代理,更加灵活,但无法代理没有接口的类

CGLIB代理是通过生成目标类的子类来实现代理,适用于对类的代理。CGLIB代理具有更高的性能,因为它不需要通过反射调用目标对象的方法。 

1.4对于两种代理模式的总结

1.4.1jdk代理模式

JDK 动态代理是基于接口的代理方式。它通过创建一个实现了目标接口的代理类,并在代理类中实现代理逻辑。代理类在运行时动态生成,并在其中调用原始对象的方法

JDK 动态代理通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现。代理对象是在运行时动态生成的。

无法代理非公有类:JDK 动态代理不能代理那些声明为 final 的类,因为 final 类不能被继承。另外,由于代理类是在运行时动态生成的,因此也无法代理那些没有默认构造函数的类

方法拦截:代理对象在调用方法时,会将方法调用转发给 InvocationHandler 的实现类,在这个实现类中可以添加自定义的逻辑,完成方法的拦截、增强等操作。

性能相对较低:相比于 CGLIB 动态代理,JDK 动态代理的性能较低。这主要是因为 JDK 动态代理需要通过反射来调用目标对象的方法。

总的来说,JDK 动态代理是一种比较常用的代理方式,适用于代理接口的场景,易于使用和理解。但它的局限性在于只能代理实现了接口的类,并且在性能方面稍逊于 CGLIB 动态代理。

1.4.2cglib代理模式

CGLIB 动态代理是一种基于继承的代理方式。它通过创建目标类的子类来实现代理。代理类继承自目标类,并重写其中的方法,在重写的方法中添加了增强逻辑

类代理:CGLIB 动态代理可以代理类,无论是否实现了接口。这使得它可以代理那些没有实现接口的类,不包括 final 类

代理生成:CGLIB 动态代理使用字节码生成库来创建目标类的子类。代理类在运行时动态生成,并且不需要目标类实现任何接口。

方法拦截:被代理的方法在执行时,会调用代理类中的方法。这样,我们可以在代理类中添加拦截器(MethodInterceptor),并在拦截器中实现自定义的逻辑。

性能相对较高:相比于 JDK 动态代理,CGLIB 动态代理的性能更高。这是因为 CGLIB 通过继承来实现代理,避免了反射调用的开销。

对于 final 方法和私有方法的限制:CGLIB 默认无法代理 final 方法,因为 final 方法无法被重写。此外,CGLIB 也不能代理私有方法,因为代理类无法访问目标类的私有方法。但是可以通过设置 CGLIB 的 Enhancer 对象的 setUseReflection(true) 方法来强制代理私有方法。这样一来,CGLIB 将使用反射调用私有方法,但这可能会导致性能下降。

需要注意的是,CGLIB 代理依赖于字节码生成,在代理类生成时会占用一定的时间和内存

总结来说,CGLIB 动态代理适用于代理类的场景,可以代理没有实现接口的类,并且具有较高的性能。

二.两种代理模式应用场景

2.1jdk代理模式应用场景

2.1.1基于接口的代理

如果目标对象实现了接口,可以使用JDK动态代理。它要求目标对象实现一个接口,并且生成的代理对象也会实现相同的接口。

2.1.2细粒度的方法拦截

JDK动态代理可以在目标对象的方法调用前后添加额外的逻辑。例如,在方法调用前打印日志、进行权限验证或事务管理等

2.2cglib代理模式应用场景

2.2.1非基于接口的代理

CGLIB动态代理可以代理没有实现接口的类。因此,当目标对象没有实现任何接口时,可以使用CGLIB动态代理。

2.2.2覆盖父类中的方法 

CGLIB动态代理通过继承目标类并覆盖其中的方法来创建代理对象。这使得它可以代理目标类中的非公有方法。 

2.2.3高性能的代理 

相比JDK动态代理,CGLIB动态代理通常具有更高的性能,因为它直接操作字节码而不需要通过反射调用方法。 

三.代码演示 

3.1jdk代理模式

3.1.1源码

package com.daili.jdk;

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

/**
 * @author lz
 * @create 2023-08-21 9:33
 */
public interface UserService {
    void saveUser(String username);
}
class UserServiceImpl implements UserService {
    public void saveUser(String username) {
        System.out.println("Saving user: " + username);
    }
}

class UserServiceProxy implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new UserServiceProxy(userService)
        );

        proxy.saveUser("刘兵");
    }
}

 3.2思路解释

  1. 定义了一个接口 UserService,其中包含了一个抽象方法 saveUser(String username)
  2. 实现了接口 UserService 的具体类 UserServiceImpl,该类实现了 saveUser 方法,用于保存用户信息。
  3. 创建了一个代理类 UserServiceProxy,实现了 InvocationHandler 接口。在 invoke 方法中,对目标方法进行前置和后置处理,即在目标方法执行前输出 "Before method: " + 方法名,在目标方法执行后输出 "After method: " + 方法名。
  4. 在 Main 类的 main 方法中,创建了一个 UserServiceImpl 的实例。
  5. 通过 Proxy.newProxyInstance() 方法创建代理对象,传入目标对象的类加载器、接口数组和 UserServiceProxy 的实例。返回的代理对象将会实现 UserService 接口。
  6. 调用代理对象的 saveUser("John") 方法,实际上会触发代理对象的 invoke 方法,从而实现了动态代理。

在代码执行过程中,代理对象的 invoke 方法会先输出 "Before method: saveUser",然后调用目标对象的 saveUser 方法,最后输出 "After method: saveUser"。

通过 JDK 动态代理,可以在不修改目标对象代码的情况下,对其方法进行增强、添加日志等操作。

3.2cglib代理模式

3.2.1源码

package com.daili.cglib;

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

import java.lang.reflect.Method;

/**
 * @author lz
 * @create 2023-08-21 9:49
 */
public class UserService {
    public void saveUser(String username) {
        System.out.println("Saving user: " + username);
    }
}
class UserServiceInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method: " + method.getName());
        return result;
    }


static class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new UserServiceInterceptor());

        UserService proxy = (UserService) enhancer.create();

        proxy.saveUser("刘兵");
    }
}
}

 3.2.1思路解释

  1. 定义了一个类 UserService,其中包含了一个方法 saveUser(String username),用于保存用户信息。
  2. 创建了一个代理类 UserServiceInterceptor,实现了 MethodInterceptor 接口。在 intercept 方法中,对目标方法进行前置和后置处理,即在目标方法执行前输出 "Before method: " + 方法名,在目标方法执行后输出 "After method: " + 方法名。使用 MethodProxy 对象调用原始方法。
  3. 在 Main 类的 main 方法中,创建了一个 Enhancer 对象。
  4. 通过 enhancer.setSuperclass(UserService.class) 设置目标类为 UserService
  5. 通过 enhancer.setCallback(new UserServiceInterceptor()) 设置回调处理器为 UserServiceInterceptor 的实例。
  6. 调用 enhancer.create() 方法返回代理对象,将其转换为 UserService 类型。
  7. 调用代理对象的 saveUser("John") 方法,会触发代理对象的 intercept 方法,从而实现了动态代理。

在代码执行过程中,代理对象的 intercept 方法会先输出 "Before method: saveUser",然后调用目标对象的 saveUser 方法,最后输出 "After method: saveUser"。

通过 CGLIB 动态代理,可以在不修改目标对象代码的情况下,对其方法进行增强、添加日志等操作。与 JDK 动态代理不同的是,CGLIB 动态代理可以代理类而不仅限于接口。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/909608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试框架pytest教程(5)运行失败用例-rerun failed tests

# content of test_50.py import pytestpytest.mark.parametrize("i", range(50)) def test_num(i):if i in (17, 25):pytest.fail("bad luck") 运行这个文件,2个失败,48个通过。 要运行上次失败的测试用例,可以使用--l…

框架(Git基础详解及Git在idea中集成步骤)

目录 基础: idea集成Git并添加项目到git仓库 1.idea集成git,集成.git.exe文件 2.初始化本地Git仓库项目 3. 将工作区代码添加到暂存区 4.将暂存区代码添加到本地仓库 5.Git本地库操作 Idea集成Gitee并提交代码到第三方库 1.setting里搜索gitee 2.添…

什么是RNN(循环神经网络)

什么是RNN(循环神经网络) 循环神经网络(Recurrent Neural Network),在识别图像时,输入的每张图片都是孤立的,认出这张图片是苹果,并不会对认出下一张图片是梨造成影响。 但对语言来说,顺序是十分重要的,“…

Lua与C++交互(一)————堆栈

Lua与C交互(一)————堆栈 Lua虚拟机 什么是Lua虚拟机 Lua本身是用C语言实现的,它是跨平台语言,得益于它本身的Lua虚拟机。 虚拟机相对于物理机,借助于操作系统对物理机器(CPU等硬件)的一…

Java【手撕双指针】LeetCode 1089. “复写零“, 图文详解思路分析 + 代码

文章目录 前言一、复写零1, 题目2, 思路分析2.1, 从左往右 or 从右往左2.2, 找到最后一个保留的数 3, 代码展示 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: 📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管…

SpringCloud Gateway服务网关的介绍与使用

目录 1、网关介绍2、SpringCloudGateway工作原理3、三大组件3.1 、Route(路由)3.2、断言 Predicate3.3、过滤器 filter 4、Gateway整合nacos的使用4.1 、引入依赖4.2、 编写基础类和启动类4.3、 编写基础配置和路由规则4.4 、测试结果 1、网关介绍 客户…

营销数字化|企业级 AIGC 工具的「iPhone 时刻」

2007 年,乔布斯发布了第一款 iPhone,从此彻底改变了手机行业的市场走向。iPhone 成功的背后,一个很重要的原因是:它让用户以更简单、更符合直觉的方式来使用手机。 如今,AIGC 工具也在等待它的「iPhone 时刻」&#xf…

C++信息学奥赛1119:矩阵交换行

解题思路&#xff1a;当输出时换行 解题程序&#xff1a; #include<iostream> using namespace std; int main() {int arr[5][5];// 输入矩阵元素for(int i0;i<5;i){for(int j0;j<5;j){cin>>arr[i][j];}} int n,m;cin>>n>>m;// 根据条件进行矩…

RT-Thread学习日记——点亮LED

最近开始接触RT-Thread&#xff0c;后面会单独建立专栏以此记录我的学习过程&#xff0c;如果能给你的学习提供参考&#xff0c;本人倍感荣幸。 学习工具&#xff1a;正点原子战舰开发板 一、、点亮LED 在RT-Thread的配置项里搜索LED可以看到和LED相关的很多内容&#xff0c…

AutoDev 1.1.3 登场,个性化 AI 辅助:私有化大模型、自主设计 prompt、定义独特规则...

在过去的半个月里&#xff0c;我们为开源辅助编程工具 AutoDev 添加了更强大的自定义能力&#xff0c;现在你可以&#xff1a; 使用自己部署的开源大模型自己配置 Intellij IDEA 中的行为自定义开发过程中的规范 当然了&#xff0c;如果您自身拥有开发能力的话&#xff0c;建议…

无涯教程-PHP - XML

简单的XML解析器解析 Name&#xff0c; attributes 和 textual content&#xff0c;简单的XML函数如下所示- simplexml_load_file() 此函数接受文件路径作为第一个参数&#xff0c;这是必需的。 simplexml_load_file(($fileName,$class,$options,$ns,$is_prefix) simplexml…

springMVC Unix 文件参数变更漏洞修复

错误信息如下&#xff1a; 解决方案&#xff1a; 原因&#xff1a;未对用户输入正确执行危险字符清理 未检查用户输入中是否包含“…”&#xff08;两个点&#xff09;字符串&#xff0c;比如 url 为 /login?action…/webapps/RTJEKSWTN26635&typerandomCode cookie为Coo…

飞天使-kubeadm安装一主一从集群

文章目录 安装前准备安装前准备配置yum源等安装前准备docker安装 安装kubeadm配置kubeadm验证集群 参考链接 安装前准备 cat >> /etc/hosts <<EOF 192.168.100.30 k8s-01 192.168.100.31 k8s-02 EOF hostnamectl set-hostname k8s-01 #所有机器按照要求修改 ho…

React笔记[tsx]-解决Property ‘frames‘ does not exist on type ‘Readonly<{}>‘

浏览器报错如下&#xff1a; 编辑器是这样的&#xff1a; 原因是React.Component<any>少了后面的any&#xff0c;改成这样即可&#xff1a; export class CustomFrame extends React.Component<any, any>{............ }

CH02_重构的原则(什么是重构、为什么重构、何时重构)

什么是重构 重构&#xff08;名词&#xff09;&#xff1a;对软件内部结构的一种调整&#xff0c;目的是在不改变软件可观察行为的前提下&#xff0c;提高其可理解性&#xff0c;降低其修改成本。 重构&#xff08;动词&#xff09;&#xff1a;使用一系列重构手法&#xff0…

Lnton羚通算法算力云平台在环境配置中当使用conda创建新的虚拟环境时为什么会遇到错误

当使用conda创建新的虚拟环境时遇到错误&#xff0c;可能是由于以下一些常见原因导致的&#xff1a; Conda环境未正确安装&#xff1a;请确保你已经正确安装了Conda&#xff0c;并且设置了正确的环境变量。你可以尝试在终端中运行conda --version来验证Conda是否已经成功安装并…

STM32设置为I2C从机模式(HAL库版本)

STM32设置为I2C从机模式&#xff08;HAL库版本&#xff09; 目录 STM32设置为I2C从机模式&#xff08;HAL库版本&#xff09;前言1 硬件连接2 软件编程2.1 步骤分解2.2 测试用例 3 运行测试3.1 I2C连续写入3.2 I2C连续读取3.3 I2C单次读写测试 4 总结 前言 我之前出过一篇关于…

ios小组件报错:Please adopt containerBackground API

iOS 17 小组件报错:Please adopt containerBackground API 使用下面的方法解决了: 代码: extension View {func widgetBackground(_ backgroundView: some View) -> some View {if #available(iOSApplicationExtension 17.0, *) {return containerBackground(for: .wi…

恒运资本:信创概念再度活跃,华是科技再创新高,南天信息等涨停

信创概念21日盘中再度活跃&#xff0c;截至发稿&#xff0c;华是科技涨超17%&#xff0c;盘中一度触及涨停再创新高&#xff0c;中亦科技涨超13%亦创出新高&#xff0c;久其软件、南天信息、新炬网络、英飞拓均涨停。 音讯面上&#xff0c;自8月3日以来&#xff0c;财政部官网连…

YOLOX在启智AI GPU/CPU平台部署笔记

文章目录 1. 概述2. 部署2.1 拉取YOLOX源码2.2 拉取模型文件yolox_s.pth2.3 安装依赖包2.4 安装yolox2.5 测试运行2.6 运行报错处理2.6.1 ImportError: libGL.so.1: cannot open shared object file: No such file or directory2.6.2 ImportError: libgthread-2.0.so.0: cannot…