Java代理模式之动态代理

2023-05-16

    代理模式是设计模式中非常重要的一种类型。代理模式从类型上来说,可以分为静态代理和动态代理两种类型。

    假设一个场景,有一个蛋糕店,卖的蛋糕都是用蛋糕机做的,而且不同种类的蛋糕由不同的蛋糕机来做,有水果蛋糕机,巧克力蛋糕机等。它们卖的面包片也是面包机做的,不同种类的面包机也是由不同的面包机来做,有红豆面包机,葡萄干面包机等。用代码描述如下。


//做蛋糕的机器 
public interface CakeMachine{ 
	void makeCake(); 
	} 
//专门做水果蛋糕的机器 
class FruitCakeMachine implements CakeMachine{ 
	public void makeCake() { 
		System.out.println("Making a fruit cake..."); 
		} 
	} 
//专门做巧克力蛋糕的机器 
public class ChocolateCakeMachine implements CakeMachine{ 
	public void makeCake() { 
		System.out.printf("making a Chocolate Cake..."); 
		} 
	} 
//做面包的机器
public interface BreadMachine { 
	void makeBread(); 
	} 
//专门做红豆面包的机器 
public class RedBeanBreadMachine implements BreadMachine { 
	public void makeBread() { 
		System.out.println("making red bean bread...."); 
		} 
	} 
//专门做葡萄干面包的机器 
public class CurrantBreadMachine implements BreadMachine{ 
	public void makeBread() { 
		System.out.println("making currant bread..."); 
		} 
	} 
//蛋糕店 
public class CakeShop { 
	public static void main(String[] args) {
		new FruitCakeMachine().makeCake(); 
		new ChocolateCakeMachine().makeCake(); 
		new RedBeanBreadMachine().makeBread(); 
		new CurrantBreadMachine().makeBread(); 
		} 
	}
}

    如果有个客户想要在水果蛋糕上面加珍珠,我们可以再做一个水果珍珠蛋糕机,但是这样成本太高,因为不能因为一个客户的请求就造一个新蛋糕机。根据修改封闭,扩展开放原则。我们可以设计一个珍珠代理类(BoboCakeProxy),先用水果蛋糕机做一个水果蛋糕,然后再加上珍珠就好了。

静态代理:

public class BoboCakeProxy implements CakeMachine{
	private CakeMachine cakemachine;
	public BoboCakeProxy(CakeMachine cakemachine){
		this.cakemachine=cakemachine;
	}
	@Override
	public void makeCake() {
		cakemachine.makeCake();
		System.out.println("add bobo");
	}	
}
//蛋糕店 
public class CakeShop { 
	public static void main(String[] args) { 
		//可以给各种各样的蛋糕加上杏仁 
		FruitCakeMachine fruitCakeMachine = new FruitCakeMachine(); 
		BoboCakeProxy boboCakeProxy = new BoboCakeProxy(fruitCakeMachine); 
		boboCakeProxy.makeCake(); 
		boboCakeProxy = new BoboCakeProxy(new ChocolateCakeMachine());
                boboCakeProxy.makeCake(); 
        } 
}
	

动态代理:

    我们只能为一种产品加上珍珠,如果要给面包加珍珠,就需要重新写一个珍珠面包代理,如果产品有100种,那么就得写100个代理类。所以要用动态代理,可以让我们只写一次实现,但是任何类型的产品都可以使用。InvocationHandler。动态代理和静态代理的区别就是静态代理只能针对特定一种产品做代理动作,而动态代理可以针对所有类型产品做代理。写一个珍珠动态代理。

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

public class BoboHandler implements InvocationHandler{
	private Object object;
	public BoboHandler(Object object){
		this.object=object;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result=method.invoke(object, args);//调用真正的蛋糕机做蛋糕
		System.out.println("add bobo");
		return result;
	}
}

蛋糕店开始工作

public class CakeShop {
	public static void main(String[] args) { 
		//动态代理(可以同时给蛋糕、面包等加珍珠) 
		//给蛋糕加上珍珠 
		FruitCakeMachine fruitCakeMachine = new FruitCakeMachine(); 
		BoboHandler boboHandler = new BoboHandler(fruitCakeMachine); 
		CakeMachine cakeMachine = (CakeMachine) Proxy.newProxyInstance(fruitCakeMachine.getClass().getClassLoader(), fruitCakeMachine.getClass().getInterfaces(), boboHandler); 
		cakeMachine.makeCake(); 
		//给面包加上珍珠 
		RedBeanBreadMachine redBeanBreadMachine = new RedBeanBreadMachine(); 
		boboHandler = new BoboHandler(redBeanBreadMachine); 
		BreadMachine breadMachine = (BreadMachine) Proxy.newProxyInstance(redBeanBreadMachine.getClass().getClassLoader(), redBeanBreadMachine.getClass().getInterfaces(), boboHandler); 
		breadMachine.makeBread(); 
		}
	}
}

    静态代理只能针对某一接口(面包 或 蛋糕)进行操作,如果要对所有接口都(所有产品)都能做一样操作,那就必须要动态代理出马了。

动态代理的几种实现方式

  • Java动态代理

  • CGLib

    Java动态代理适合有接口抽象的类代理,而CGLib适合没有接口对象的类代理。

CGLib实现方式

    Java动态代理只能针对有接口的类进行扩展,CGLib是使用继承原有类的方式来实现代理的。要是用CGLib来实现以上功能就是,先写一个珍珠拦截器类。

public class BoboInterceptor implements methodInterceptor{
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 
		methodProxy.invokeSuper(o, objects); 
	System.out.println("adding bobo..."); 
	return o; 
	}
}

然后蛋糕店通过调用拦截器类来进行加珍珠操作。

public class CakeShop { 
	public static void main(String[] args) { 
		//CGLib动态代理(可以同时给蛋糕、面包等加杏仁) 
		Enhancer enhancer = new Enhancer(); 
		enhancer.setSuperclass(FruitCakeMachine.class); 
		enhancer.setCallback(new BoboInterceptor()); 
		FruitCakeMachine fruitCakeMachine = (FruitCakeMachine) enhancer.create(); 
		fruitCakeMachine.makeCake(); 
		} 
	}
	
}

    enhancer.setSuperClass()设置需要增强的类,enhancer.setCallback()设置需要回调的拦截器,也就是实现了MethodInterceptor的接口的类。最后使用enhancer.create()生成了对应的增强类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java代理模式之动态代理 的相关文章

  • Grails 3.x bootRun 失败

    我正在尝试在 grails 3 1 11 中运行一个项目 但出现错误 失败 构建失败并出现异常 什么地方出了错 任务 bootRun 执行失败 进程 命令 C Program Files Java jdk1 8 0 111 bin java
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • 为什么 i++ 不是原子的?

    Why is i Java 中不是原子的 为了更深入地了解 Java 我尝试计算线程中循环的执行频率 所以我用了一个 private static int total 0 在主课中 我有两个线程 主题 1 打印System out prin
  • Java中反射是如何实现的?

    Java 7 语言规范很早就指出 本规范没有详细描述反射 我只是想知道 反射在Java中是如何实现的 我不是问它是如何使用的 我知道可能没有我正在寻找的具体答案 但任何信息将不胜感激 我在 Stackoverflow 上发现了这个 关于 C
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • Spark 1.3.1 上的 Apache Phoenix(4.3.1 和 4.4.0-HBase-0.98)ClassNotFoundException

    我正在尝试通过 Spark 连接到 Phoenix 并且在通过 JDBC 驱动程序打开连接时不断收到以下异常 为简洁起见 下面是完整的堆栈跟踪 Caused by java lang ClassNotFoundException org a
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 从 127.0.0.1 到 2130706433,然后再返回

    使用标准 Java 库 从 IPV4 地址的点分字符串表示形式获取的最快方法是什么 127 0 0 1 到等效的整数表示 2130706433 相应地 反转所述操作的最快方法是什么 从整数开始2130706433到字符串表示形式 127 0
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s

随机推荐

  • Spring容器应用到项目

    1 管理Service对象和DAO对象 2 Listener xff1a 监听器 xff08 监听属性创建销毁 xff09 xff0c 监听器中方便获得事件源 管理容器在项目中的生命周期 配置Listener来管理ApplicationCo
  • 使用注解配置spring

    为主配置文件引入新的命名空间 xff08 context约束 xff09 xff1b 开启使用注解代理配置文件 xff1b 在类中使用注解完成配置 xff1b 自动装配有缺点 xff1a 如果匹配到多个类型一致的对象 xff0c 将无法选择
  • ArchLinux安装全过程

    文章目录 安装桌面软件美化 arch很美好 xff0c 不多说直接开搞 xff0c 记录我的安装过程并解决问题 安装 1 镜像下载 清华大学开源镜像站 xff1a TUNA 2 虚拟机加载 选择 Arch Lnuxarchiso x86 6
  • spring bean的生命周期

    Spring Bean的完整生命周期从创建Spring容器开始 xff0c 直到最终Spring容器销毁Bean 一个Bean从创建到销毁 xff0c 如果是用BeanFactory来生成 管理Bean的话 xff0c 会经历以下几个阶段
  • 线程的状态总结以及各状态之间转换

    1 初始 xff08 NEW xff09 xff1a 新创建了一个线程对象 xff0c 但还没有调用start xff08 xff09 方法 xff1b 实现Runnable接口和继承Thread类可以得到一个线程类 xff0c new一个
  • HTTP和HTTPS

    HTTPS就是HTTP加上加密处理 xff08 一般是SSL安全通信线路 xff09 43 认证 43 完整性保护 HTTPS的作用 xff1a 内容加密 xff1a 建立一个信息安全通道 xff0c 来保证数据传输的安全 xff1b 身份
  • spring整合JDBC+spring aop事务

    1 spring整合JDBC spring中提供了一个可以操作数据库的对象 xff0c 对象封装了JDBC技术 JDBCTemplate xff1a JDBC模板对象 与DBUtils中的QueryRunner非常相似 JDBCDaoSup
  • 网站高并发&高可用处理

    1 三大问题 高并发 xff1a 多个进程或线程同时访问同一资源会产生并发问题 xff1b 高可用大数据量 2 解决方案 初级解决方案 xff1a 系统或服务器级别的解决方案 xff1a 增大服务器的CPU xff1b 增加内存条 xff1
  • 背包问题详解

    1 0 1背包问题 问题描述 xff1a 有N件物品和一个容量为V的背包 第i件物品的重量是w i xff0c 价值是p i 求解将哪些物品装入背包可使这些物品的总重量不超过背包容量 xff0c 且价值总和最大 思路 xff1a 每种物品仅
  • 堆排序原理与实现

    堆排序实际上是利用堆的性质来进行排序的 xff0c 我们通常说的堆就是二叉堆 xff0c 二叉堆又称完全二叉树或者近似完全二叉树 堆排序是选择排序的一种 可以利用数组的特点快速定位指定索引的元素 数组可以根据索引直接获取元素 xff0c 时
  • Hashmap1.7和1.8区别+ConcurrentHashmap1.7和1.8区别

    Hashmap JDK1 7中 使用一个Entry数组来存储数据 xff0c 用key的hashcode取模来决定key会被放到数组里的位置 xff0c 如果hashcode相同 xff0c 或者hashcode取模后的结果相同 xff0c
  • TOP k问题

    题目 xff1a 有1千万条短信 xff0c 有重复 xff0c 以文本文件的形式保存 xff0c 一行一条 xff0c 有重复 请用5分钟时间 xff0c 找出重复出现最多的前10条 解析 xff1a 对于本题来说 xff0c 某些面试者
  • CAS操作是怎么实现的

    CAS是compare and swap xff0c 翻译过来就是比较并交换 维护三个变量值 xff0c 一个是内存值V xff0c 一个是期望的旧的值A xff0c 一个是要更新的值B 更新一个变量的时候 xff0c 只有当预期值A与内存
  • liunx在整合springboot 项目时出现错误CLUSTERDOWN The cluster is down

    在运行springboot项目并且把项目利用二级缓存 xff0c 储存到集群中时候在idea下报错显示CLUSTERDOWN The cluster is down 可以进入linux中查看集群配置 连接到某个节点此时显示此时节点明显显示的
  • volatile关键字

    java提供了一种稍弱的同步机制 xff0c volatile变量 xff0c 用来确保将变量的更新操作通知到其他线程 当把变量声明为volatile类型的时候 xff0c 编译器与运行时都会注意到这个变量是共享的 xff0c 所以不会将该
  • MVCC

    在并发读写数据库时 xff0c 读操作可能会不一致的数据 xff08 脏读 xff09 为了避免这种情况 xff0c 需要实现数据库的并发访问控制 xff0c 最简单的方式就是加锁访问 由于加锁会将读写操作串行化 xff0c 所以不会出现不
  • AQS理解

    AbstractQueuedSynchronizer简称AQS xff0c 是一个用于构建锁和同步容器的框架 事实上concurrent包内许多类都是基于AQS构建 xff0c 例如ReentrantLock Semaphere Count
  • B树、B+树及索引

    B树 xff1a 每个节点都存储key和data xff0c 所有节点组成这棵树 xff0c 并且叶子节点指针为null B 43 树 xff1a 只有叶子节点存储data xff0c 叶子节点包含了这棵树的所有键值 xff0c 叶子节点不
  • Arrays.sort和Collections.sort实现原理解析

    Collections sort方法底层就是调用的Arrays sort方法 写一个例子看源码 xff1a public static void main String args List lt String gt strings 61 A
  • Java代理模式之动态代理

    代理模式是设计模式中非常重要的一种类型 代理模式从类型上来说 xff0c 可以分为静态代理和动态代理两种类型 假设一个场景 xff0c 有一个蛋糕店 xff0c 卖的蛋糕都是用蛋糕机做的 xff0c 而且不同种类的蛋糕由不同的蛋糕机来做 x