Java设计模式-结构型模式-代理模式

news2024/11/16 19:25:08

代理模式

  • 代理模式
    • 静态代理
    • 动态代理
      • JDK动态代理
      • CGlib动态代理

代理模式

创建一个代理对象来控制对原始对象的访问,可以用来扩展原始对象的功能,同时保护原始对象
一般使用代理模式的目的有两个:

  1. 保护目标对象
  2. 增强目标对象

代理模式有两种实现方案:静态代理 和 动态代理
在这里插入图片描述
下面以Dao层执行sql语句为例,讲述代理模式的 应用

静态代理

静态代理就是通过组合/继承的方式,代理类关联原始类,通过调用代理类的方法来实现 原始类的方法增强
这里有一个UserDaoImpl,作为原始类,提供一个模拟插入用户的接口

public interface UserDao {
    void insert();
}
/*****************************************************/

public class UserDaoImpl implements UserDao{

    public void insert(){
        System.out.println("插入一个用户");
    }
}

创建一个静态代理类,StaticProxyUserDao,完成对userDao的增强

public class StaticProxyUserDao implements UserDao{

    private UserDao userDao;

    public StaticProxyUserDao(UserDao userDao) {
        this.userDao = userDao;
    }


    @Override
    public void insert(){
        //事务开启...
        System.out.println("事务开启");
        userDao.insert();
        //方法增强...
        //事务提交...
        System.out.println("事务提交");
    }
}

测试代码如下,很容易理解,就不解释了

@Test
public void staticProxyTest(){
    //直接使用
    UserDao userDao = new UserDaoImpl();
    userDao.insert();

    System.out.println("---------------------------------------------------");
    //通过静态代理的方式,增强insert()方法
    StaticProxyUserDao staticProxyUserDao = new StaticProxyUserDao(userDao);
    staticProxyUserDao.insert();
}

输出:
插入一个用户
---------------------------------------------------
事务开启
插入一个用户
事务提交

动态代理

通过静态代理的方式可以实现方法的增强,但对于每个增强的类,都需要再写一个代理类,这样显得代码比较臃肿,所以就有了动态代理,可以在程序执行过程中,动态的代理目标类。

动态代理有两种实现方式:JDK动态代理CGlib动态代理

JDK动态代理

JDK动态代理是Java标准库中提供的一种代理方式
JDK动态代理是依赖接口的。
实现方式:通过Proxy类中的 静态方法 newProxyInstance(…)实现

@Test
public void JdkProxyTest(){
    UserDao userDao = new UserDaoImpl();
    /*
    * 参数1:指定一个类加载器
    * 参数2:指定接口 getInterfaces()
    * 参数3:指定对应的代理方法
    * */
    System.out.println();
    UserDao proxyUserDao = (UserDao)Proxy.newProxyInstance(UserDao.class.getClassLoader(), UserDaoImpl.class.getInterfaces(), (proxy, method, args) -> {
        System.out.println("事务开启");
        Object invoke = method.invoke(userDao,args);
        System.out.println("事务关闭");
        return invoke;
    });
    proxyUserDao.insert();
}

可以看出来,JDK动态代理的方法 必须在接口中有定义,所以,如果想要代理没有在接口中定义的方法,这就需要使用CGlib来实现

CGlib动态代理

CGlib 是基于 类继承实现的,通过继承目标类 来实现类的代理,所以目标类必须是可继承的
CGlib支持更细粒度的代理——针对某个方法进行代理
CGLIB是第三方提供的包,需要引入Jar包

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.1</version>
</dependency>

spring-core jar包里包含cglib ,所以使用spring框架的工程可以直接使用。
实现方式:通过Enhancer类实现,如下:

@Test
public void CGlibProxyTest(){
    // 创建Enhancer对象 类似于 Proxy类
    Enhancer enhancer = new Enhancer();
    // 设置父类的字节码对象 即需要代理的类
    enhancer.setSuperclass(UserDaoImpl.class);
    //设置回调函数,增强方法
    /**
         * o 代理对象,即生成的代理类的实例,这里是生成的代理对象,不是被代理对象
         * method 被代理方法的Method对象
         * args 方法调用时传递的参数数组
         * methodProxy 方法代理对象
         */
    enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
        System.out.println("事务开启");
        //这里注意使用的是 invokeSuper() 调用的是父类的接口
        Object invoke = methodProxy.invokeSuper(o,objects);
        System.out.println("事务关闭");
        return invoke;
    });
    // 生成代理对象
    UserDaoImpl proxy = (UserDaoImpl) enhancer.create();
    proxy.insert();
}

这里提一下注意的点:

JDK动态代理,依赖接口完成代理,没有实例对象,所以需要传入实例对象,
即 method.invoke(userDao,args); 中的userDao,所以在代理之前,需要先有个实例化的对象

而CGlib动态代理,依赖类继承实现,本身是知道代理对象的所有结构的,所以不需要传入实例对象,所以:
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
System.out.println(“事务开启”);
Object invoke = methodProxy.invokeSuper(o,objects);
System.out.println(“事务关闭”);
return invoke;
});
第一个参数是 代理对象,而不是被代理对象,调用方法使用的是 invokeSuper() 不是invoke(),调用的是父类的接口

关于CGlib和JDK代理的详细代理过程,可以看下这篇文章
https://blog.csdn.net/ren9436/article/details/125602288

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

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

相关文章

msvcr110.dll文件丢失的解决方法

msvcr110.dll是一个动态链接库文件&#xff0c;属于Microsoft Visual C运行时库&#xff08;Runtime Library&#xff09;版本11.0。它包含了在Visual C程序中使用的函数和变量。当一个程序编译完成后&#xff0c;仍然需要一些运行时库来在操作系统上运行。这些库提供了程序所需…

记录一个错误

通过Resource注解&#xff0c;将IStateHandler接口的实现类 StateHandlerImpl注入进来 Resource private IStateHandler stateHandler;Resource注解默认按照名称进行装配&#xff0c;这里抛出异常是因为IStateHandler和StateHandlerImpl都被 Spring 容器管理&#xff0c;在进行…

GPTS应用怎么创建?GPTS无法创建应用很卡怎么办

在首届开发者大会上&#xff0c;OpenAI宣布推出了GPTs功能&#xff0c;也就是GPT Store&#xff0c;类似App Store的应用商店&#xff0c;任何用户都可以去参与创建应用。那么GPTS应用该如何创建?碰到应用无法创建很卡怎么办呢?下面就为大家带来GPTS应用创建图文教程&#xf…

ChatGPT重磅升级 奢侈品VERTU推出双模型AI手机

2023年11月7日,OpenAI举办了首届开发者大会,CEO Sam Altman(山姆奥尔特曼)展示了号称“史上最强”AI的GPT-4 Turbo。它支持长达约10万汉字的输入,具备前所未有的长文本处理能力,使更复杂的互动成为可能。此外,GPT-4 Turbo还引入了跨模态API支持,可以同时处理图片、视频和声音,从…

【C语言】深入解开指针(二)

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 &#x1f308;作者寄语 &#x1f308;&#xff1a; 小菜鸟的力量不在于它的体型&#xff0c;而在于它内心的勇气和无限的潜能&#xff0c;只要你有决心&#xff0c;就没有什么事情是不可能的…

[C++]Leetcode17电话号码的字母组合

题目描述 解题思路&#xff1a; 这是一个深度优先遍历的题目&#xff0c;涉及到多路递归&#xff0c;下面通过画图和解析来分析这道题。 首先说到的是映射关系&#xff0c;那么我们就可以通过一个字符串数组来表示映射关系&#xff08;字符串下标访问对应着数字映射到对应的…

使用Python和requests库的简单爬虫程序

这是一个使用Python和requests库的简单爬虫程序。我们将使用代理来爬取网页内容。以下是代码和解释&#xff1a; import requests from fake_useragent import UserAgent # 每行代理信息 proxy_host "jshk.com.cn" # 创建一个代理器 proxy {http: http:// proxy_…

分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测

分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测 目录 分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 Isomap-Adaboost-IHBA-…

OpenGL的学习之路-3

前面1、2介绍的都是glut编程 下面就进行opengl正是部分啦。 1.绘制点 #include <iostream> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h>void myMainWinDraw();int main(int argc,char** argv) {glutInit(&argc,argv);glutIni…

字符设备驱动基础框架

一、总体框架 1.Linux字符设备驱动工作原理图 2.驱动使用端 3.驱动实现端 二、各部分详解 1.VFS层 1) inode结构体 在Unix/Linux操作系统中&#xff0c;每个文件都由一个inode&#xff08;索引节点&#xff09;来索引。inode是特殊的磁盘块&#xff0c;它们在文件系统创建时…

【SQLite】环境安装

SQLite - C/C SQLite简介 SQLite 是一种轻量级的嵌入式数据库引擎&#xff0c;它在程序中直接访问数据库文件而不需要独立的数据库服务器。以下是一些关于 SQLite 的简介信息&#xff1a; 嵌入式数据库引擎&#xff1a; SQLite 是一种嵌入式数据库引擎&#xff0c;这意味着它…

Windows系统下使用docker部署redis

使用虚拟机部署redis&#xff0c;虚拟机很占用电脑资源&#xff0c;所以选择使用docker对redis进行部署。 一、安装docker 安装链接&#xff1a;https://docker.p2hp.com/ 二、配置redis.conf文件 下载配置文件&#xff1a;https://download.redis.io/redis-stable/redis.con…

时间序列预测实战(十五)PyTorch实现GRU模型长期预测并可视化结果

往期回顾&#xff1a;时间序列预测专栏——包含上百种时间序列模型带你从入门到精通时间序列预测 一、本文介绍 本文讲解的实战内容是GRU(门控循环单元)&#xff0c;本文的实战内容通过时间序列领域最经典的数据集——电力负荷数据集为例&#xff0c;深入的了解GRU的基本原理和…

信驰达科技加入车联网联盟(CCC),推进数字钥匙发展与应用

CCC)的会员。 图 1 深圳信驰达正式成为车联网联盟(CCC)会员 车联网联盟(CCC)是一个跨行业组织&#xff0c;致力于推动智能手机与汽车连接解决方案的技术发展。CCC涵盖了全球汽车和智能手机行业的大部分企业&#xff0c;拥有150多家成员公司。CCC成员公司包括智能手机和汽车制造…

Elasticsearch docker-compose 使用 Logstash 从 JSON 文件中预加载数据

在我们创建 Elasticsearch 进行开发时&#xff0c;最简单的办法就是在本地使用 docker-compose 来一键部署一个 Elasticsearch 集群。有时&#xff0c;特别是在准备测试环境时&#xff0c;开发人员希望从一开始就创建包含一些测试数据的数据库容器。我们可以使用 Logstash 来很…

nodejs+vue+python+PHP+微信小程序-安卓-房产中介管理信息系统的设计与实现-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

Day29力扣打卡

打卡记录 美丽塔 II&#xff08;前后缀分解 单调栈&#xff09; 链接 大佬的题解 class Solution:def maximumSumOfHeights(self, a: List[int]) -> int:n len(a)suf [0] * (n 1)st [n] # 哨兵s 0for i in range(n - 1, -1, -1):x a[i]while len(st) > 1 and …

OSG查看版本信息和32or64位

使用osgversiond命令&#xff1b; -h&#xff0c;显示帮助&#xff1b; osg使用了OpenThreads库&#xff0c;也可以查看OpenThreads的版本号&#xff1b; -r 或 -read&#xff0c;读取贡献者名单文件&#xff1b;没看到啥&#xff1b; 然后进入VS开发人员命令提示&#xff1b;…

一行JavaScrip可以做什么?

说在前面 JavaScript 提供了许多方便的方法和操作符来简化常见的任务&#xff0c;使得编程变得更加高效和便捷。无论是数学计算、字符串处理还是数据操作&#xff0c;JavaScript 都能帮助我们以简洁的方式实现所需功能。 代码 1、生成指定范围内的随机整数 const randomInt …

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline

模型简介 本基线模型共分为三个部分&#xff1a; 基于CNN的判断每张人脸是否是说话人的模型&#xff1b;基于Transformer-Encoder的判断同一段对话中不同轮次的说话人关系的模型&#xff1b;和使用上述两个预测结果求解二次型优化问题的说话人识别求解器。 基于CNN的判断每…