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.mzph.cn/news/145049.shtml

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

相关文章

国内crm解决方案的主要提供商有哪些?对比7家

目前国内CRM服务商1410家&#xff0c;今年1-7月CRM服务商新注册19家。如何从众多服务商中挑选出合适的一家&#xff0c;无疑是一项耗时耗力的大工程。为此&#xff0c;本文将为根据国内外知名机构、媒体、网站发布、百度指数、行业知名度等维度考量&#xff0c;选择出7大CRM系统…

【Proteus仿真】【51单片机】锂电池管理系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用LCD1602显示模块、DS18B20温度传感器、PCF8691 ADC模块、按键、LED蜂鸣器模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示温度…

MFC保存窗口客户区为图片

首先的窗口输出一些内容&#xff1b; 菜单单击函数代码&#xff1b; void CgetmypicView::OnTestGetmypic() {// TODO: 在此添加命令处理程序代码HWND hwnd this->GetSafeHwnd();HDC hDC ::GetWindowDC(hwnd);//获取DC RECT rect;::GetClientRect(hwnd, &rect)…

C/C++输出整数部分 2021年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C输出整数部分 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C输出整数部分 2021年12月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个双精度浮点数f&#xff0c; 输出其整…

【918.环形子数组的最大和】

目录 一、题目描述二、算法原理三、代码实现 一、题目描述 二、算法原理 三、代码实现 class Solution { public:int maxSubarraySumCircular(vector<int>& nums) {int sum0;for(auto x:nums) sumx;vector<int> f(nums.size());vector<int> g(nums.size…

JS-项目实战-点击水果名修改特定水果库存记录

1、fruit.js function $(name) {if (name) {//假设name是 #fruit_tblif (name.startsWith("#")) {name name.substring(1); //fruit_tblreturn document.getElementById(name);} else {return document.getElementsByName(name); //返回的是NodeList类型}} }//当…

机器视觉公司怎么可能养我这闲人,连软件加密狗都用不起,项目都用盗版,为什么​?

正版价值观我是认同的&#xff0c;但是同行也不用软件加密狗&#xff0c;你让我承担过多的设备成本&#xff0c;终端客户不愿意承担加密狗的成本&#xff0c;公司更不愿意去承担&#xff0c;许多机器视觉公司“零元购”&#xff0c;机器视觉软件加密狗都用不起&#xff0c;项目…

48v变12v同步转换芯片

48v变12v同步转换芯片 以下是一篇关于48V变12V同步转换器WD5105ic的文章正文&#xff1a;48V变12V同步转换器WD5105ic是一种电源管理芯片&#xff0c;它可以将48V的直流电压转换为12V的直流电压。这款芯片具有广泛的应用范围&#xff0c;包括车载充电器件、电动车仪表器件、电…

基于SSM的智慧养老平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

郑州大学2020级信息安全专业——保研小结

最终上岸 夏令营&#xff1a; 夏令营开始的时间一般比较早&#xff0c;在期末考试之前就已经开始了&#xff0c;需要提前联系导师&#xff0c;有的学校是弱com&#xff0c;导师愿意要你入营的概率和优营的概率就会比较大&#xff0c;因此要提前联系导师&#xff0c;复习好项目…

51单片机应用从零开始(五)·加减乘除运算

51单片机应用从零开始&#xff08;一&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;二&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;三&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;四&#xff09;-CSDN博客 详解 KEIL C51 软件的使用建立工程…

conan 入门指南

conan 新手入门 1 需要注意的事项2 使用 Poco 库的 MD5 哈希计算器2.1 创建源文件2.2 搜索poco conan 库2.3 获取poco/1.9.4的元数据2.4 创建conanfile.txt2.5 安装依赖2.6 创建编译文件2.7 构建和运行程序 3 安装依赖程序4 检查依赖关系5 搜索软件包6 与其他配置一起构建 该篇…

Resolume Arena 7.15.0(VJ音视频软件)

Resolume Arena 7是一款专业的实时视觉效果软件&#xff0c;用于创造引人入胜的视频演出和灯光秀。它提供了丰富多样的功能和工具&#xff0c;可以将音频、视频和图像合成在一起&#xff0c;创造出令人惊叹的视觉效果。 Resolume Arena 7支持多种媒体格式&#xff0c;包括视频文…

LeetCode(25)验证回文串【双指针】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 验证回文串 1.题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&…

微机原理_10

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。&#xff09; 1,将二进制数110110.01转换为十六进制为(&#xff09; A. 66.1H B. 36.4H C. 66.4 D. 36.2 2,一台计算机的字长是4个字节,含义是(&#xff09; A.能处理的最大…

<MySQL> 什么是数据库索引?数据库索引的底层结构是什么?

目录 一、什么是数据库索引? 1.1 索引的概念 1.2 索引的特点 1.3 索引的适用场景 1.4 索引的使用 1.4.1 创建索引 1.4.2 查看索引 1.4.3 删除索引 二、数据库索引的底层结构是什么&#xff1f; 2.1 数据库中的 B树 长啥样&#xff1f; 2.2 B树为什么适合做数据库索…

【漏洞复现】OneThink前台注入漏洞

漏洞描述 OneThink 是一个基于 PHP 的开源内容管理框架&#xff0c;旨在简化和加速Web应用程序的开发过程。它提供了一系列通用的模块和功能&#xff0c;使开发者能够更轻松地构建具有灵活性和可扩展性的内容管理系统&#xff08;CMS&#xff09;和其他Web应用。 免责声明 …

Meta降本增效大招之:弃用产品

今晚无意间进入去哪儿技术沙龙的直播间&#xff0c;听到他们要删除50%的代码和停掉50%的服务。我就想起Meta公司最近写的这篇博客&#xff1a;Automating product deprecation。 这篇博客对于效能平台的建设非常具有指导意义。文章最后有原文链接和我个人的总结。 这是一个系列…

扩散模型实战(九):使用CLIP模型引导和控制扩散模型

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#xff…

接口自动化测试面试题

前言 前面总结了一篇关于接口测试的常规面试题&#xff0c;现在接口自动化测试用的比较多&#xff0c;也是被很多公司看好。那么想做接口自动化测试需要具备哪些能力呢&#xff1f; 也就是面试的过程中&#xff0c;面试官会考哪些问题&#xff0c;知道你是不是真的做过接口自动…