首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,082 阅读
2
类的加载
741 阅读
3
Spring Cloud OAuth2.0
726 阅读
4
SpringBoot自动装配原理
691 阅读
5
集合不安全问题
584 阅读
笔记
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
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
388
篇文章
累计收到
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
页面
统计
关于
搜索到
2
篇与
的结果
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日
96 阅读
0 评论
0 点赞
2020-12-16
代理模式
代理模式代理模式的分类:静态代理动态代理自己 --- > 租房中介 --- > 房东1、静态代理角色分析:抽象角色:一般使用抽象类或接口真实角色:被代理的角色代理角色:代理真实角色,同时可以做一些附属操作客户:访问代理对象的人租房Demo:1、接口package com.sw.demo01; /** * @Author suaxi * @Date 2020/12/16 10:06 */ //租房 public interface Rent { public void rent(); } 2、真实角色package com.sw.demo01; /** * @Author suaxi * @Date 2020/12/16 10:08 */ //房东 public class Host implements Rent{ public void rent() { System.out.println("房东要出租房子"); } } 3、代理角色package com.sw.demo01; /** * @Author suaxi * @Date 2020/12/16 10:10 */ public class Proxy { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void rent(){ seeHouse(); host.rent(); hetong(); getFee(); } //看房 public void seeHouse(){ System.out.println("中介带租客看房!"); } //签合同 public void hetong(){ System.out.println("签租赁合同"); } //收中介费 public void getFee(){ System.out.println("中介收取中介费用!"); } } 4、客户端访问代理角色package com.sw.demo01; /** * @Author suaxi * @Date 2020/12/16 10:09 */ public class Client { public static void main(String[] args) { //房东想要出租房子 Host host = new Host(); //通过中介帮房东代理发布出租信息,同时中介角色带有一些附属操作 Proxy proxy = new Proxy(host); //客户不用面对房东,直接找中介即可 proxy.rent(); } } 静态代理的优点:可以使真实角色(房东)的操作更加纯粹,即只做租房一件事,不用去关注其他的公共事务公共事务交给代理角色(中介),实现业务分工公共业务需要拓展的时候,方便集中管理缺点:一个真实角色就需要对应的一个代理角色,开发效率低。2、动态代理动态代理与静态代理的角色一样代理类是动态生成的分为两类:基于接口的动态代理,基于类的动态代理基于接口:JDK动态代理基于类:cglibJava字节码实现:javasist动态代理的优点:可以使真实角色的操作更加纯粹,不用去关注其他的公共事务公共事务交给代理角色,实现业务分工公共业务需要拓展的时候,方便集中管理一个动态代理类代理的是一个接口,即对应一类业务一个动态代理可以代理多个类,只要实现同一个接口即可1、接口package com.sw.demo04; /** * @Author suaxi * @Date 2020/12/16 11:00 */ public interface UserService { public void add(); public void delete(); public void find(); public void update(); } 2、真实角色package com.sw.demo04; /** * @Author suaxi * @Date 2020/12/16 11:01 */ public class UserServiceImpl implements UserService{ public void add() { System.out.println("新增了一个用户"); } public void delete() { System.out.println("删除了一个用户"); } public void find() { System.out.println("查询用户"); } public void update() { System.out.println("修改用户信息"); } } 3、ProxyInvocationHandlerpackage com.sw.demo04; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @Author suaxi * @Date 2020/12/16 10:39 */ public class ProxyInvocationHandler implements InvocationHandler { //被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } //生成代理对象 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //处理代理实例,并返回结果 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log(method.getName()); Object result = method.invoke(target, args); return result; } public void log(String msg){ System.out.println("执行了"+msg+"方法!"); } } 4、具体实现package com.sw.demo04; /** * @Author suaxi * @Date 2020/12/16 10:57 */ public class Client { public static void main(String[] args) { //真实角色 UserServiceImpl userService = new UserServiceImpl(); //代理角色(不存在) ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setTarget(userService); //设置要代理的对象 //动态生成代理类 UserService proxy = (UserService) pih.getProxy(); proxy.add(); } } 代理多个类时,只要实现同一个UserService接口即可UserServiceImpl01 userService = new UserServiceImpl01(); UserServiceImpl02 userService = new UserServiceImpl02(); ……
2020年12月16日
92 阅读
0 评论
0 点赞