java初探之代理模式

代理模式

代理模式一般有三种角色:

在这里插入图片描述

没有使用代理模式的话可能就会直接去操作真实的对象

加入代理模式就是加入了 隔离 把我们的真实对象与调用者隔离了一下(代理对象)

代理对象的好处?

使用者(client)跟真实的对象是没有直接的交集的。不会直接操作到真实对象

实例
//1.代理角色对象 定义了服务的接口
public interface Massage{void message();
}
//2.真实的实现类:提供马杀鸡服务的路西
public class Lucy implements Massage{@Overridepublic void message(){System.out.println("手法一流");}
}public class Alvin implements Massage{@Overridepublic void massage(){System.out.println("精通各种手法")}
}
//3.代理对象 马杀鸡经纪人
public class Agent implements Massage{private final Massage massage;public Agent(Massage massage){this.massage = massage;}//前置处理public void before(){System.out.println("前置开始");}//后置处理public void after(){System.out.println("后置处理");}@Overridepublic void massage(){before();massage.massage();after();}
}public class MyClass{public static void main(String[] args) throws Exception{//静态代理Massage massage = new Lucy();Agent agent = new Agent(massage);agent.massage();//没有直接跟lucy交互}

每个代理类只能为一个接口来服务

如果有多个功能就要写多个代理类如:

public class WashAgent implements Wash{@Overridepublic void wash(){}
}

想办法通过一个代理类实现全部的代理功能!->动态代理

public class MyClass{public static void main(String[] args) throws Exception{//动态代理 完成足浴与按摩Alvin alvin = new Alvin();//真实的要操作的对象//Proxy创建 动态代理对象Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(),new Class[]{Message.class,Wash.class},new InvocationHandler(){@OVerridepublic Object invoke(Object o,Method method,Object[] objects)throws Throwable{//System.out.println(o.toString()); 死循环 o就是Object o 调用o.任何方法都会进入invoke()中 就会一直调然后死循环//invoke(在那个对象上执行的方法,方法参数)return method.invoke(alvin,objects);}});Massage massage = (Massage) o;massage.massage();Wash wash = (Wash) o;wash.wash();}
}public class Alvin implements Massage,Wash{@Overridepublic void massage(){System.out.println("massage...");}@Overridepublic void wash(){System.out.println("washing...");}
}

源码解析

Proxy.class://生成 class数据 动态代理为我们创建的对象 
byte[] var22 = ProxyGenerator.generateProxyClass(var23,var2,var17);test:
private static void proxy() throws Exception{String name = Massage.class.getName()+"$Proxy0";//生成代理指定接口的class数据byte[] bytes = ProxyGenerator.generateProxyClass(name,new Class[]{Massage.class});FileOutputStream fos = new FileOutputStream("lib/"+name+".class");fos.wirte(bytes);fos.close();
}
com.enjoy.lib.Massage$Proxy0.classpublic final class Massage$Proxy0 extends Proxy implements Massage{public Massage$Proxy0(InvocationHandler var1)throws{//这里的invovationHandler就是new ProxyInstance传入的super(var1);}public final void massage() throws{try{//super.h===var1;//给接口赋值 这样newProxyInstance就会被回调出去super.h.invoke(this,m3,(Object][])null); }catch(Throwable var3){throw new UndeclaredThrowableException(var3);}}public final String toString() throws{try{return (String)super.h.invoke(this,m2,(Object[])null);}catch(Throwable var3){throw new UndeclaredThrowableException(var3);}}}    

Retrofit实操

public interface WetherApi{@POST("/v3/weather/weatherInfo")@FormUrlEncodedCall<ResponseBody> getWeather(@Field("city") String city,@Field("key") String key);@GET("/v3/weather/weatherInfo")Call<ResponseBody> getWeather(@Query("city") String city,@Query("key") String key);
}Retrofit retrofit = new Retrofit.Builder().baseUrl("https://restapi.amap.com").build();//create()就是内部完成了动态代理 
WeatherApi weatherApi = retrofit.create(WetherApi.class);
public class EnjoyRetrofit{//第一次调用解析一次 第二次调用又去解析一次吗final Map<Method,ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();final Call.Factory callFactory;final HttpUrl baseUrl;EnjoyRetrofit(Call.Factory callFactory,HttpUrl baseUrl){this.callFactory = callFactory;this.baseUrl = baseUrl;}public <T> T create(final Class<T> service){return (T) Proxy.newInstance(service.getClassLoader(),new Class[]{service},new InvocationHandler(){@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable{//实现对应的postWeather/getWeather//解析method上所有的注解信息loadServiceMethod(method);return serviceMethod.invoke(args);//返回Call}});}//解析方法上的注解private ServiceMethod loadServiceMethod(Method method){//先不上锁 避免synchronized的性能损耗ServiceMethod result = serviceMethodCache.get(method);if(result!=null) return result;//多线程下避免重复解析synchronized(serviceCache){//线程A和B进入时 A先进 result=null 给result赋值后B进入 如果不判断是否为空 会再次解析一次 result = serviceCache.get(method);if(result==null){result = new ServiceMethod.Builder(this,method).build();serviceMethodCache.put(method,result);}}return result;}//构建者模式 不需要关心成员的细节 只需要关心你想要设置的内容  很好的屏蔽掉细节public static final class Builder{private HttpUrl baseUrl;private okhttp3.Call.Factory callFactory;public Builder callFactory(okhttp3.Call.Factory factory){this.callFactory = factory;return this;}public Builder baseUrl(String baseUrl){this.baseUrl = HttpUrl.get(baseUrl);return this;}public EnjoyRetrofit build(){if(baseUrl==null){throw new IllegalStateException("Base URL,required");}okhttp3.Call.Factory callFactory = this.callFactory;if(callFactory==null){callFactory = new OkHttpClient();}return new EnjoyRetrofit(callFactory,baseUrl);}}
}
//可以设置也可以不设置 build会进行校验  
EnjoyRetrofit.Builder().baseUrl("https").callFactory(new OkHttpClient.Builder().callTimeout(1)).build();
//记录请求类型 请求参数 完整地址
public class ServiceMethod{String baseUrl;private final okhttp3.Call.Factory callFactory;String httpMethod;String relativeUrl;Boolean hasBody;private FormBody.Builder formBuild;//每个参数的keyParameterHandler[] parameterHandler;HttpUrl.Builder urlBuilder;//完整的urlpublic ServiceMethod(Builder builder){baseUrl = builder.enjoyRetrofit.baseUrl;callFactory = builder.enjoyRetrofit.callFactory;httpMethod = builder.httpMethod;relativeUrl = builder.relativeUrl;hasBody = builder.hasBody;parameterHandler = builder.parameterHandler;//如果有请求体 创建 一个okhttp的请求体对象 if(hasBody){formBuild = new FormBody.Builder();}}public Object invoke(Object[] args){//处理请求的地址与参数 重点for(int i=0;i<parameterHandler.length;i++){ParameterHandler handlers = parameterHandler[i]; //handler记录了key//handler内本来就记录了key 现在给到了对应的valuehandlers.apply(this,args[i].toString());//this->ServiceMethod记录了请求地址 args[i]记录了参数的value}//获取最终请求地址HttpUrl url;if(urlBuilder ==null){//说明不是get请求urlBuilder = baseUrl.newBuilder(relativeUrl); }url = urlBuilder.build();//请求体FormBody formBody = null;if(formBuild!=null){formBody =  formBuild.build();}//使用okhttp发送请求 get请求时formBody==null没关系可以传入Request request = new Request.Builder().url(url).method(httpMethod,formBody).build();return callFactory.newCall(request);}//get请求 把k-v 拼到url里面public void addQueryParameter(String key,String value){if(urlBuilder ==null){urlBuilder = baseUrl.newBuilder(relativeUrl);}urlBuilder.addQuery(key,value);}//吧k-v放到请求体中public void addFieldParameter(String key,String value){formBuild.add(key,value);}public static class Builder{private final EnjoyRetrofit enjoyRetrofit;private final Annotation[] methodA nnotations;private final Annotation[][] parameterAnnotations;private String httpMethod;private String relativeUrl;private Boolean hasBody;private ParameterHandler[] parameterHandler;public Builder(EnjoyRetrofit enjoyRetrofit,Method method){this.enjoyRetrofit = enjoyRetrofit;//获取方法上的所有注解methodAnnotations = method.getAnnotations();//获得方法参数的所有的注解(一个参数可以有多个注解,一个方法又会有多个参数)paramterAnnotations = method.getParameterAnnotations();}public ServiceMethod build(){//1.解析方法上的注解 只处理POST和GETfor(Annotation methodAnnotation:methodAnnotations){if(methodAnnotation instance of POST){//post请求//记录当前请求方式this.httpMethod = "POST";//记录当前url的paththis.relativeUrl = ((POST) methodAnnotation).getValue();//是否有请求体this.hasBody = true;}else if(methodAnnotation instance of GET){this.httpMethod = "GET";this.relativeUrl = ((GET) methodAnnotation).getValue();this.hasBody = false;}}//2.解析方法参数的注解int length = paramterAnnotations.length;//有多少个参数parameterHandler = new ParameterHandler[length];for(int i=0;i< length;i++){//一个参数上面所有的注解Annotation[] annotations = parameterAnnotations[i];//处理参数上的每一个注解for(Annotation annotation:annotations){if(annotation instance of Field){//得到注解上的value 请求参数的keyString value = ((Field) annotation).getValue();//又在一个新的类中记录了请求参数的keyparameterHandler[i] = new ParameterHandler.FieldParameterHandler(value);}else if(annotation instance of Query){String value = ((Query) annotation).getValue();parameterHandler[i] = new ParameterHandler.QueryParameterHandler(value);}}}return new ServiceMethod(this);}} 
}
//
public abstract class ParameterHandler{abstract void apply(ServiceMethod serviceMethod,String value);//只处理get请求 没有请求头static class QueryParameterHandler extends ParameterHandler{String key;public QueryParameterHandler(String key){this.key = key;}@Overridevoid apply(ServiceMethod serviceMethod,String value){serviceMethod.addQueryParameter(key,value);//回调到serviceMethod中}}//只处理post请求 带请求头static class FiledParameterHander extends ParameterHandler{String key;public FiledParameterHandler(String key){this.key = key;}@Overridevoid apply(ServiceMethod serviceMethod,String value){serviceMethod.addFieldParameter(key,value);//回调到serviceMethod中}}
}

/回调到serviceMethod中
}
}

//只处理post请求 带请求头
static class FiledParameterHander extends ParameterHandler{String key;public FiledParameterHandler(String key){this.key = key;}@Overridevoid apply(ServiceMethod serviceMethod,String value){serviceMethod.addFieldParameter(key,value);//回调到serviceMethod中}
}

}


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

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

相关文章

.Net8 Blazor 尝鲜

全栈 Web UI 随着 .NET 8 的发布&#xff0c;Blazor 已成为全堆栈 Web UI 框架&#xff0c;可用于开发在组件或页面级别呈现内容的应用&#xff0c;其中包含&#xff1a; 用于生成静态 HTML 的静态服务器呈现。使用 Blazor Server 托管模型的交互式服务器呈现。使用 Blazor W…

Games104现代游戏引擎笔记 面向数据编程与任务系统

Basics of Parallel Programming 并行编程的基础 核达到了上限&#xff0c;无法越做越快&#xff0c;只能通过更多的核来解决问题 Process 进程 有独立的存储单元&#xff0c;系统去管理&#xff0c;需要通过特殊机制去交换信息 Thread 线程 在进程之内&#xff0c;共享了内存…

后端接口错误总结

今天后端错误总结&#xff1a; 1.ConditionalOnExpression(“${spring.kafka.exclusive-group.enable:false}”) 这个标签负责加载Bean&#xff0c;因此这个位置必须打开&#xff0c;如果这个标签不打开就会报错 问题解决&#xff1a;这里的配置在application.yml文件中 kaf…

HelloWorld - 从Houdini导出HDA到UE5

1.配置插件 在Houdini安装目录下找到对应版本引擎的插件&#xff0c;例如这里是Houdini19对应UE5.2的版本&#xff0c;我们就要保证先下载好UE5.2&#xff1a; 将Houdini插件粘贴到UE安装目录的Plugins文件夹下&#xff1a; 目前插件配置完成&#xff0c;打开UE会自动启用插…

C与汇编深入分析

汇编怎么调用C函数 直接调用 BL main传参数 在arm中有个ATPCS规则&#xff08;ARM-THUMB procedure call standard&#xff09;&#xff08;ARM-Thumb过程调用标准&#xff09;。 约定r0-r15寄存器的用途&#xff1a; r0-r3&#xff1a;调用者和被调用者之间传递参数r4-r11…

【python】Django——django简介、django安装、创建项目、快速上手

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ 【Django专栏】 Django——django简介、django安装、创建项目、快速上手 Django——templates模板、静态文件、django模板语法、请求和响应 Django——连接mysql数据库 Django——django安装、创建django项目、dj…

提高生存能力的7个关键技巧!

作为一款备受热议和玩家喜爱的多人在线射击游戏&#xff0c;《绝地求生》中生存能力的提高是取得胜利的关键。在这篇实用干货分享中&#xff0c;我们将详细说明7个关键技巧&#xff0c;帮助你在游戏中提高生存能力&#xff0c;获得更多胜利。 1.选择降落点&#xff1a;选择适合…

Typora使用教程

文章目录 markdown的使用说明一、标题 这是一级标题这是二级标题二、段落1、换行2、分割线 三、文字显示1、字体2、上下标 四、列表1、无序列表2、有序列表3、任务列表 五、区块显示六、代码显示1、行内代码2、代码块 七、链接八、脚注九、图片插入十、表格十一、流程图1、横向…

excel怎么能保证粘贴公式的时候不自增

例如在C4单元格中输入了公式&#xff1a; 现在如果把C4拷贝到C5&#xff0c;D3会自增长为D4&#xff1a; 现在如果想拷贝的时候不自增长&#xff0c;可以先把光标放到C4单元格&#xff0c;然后按F4键&#xff0c;加上了$符号&#xff0c;锁定了&#xff1a; 现在再拷贝&a…

kubernetes资源管理

资源管理 资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 kubernetes的本质上就是一个集群系统&#xff0c;用户可以在集群中部署各种服务&#xff0c;所谓的部署服务&#xff0c;其实就是在kubernetes集…

人均年薪70万!华为项目经理具备了哪些能力

大家好&#xff0c;我是老原。 最近在逛脉脉的时候&#xff0c;看到了一位华为项目经理晒出的月收入&#xff1a;5W&#xff0c;这还是不包含每年分红奖励前的到手薪资。 按他现在的19级别&#xff0c;再加上分红奖励&#xff0c;年薪至少在70W&#xff0c;留言区羡慕声一片。…

Since Maven 3.8.1 http repositories are blocked

原因 高版本的maven不支持http的存储库。 解决方案 其实方法有好几种&#xff0c;比如降级maven版本至3.6.3(之前一直用的都是这个版本)&#xff0c;我选择了一种比较快(但不一定安全)的方式&#xff0c;因为3.6.3版本被我卸载了&#xff0c;这里直接修改idea的setting配置&…

【数据处理】Python:实现求条件分布函数 | 求平均值方差和协方差 | 求函数函数期望值的函数 | 概率论

猛戳订阅&#xff01; &#x1f449; 《一起玩蛇》&#x1f40d; &#x1f4ad; 写在前面&#xff1a;本章我们将通过 Python 手动实现条件分布函数的计算&#xff0c;实现求平均值&#xff0c;方差和协方差函数&#xff0c;实现求函数期望值的函数。部署的测试代码放到文后了&…

DNS正向解析和主从复制

目录 概念 DNS解析 例&#xff1a;www.baidu.com. 解析过程 DNS查询方式 DNS的查询过程 DNS软件bind 正向解析&#xff08;根据域名查找ip地址&#xff09; 1.先安装bind软件 2.打开网卡配置文件 将DNS1改为自己本机 &#xff08;更改完配置重启服务&#xff09; 3.打…

最长上升子序列模型 笔记

首先附上模板&#xff1a; #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std;typedef pair<int, int> PII; typedef long long ll;const int N 100010;int n; int a[N], q[N];int main()…

MySQL库的操作『增删改查 ‖ 编码问题 ‖ 备份与恢复』

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; MySQL 学习 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 &#x1f381;软件版本&#xff1a; MySQL 5.7.44 文章目录 1.创建数据库2.数据库中的编码问题2.1.字符集与校验集2.3.支持的字符…

DNS域名解析服务

1.概述 1.1.产生原因 IP 地址:是互联网上计算机唯一的逻辑地址&#xff0c;通过IP 地址实现不同计算机之间的相互通信&#xff0c;每台联网计算机都需要通过I 地址来互相联系和分别&#xff0c;但由于P 地址是由一串容易混淆的数字串构成&#xff0c;人们很难记忆所有计算机的…

python 实验7

姓名&#xff1a;轨迹 学号&#xff1a;6666 专业年级&#xff1a;2021级软件工程 班级&#xff1a; 66 实验的准备阶段 (指导教师填写) 课程名称 Python开发与应用 实验名称 文件异常应用 实验目的 &#xff08;1&#xff09;掌握基本文件读写的方式&#xff1b; …

【仿真动画】ABB IRB 8700 机器人搬运(ruckig在线轨迹生成)动画欣赏

场景 动画 一、IRB 8700简介 二、动画脚本重点分析 2.1 sim.moveToPose 通过在两个 poses 之间执行插值&#xff0c;使用 Ruckig 在线轨迹生成器生成对象运动数据。该函数可以通过处理 4 个运动变量&#xff08;x、y、z 和两个姿势之间的角度&#xff09;或单个运动变量&#…

linux 网络 cat /proc/net/dev 查看测试网络丢包情况

可以通过 cat /proc/net/dev 查看测试网络丢包情况&#xff0c;drop关键字&#xff0c;查看所有网卡的丢包情况 还可以看其他数据&#xff0c; /proc/net/下面有如下文件