什么是静态代理、JDK动态代理、cglib动态代理?

静态代理

package com;
/*** @author jiaxinxiao* @date 2020年2月18日* 静态代理类的缺点:* 一个代理类只能对一个业务接口的实现类进行包装* 如果有多个业务接口的话就要定义很多实现类和代理类才行* 如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。* 所以需要动态代理:* 这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。*/
public class GenerateProxy {//静态代理测试public static void main(String[] args) {CountImpl countImpl = new CountImpl();ProxyCount countProxy = new ProxyCount(countImpl);countProxy.queryCount();countProxy.updateCount();}
}
/*** 定义账户接口* 说明业务逻辑* @author jiaxinxiao* @date 2020年2月18日*/
interface Count{//查询public void queryCount();//修改public void updateCount();
}
/*** 定义业务实现类,实现业务逻辑接口* @author jiaxinxiao* @date 2020年2月18日*/
class CountImpl implements Count{@Overridepublic void queryCount() {// TODO Auto-generated method stubSystem.out.println("查看账户");}@Overridepublic void updateCount() {// TODO Auto-generated method stubSystem.out.println("修改账户");}
}
/*** 通过组合,在代理类中创建一个业务实现类对象来调用具体的业务方法* 通过实现业务逻辑接口,来统一业务方法* 在代理类中实现业务逻辑接口中的方法时,进行预处理操作、通过业务实现类对象调用真正的业务方法、进行调用后操作的定义。* @author jiaxinxiao* @date 2020年2月18日*/
class ProxyCount implements Count{//组合一个业务实现类对象来进行真正的业务方法的调用private CountImpl countImpl;public ProxyCount(CountImpl countImpl){this.countImpl = countImpl;}@Overridepublic void queryCount() {System.out.println("预处理");countImpl.queryCount();System.out.println("查询之后");}@Overridepublic void updateCount() {System.out.println("预处理");countImpl.updateCount();System.out.println("查询之后");}}

静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。

JDK动态代理

JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。我们需要做的,只需指定代理类的预处理、调用后操作即可。

package com;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JDKProxy {//测试public static void main(String[] args) {/*** 在使用时,首先创建一个业务实现类对象和一个代理类对象,然后定义接口引用(这里使用向上转型)并用代理对象.bind(业务实现类对象)的返回值进行赋值。* 最后通过接口引用调用业务方法即可。(接口引用真正指向的是一个绑定了业务类的代理类对象,所以通过接口方法名调用的是被代理的方法们*/BooKFacade bf = new BookFacadeImpl();BookFacadeProxy bfp = new BookFacadeProxy();BooKFacade handler = (BooKFacade)bfp.bind(bf);handler.addBook();}
}
interface BooKFacade{public void addBook();
}
class BookFacadeImpl implements BooKFacade{@Overridepublic void addBook() {System.out.println("add book...");}
}
class BookFacadeProxy implements InvocationHandler{//这其实业务实现类对象,用来调用具体的业务方法 private Object target;public Object bind(Object target){this.target = target;//通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object arg0, Method arg1, Object[] arg2)throws Throwable {Object result = null;System.out.println("预处理操作----");result = arg1.invoke(target, arg2);System.out.println("调用后处理----");return result;}}

JDK动态代理的代理对象在创建时,需要使用业务实现类所实现的接口作为参数(因为在后面代理方法时需要根据接口内的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。

cglib动态代理

package com;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class CglibProxy {public static void main(String[] args) {/*** 创建业务类和代理类对象,然后通过  代理类对象.getInstance(业务类对象)  * 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。* 最后通过动态代理类对象进行方法调用。*/BookFacadeImpl2 bf2 = new BookFacadeImpl2();BookFacadeCglibProxy bfcp = new BookFacadeCglibProxy();BookFacadeImpl2 cglib = (BookFacadeImpl2)bfcp.getInstance(bf2);cglib.addBook();}
}
//首先定义业务类,无需实现接口
class BookFacadeImpl2{public void addBook(){System.out.println("新增图书...");}
}
class BookFacadeCglibProxy implements MethodInterceptor{//业务类对象,供代理方法中进行真正的业务方法调用private Object target;//相当于JDK动态代理中的绑定public Object getInstance(Object target){//给业务对象赋值this.target = target;//创建加强器,用来创建动态代理类Enhancer enhancer = new Enhancer();//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)enhancer.setSuperclass(this.target.getClass());//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦enhancer.setCallback(this);return enhancer.create();}// 实现回调方法 @Overridepublic Object intercept(Object paramObject, Method paramMethod,Object[] paramArrayOfObject, MethodProxy paramMethodProxy)throws Throwable {System.out.println("预处理---");Object result = paramMethodProxy.invokeSuper(paramObject, paramArrayOfObject);System.out.println("调用后操作---");return result;}}

三种代理比较

  • 静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;
  • JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;
  • CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;

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

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

相关文章

Leetcode82删除排序链表中重复元素2

代码: 为了找到结果的head 可以在head前加一个dummy dummy->head 再顺序去重 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* Lis…

CTFhub-RCE-过滤空格

1. 查看当前目录&#xff1a;127.0.0.1|ls 2. 查看 flag_890277429145.php 127.0.0.1|cat flag_890277429145.php 根据题目可以知道空格被过滤掉了 3.空格可以用以下字符代替&#xff1a; < 、>、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS等 $IFS在li…

idea显示pom.xml文件漂黄警告 Dependency maven:xxx:xxx is vulnerable

场景&#xff1a; idea警告某些maven依赖包有漏洞或者依赖传递有易受攻击包&#xff0c;如下&#xff1a; 解决&#xff1a; 1、打开idea设置&#xff0c;找到 File | Settings | Editor | Inspections 2、取消上述两项勾选即可

基于libcurl+libopenssl开源库编译出curl下载工具及代码集成curl功能

准备素材&#xff1a; 1. openssl的版本&#xff1a; openssl-1.1.1w.tar.gz 2.curl的版本&#xff1a;curl-8.4.0.tar.gz 目标&#xff1a; 1.编译出openssl库&#xff1b; 2.编译出curl可执行文件及库&#xff1b; 步骤一&#xff1a;先解压压缩包 tar -zxvf openssl-1…

Node.js之path路径模块

让我为大家介绍一下path路径模块吧&#xff01; 什么是path路径模块&#xff1f; path 模块是 Node.s 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对路径的处理需求。 介绍三个关于path模块的方法&#xff1a; path.join() 方法&…

Topaz Video AI:引领视频质量革命,让您的内容焕发新生

随着数字媒体的日益普及&#xff0c;视频质量的重要性日益凸显。无论是个人用户还是专业团队&#xff0c;都需要确保他们的视频内容具有最佳的质量。但是&#xff0c;由于各种原因&#xff0c;如设备限制、环境干扰等&#xff0c;往往导致视频质量不尽如人意。这时&#xff0c;…

重命名com1.{d3e34b21-9d75-101a-8c3d-00aa001a1652}文件夹

今天在win10系统上&#xff0c;发现一个名称为: com1.{d3e34b21-9d75-101a-8c3d-00aa001a1652} 的文件夹&#xff0c;该文件夹很奇怪&#xff0c;既不能手动删除&#xff0c;也不能手动给文件夹重命名&#xff0c;如图(1)所示&#xff1a; E:\EncodeOne\hello\Thumbs.ms\com1.…

uni-app 使用vscode开发uni-app

安装插件 uni-create-view 用于快速创建页面 配置插件 创建页面 输入页面名称&#xff0c;空格&#xff0c;顶部导航的标题&#xff0c;回车 自动生成页面并在pages.json中注册了路由 pages\login\login.vue <template><div class"login">login</d…

SourceTree提示128错误

错误&#xff1a; SourceTree打开报错&#xff1a;git log 失败&#xff0c;错误代码128 错误截图&#xff1a; 解决方法&#xff1a; 第一种&#xff1a; 打开电脑路径 C:\Users\Administrator &#xff0c;删除下面的【.gitconifg】文件 第二种&#xff1a; 如果上述方法…

【csapp lab】lab2_bomblab

文章目录 前言实验内容phase_1phase_2phase_3phase_4phase_5phase_6secret_phase 前言 刚做了csapp lab2&#xff0c;记录一下。 我这里用的的系统环境是Ubuntu22.04&#xff0c;是64位系统&#xff0c;与用32位系统可能有所差异。 实验共包括七个阶段&#xff0c;每个阶段考…

了解异常的特性

导言&#xff1a; 在代码时&#xff0c;即使尽可能的避开错误&#xff0c;但在程序的与运行过程中难免会出现问题&#xff0c;它可能会导致程序中断或出现不可预料的结果。本篇文章主要对异常出现时如何进行处理&#xff0c;以及如何尽量将异常实现可控化&#xff0c;进行概述…

stm32 HSUSB

/ stm32f407xx.h #define USB_OTG_HS_PERIPH_BASE 0x40040000UL #define USB_OTG_HS ((USB_OTG_GlobalTypeDef *) USB_OTG_HS_PERIPH_BASE) // // 定义全局变量 USBD_HandleTypeDef hUsbDeviceHS;并默认全零初始化/* USB Device handle structure */ typedef struct _USB…

4月2日-3日·上海 | 3DCC 第二届3D细胞培养与类器官研发峰会携手CGT Asia 重磅来袭

类器官&#xff08;Organoids&#xff09;作为干细胞研究领域最重要的成果之一&#xff0c;在基础医学研究、转化医学及药物研发领域展现出巨大的应用潜力&#xff0c;特别是在精准医疗以及药物安全性和有效性评价等方向凭借其先天优势引起了极大的市场关注&#xff0c;成为各大…

无线WiFi安全渗透与攻防(一) 无线安全环境搭建以及密码生成

无线WiFi安全渗透与攻防 一. 无线安全环境搭建1.802.11标准(1).概念(2). 802.11标准和补充2.WiFi标准3.无线接入点AP(Access Point)1.概念2.AP的分类(1).胖AP(2).瘦AP(3).用途的区别4.客户端 STA5.无线局域网AP术语介绍6.无线网卡的工作模式(1).Managed Mode(2).…

【智能家居】5、主流程设计以及外设框架编写与测试

目录 一、主流程设计 1、工厂模式结构体定义 &#xff08;1&#xff09;指令工厂 inputCmd.h &#xff08;2&#xff09;外设工厂 controlDevices.h 二、外设框架编写 1、创建外设工厂对象bathroomLight 2、编写相关函数框架 3、将浴室灯相关操作插入外设工厂链表等待被调…

pm2在Windows环境中的使用

pm2 进程管理工具可以Windows操作系统上运行&#xff0c;当一台Windows电脑上需要运行多个进程时&#xff0c;或者运维时需要运行多个进程以提供服务时。可以使用pm2&#xff0c;而不再是使用脚本。 1. 使用PM2管理进程 1.1. 启动PM2项目 1.1.1. 直接启动项目 参数说明&…

springboot集成nacos并实现自动刷新

目录 1.说明 2.示例 3.自动刷新的注意点 1.说明 springboot项目中存在好多配置文件&#xff0c;比如配置数据信息&#xff0c;redis信息等等&#xff0c;配置文件可以直接放在代码&#xff0c;也可以放在像nacos这样的组件中&#xff0c;实现动态的管理&#xff0c;修改配置…

浅谈滑动窗口

滑动窗口是什么&#xff1f; 滑动窗口其实是一个想象出来的数据结构。有左边界L和有边界R。 举例来说&#xff1a;数组 arr {3,1,5,7,6,5,8}; 其窗口就是我们规定的一个运动轨迹。 最开始时&#xff0c;边界LR都在数组的最左侧&#xff0c;此时没有包住任何数。 此时规定&…

ExoPlayer架构详解与源码分析(9)——TsExtractor

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

linux进程之进程的优先级➕环境变量

文章目录 1.优先级的认识1.1优先级的介绍1.2初识优先级1.3ps指令1.4查看/修改进程的优先级1.5对优先级的认识1.6对进程的深一步理解 2.环境变量2.0环境变量相关的命令2.1环境变量的概念2.2常见/查看环境变量2.3环境变量的作用2.4修改环境变量1.将zombie可执行程序放到PATH现有的…