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.hqwc.cn/news/180120.html

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

相关文章

基于平衡优化器算法优化概率神经网络PNN的分类预测 - 附代码

基于平衡优化器算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于平衡优化器算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于平衡优化器优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针…

构造函数和初始化列表的关系和区别【详解】

构造函数和初始化列表关系和区别&#xff0c;以及为什么有初始化列表&#xff0c;和它的好处 一、构造函数和初始化列表的关系和区别二、为什么有初始化列表三、使用初始化列表的好处 一、构造函数和初始化列表的关系和区别 百度百科这样定义初始化列表&#xff1a;与其他函数…

CocosCreator3.8神秘面纱 CocosCreator 项目结构说明及编辑器的简单使用

我们通过Dashboard 创建一个2d项目&#xff0c;来演示CocosCreator 的项目结构。 等待创建完成后&#xff0c;会得到以下项目工程&#xff1a; 一、assets文件夹 assets文件夹&#xff1a;为资源目录&#xff0c;用来存储所有的本地资源&#xff0c;如各种图片&#xff0c;脚本…

nodejs+vue黄河风景线旅游网站的设计与实现-微信小程序-安卓-python-PHP-计算机毕业设计

本文首先对该系统进行了详细地描述&#xff0c;然后对该系统进行了详细的描述。管理人员增加了系统首页、个人中心、用户管理、景点分类管理、景点简介管理、旅游路线管理、文章分类管理、公告文章管理、系统管理理等功能。这套黄河风景线旅游网站是根据当前的现实需要&#xf…

Nginx配置开启HTTPS

获取证书文件 Nginx 开启SSL server {listen 443 default ssl;server_name localhost;#charset koi8-r;#access_log logs/host.access.log main;proxy_set_header Host $host;ssl_certificate /usr/local/nginx/cert/server.pem;ssl_certificate_key /usr/local/ngin…

大数据爬虫分析基于Python+Django旅游大数据分析系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于Python和Django的旅游大数据分析系统是一种使用Python编程语言和Django框架开发的系统&#xff0c;用于处理和分…

OpenAI与微软合作,构建 ChatGPT 5 模型;10天准确天气预报

&#x1f989; AI新闻 &#x1f680; OpenAI与微软合作&#xff0c;构建 ChatGPT 5 模型&#xff0c;下一代人工智能或拥有超级智能 摘要&#xff1a;OpenAI首席执行官 Sam Altman 在接受采访时表示&#xff0c;OpenAI正在与微软合作构建下一代人工智能模型 ChatGPT 5&#x…

人工智能基础_机器学习037_多项式回归升维实战4_使用随机梯度下降模型_对天猫双十一销量数据进行预测_拟合---人工智能工作笔记0077

上一节我们使用线性回归模型最终拟合了双十一天猫销量数据,升维后的数据. 我们使用SGDRegressor的时候,随机梯度下降的时候,发现有问题, 对吧,怎么都不能拟合我们看看怎么回事现在 可以看到上面是之前的代码 上面是对数据的准备 这里我们还是修改,使用 poly=PolynomialFeatur…

第14届蓝桥杯青少组python试题解析:22年10月选拔赛

选择题 T1. 执行print (5%3) 语句后&#xff0c;输出的结果是 ( ) 0 1 2 3 T2. 以下选项中&#xff0c;哪一个是乘法运算符?&#xff08;&#xff09; % // * ** T3. 已知x3&#xff0c;求x//2x**2的运算结果? 7.5 10 8 10.5 T4. 以下选项中&#xff0c;对下面程序的打印…

【Phoenix】请求的生命周期

本文的目的是讨论Phoenix请求的生命周期。我们实战添加两个新的页面&#xff0c;并讨论整个过程是如何串起来的。 让我们从添加第一个新页面开始。 添加一个新页面 web应用通常通过将HTTP方法和路径映射到应用的某个函数来处理请求。Phoenix通过路由器来实现这个匹配。例如将…

《effective C++》条款10

令operator返回一个reference to *this int main() {int a, b, c 5;a b c;cout << a; } 这个代码&#xff0c;很明显输出的是5。所以我们在写这种连续赋值的时候&#xff0c;其对应的赋值运算符应当返回一个*this &#xff1a; class A { public:A(string ss, int x) …

Swift--基本运算符与程序流程控制

系列文章目录 第一章&#xff1a;量值与基本数据类型 第二章&#xff1a;字符、字符串与集合类型 文章目录 系列文章目录空合并运算符区间运算符循环结构while与repeat-while条件循环结构 空合并运算符 可选值类型是Swift语言的一个独特之处&#xff0c;空合并运算符就是针对…