首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,085 阅读
2
类的加载
741 阅读
3
Spring Cloud OAuth2.0
726 阅读
4
SpringBoot自动装配原理
691 阅读
5
集合不安全问题
586 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
FastApi
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
389
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
FastApi
页面
统计
关于
搜索到
1
篇与
的结果
2022-09-04
结构型模式-代理模式
结构型模式描述如何将类或对象按某种布局组合成更大的结构,分为类结构型模式和对象结构型模式,前者采用继承来组织接口和类,后者采用组合或聚合来组合对象分为:代理模式、适配器模式、装饰者模式、桥接模式、外观模式、组合模式、享元模式1. 代理模式(1)概述由于某些原因需要给某对象提供一个代理以控制对该对象的访问,这时,访问对象不适合或不能直接引用目标对象,代理对象作为访问对象与目标对象之间的中介Java中的代理按照类生成时机的不同分为静态代理和动态代理,静态代理 代理类在编译时生成,动态代理 代理类在运行时动态生成(JDK动态代理、CGLib动态代理)(2)结构抽象主题类:通过接口或抽象类声明真实主题和代理对象实现的业务方法真实主题类:实现抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象代理类:提供与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制以及扩展真实主题的功能(3)静态代理以火车站卖票为例抽象主题类public interface SellTickets { /** * 卖票 */ void sell(); }真实主题类public class TrainStation implements SellTickets { @Override public void sell() { System.out.println("火车站卖票"); } }代理类public class ProxyPoint implements SellTickets { /** * 聚合火车站对象 */ private TrainStation trainStation = new TrainStation(); @Override public void sell() { System.out.println("代售点收取5元手续费"); trainStation.sell(); } }测试public class Client { public static void main(String[] args) { //创建代售点 ProxyPoint proxyPoint = new ProxyPoint(); //顾客从代售点买票 proxyPoint.sell(); } }(4)JDk动态代理抽象主题类public interface SellTickets { /** * 卖票 */ void sell(); }真实主题类public class TrainStation implements SellTickets { @Override public void sell() { System.out.println("火车站卖票"); } }获取代理对象的工厂类public class ProxyFactory { /** * 声明目标对象 */ private final TrainStation trainStation = new TrainStation(); /** * 获取代理对象 * * @return */ public SellTickets getProxyInstance() { //返回代理对象 /** * ClassLoader loader:类加载器(可以通过目标对象获取类加载器) * Class<?>[] interfaces:代理类实现的接口的字节码对象 * InvocationHandler h:代理对象的调用处理程序 */ return (SellTickets) Proxy.newProxyInstance( trainStation.getClass().getClassLoader(), trainStation.getClass().getInterfaces(), new InvocationHandler() { /** * Object proxy:代理对象,和proxyObject是同一个对象,在invoke方法中基本不用 * Method method:对接口中的方法进行封装的method对象 * Object[] args:调用方法的实际参数 * 返回值:方法的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代售点收取10元手续费(jdk动态代理)"); //执行目标对象的方法 return method.invoke(trainStation, args); } }); } }测试public class Client { public static void main(String[] args) { //获取代理对象 //1.创建代理工厂对象 ProxyFactory proxyFactory = new ProxyFactory(); //2.使用proxyFactory对象的方法获取代理对象 SellTickets proxyObject = proxyFactory.getProxyInstance(); //3.调用卖票的方法 proxyObject.sell(); } }Java中提供了一个动态代理类 Proxy ,即提供了一个创建代理对象的静态方法 newProxyInstance 来获取代理对象使用Arthas (阿尔萨斯)查看代理类的结构:package com.sun.proxy; import com.itheima.proxy.dynamic.jdk.SellTickets; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements SellTickets { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler invocationHandler) { super(invocationHandler); } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.itheima.proxy.dynamic.jdk.SellTickets").getMethod("sell", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException noSuchMethodException) { throw new NoSuchMethodError(noSuchMethodException.getMessage()); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError(classNotFoundException.getMessage()); } } public final boolean equals(Object object) { try { return (Boolean)this.h.invoke(this, m1, new Object[]{object}); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return (Integer)this.h.invoke(this, m0, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final void sell() { try { this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }从以上类结构可以看出:代理类 $Proxy0 实现了 SellTickets,即真实类和代理类都实现了同样的接口代理类 $Proxy0 将我们提供了的匿名内部类 invocationHandler 传递给了父类动态代理执行流程:在测试类(访问类)中通过代理对象调用 sell() 方法根据多态的特性,执行的代理类是 $Proxy0 中的 sell() 方法代理类 $Proxy0 中的 sell() 方法中又调用了 invocationHandler 接口的子实现类对象的 invoke() 方法invoke 方法通过反射执行了真实对象所属类 TrainStation 中的 sell() 方法(5)CGLib动态代理如果没有定义 SellTickets 接口,只定义了 TrainStation 火车站类,此时无法使用JDK动态代理,因为它要求必须定义接口真实主题类public class TrainStation { public void sell() { System.out.println("火车站卖票"); } }代理对象工厂public class ProxyFactory implements MethodInterceptor { /** * 声明火车站对象 */ private TrainStation trainStation = new TrainStation(); public TrainStation getProxyObject() { //创建Enhancer对象(类似于JDK代理中的Proxy) Enhancer enhancer = new Enhancer(); //设置父类的字节码对象 enhancer.setSuperclass(TrainStation.class); //设置回调函数 enhancer.setCallback(this); //创建代理对象 TrainStation proxyObject = (TrainStation) enhancer.create(); return proxyObject; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代售点收取15元手续费(CGLib代理)"); //要调用目标方法的对象 return method.invoke(trainStation, objects); } }测试public class Client { public static void main(String[] args) { //代理工厂 ProxyFactory proxyFactory = new ProxyFactory(); //获取代理对象 TrainStation proxyObject = proxyFactory.getProxyObject(); //调用sell proxyObject.sell(); } }(6)三种代理模式的对比静态代理与动态代理:动态代理将接口中声明的所有方法都转移到调用处理器一个集中的方法中处理(JDK:InvocationHandler.invoke()),在接口方法较多的情况下可以进行灵活的处理;反之静态代理每增加一个方法就需要新增对应的代理类JDK与CGLib动态代理:CGLib 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类,在 JDK1.6 之前比使用 Java反射效率要高,其中需注意:CGLib 不能对声明为 final 类型的类或方法进行代理,因为 CGLib 原理是动态生成被代理类的子类在JDK1.6、1.7、1.8逐步优化之后,在调用次数较少的情况下,其效率高于 CGLib 动态代理,在大量调用的情况下,CGLib 效率优于 JDK1.6、1.7,JDK1.8 时效率高于 CGLib有接口时使用JDK动态代理,没有接口时使用CGLib动态代理(7)优缺点代理模式在客户端与目标对象之间起到中介的作用和保护目标对象的作用可以扩展目标对象的功能将客户端与目标对象分离,降低了耦合度增加了系统的复杂度(8)使用场景远程代理(Remote)本地服务通过网络请求远程服务,将通信部份隐藏起来,只暴露给本地服务一个接口,通过该接口访问远程服务所提供的功能,而不必过多关心通信细节的部分,如:RPC 远程调用防火墙代理在浏览器配置代理功能时,防火墙将请求转发给互联网,收到响应之后再转发给浏览器保护代理控制一个对象的访问,可以给不同的用户提供不同的使用权限
2022年09月04日
97 阅读
0 评论
0 点赞