java初探之代理模式

news2024/11/25 14:30:31

代理模式

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

在这里插入图片描述

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

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

代理对象的好处?

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

实例
//1.代理角色对象 定义了服务的接口
public interface Massage{
    void message();
}
//2.真实的实现类:提供马杀鸡服务的路西
public class Lucy implements Massage{
    
    @Override
    public void message(){
        System.out.println("手法一流");
    }
}


public class Alvin implements Massage{
    
    @Override
    public 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("后置处理");
    }
    
    @Override
    public 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{
    @Override
    public 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(){
            @OVerride
            public 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{
    
    @Override
    public void massage(){
        System.out.println("massage...");
    }
    
    @Override
    public 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.class

public 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")
    @FormUrlEncoded
    Call<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(){
           @Override
            public 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;
    //每个参数的key
    ParameterHandler[] parameterHandler;
    HttpUrl.Builder urlBuilder;//完整的url
    
    public 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 现在给到了对应的value
            handlers.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和GET
            for(Annotation methodAnnotation:methodAnnotations){
                if(methodAnnotation instance of POST){//post请求
                    //记录当前请求方式
                    this.httpMethod = "POST";
                    //记录当前url的path
                    this.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 请求参数的key
                        String value = ((Field) annotation).getValue();
                        //又在一个新的类中记录了请求参数的key
                        parameterHandler[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;
        }
        
        @Override
        void 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;
        }
        
        @Override
        void 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;
    }
    
    @Override
    void apply(ServiceMethod serviceMethod,String value){
        serviceMethod.addFieldParameter(key,value);//回调到serviceMethod中
    }
}

}


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

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

相关文章

蓝桥杯算法双周赛心得——深秋的苹果(二分+贪心分组前缀和)

大家好&#xff0c;我是晴天学长&#xff0c;二分的check函数&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .深秋的苹果 问题描述 当深秋的苹果树丰收时&#xff0c;村庄的居民们兴致勃勃地采摘着红彤…

c语言从入门到实战——数组指针与函数指针

数组指针与函数指针 前言1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么&#xff1f;2.2 数组指针变量怎么初始化? 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用4.3 两段有趣的代码4.3.1 typedef关键字 5. 函数指针数组6. 转移…

【AIGC】一起学习prompt提示词(4/4)【经典】【15种提示词技巧】

写的时候并没有设计好&#xff0c;要做多少期&#xff0c;还是有始有终的比较好&#xff0c;为了方便阅读&#xff0c;我把之前的3期&#xff0c;改下名字&#xff0c;放到这里。 【AIGC】一起学习prompt提示词&#xff08;1/4&#xff09; 内容摘要&#xff1a;提示词是什么…

借教室——二分、前缀和、差分

题目 思路 当某一份订单可以满足的时候&#xff0c;那么他前面的所有订单都可以满足&#xff0c;当某一份订单不能满足的时候&#xff0c;那么他后面的所有订单都不能完成&#xff0c;所以可以使用二分查找来降低时间复杂度每次二分找到一份订单&#xff0c;利用二分与前缀和将…

【JavaSE语法】类和对象(二)

六、 封装 6.1 封装的概念 面向对象程序三大特性&#xff1a;封装、继承、多态。而类和对象阶段&#xff0c;主要研究的就是封装特性。 封装&#xff1a;将数据和操作数据的方法进行有机结合&#xff0c;隐藏对象的属性和实现细节&#xff0c;仅对外公开接口来和对象进行交互…

opencv:从0到实现人脸识别

目录 opencv 人脸检查原理&#xff1a; 整体目录&#xff1a; 1.读取并展示图片 2.人脸检测 3.视频人脸检测 4.拍照保存 5 数据训练 6 人脸识别 opencv 人脸检查原理&#xff1a; OpenCV 中的人脸检测是基于哈尔特征分类器&#xff08;Haar Feature-based Cascade Cla…

zabbix中监控数据,报错返回给钉钉查看

### 在钉钉中创建群聊(同组的同学创建一个群聊)&#xff0c;在群里面添加自定义机器人 1.通过自定义webhook接入自定义服务 webhook&#xff1a;记住webhook的地址 安全设置&#xff1a;设置加签&#xff0c;只有信息内容包含签才会被机器人发送。 2.配置钉钉告警脚本 #### **安…

【计算思维】少儿编程蓝桥杯青少组计算思维题考试真题及解析B

STEMA考试-计算思维-U8级(样题) 1.浩浩的左⼿边是&#xff08; &#xff09;。 A.兰兰 B.⻉⻉ C.⻘⻘ D.浩浩 2.2时30分&#xff0c;钟⾯上时针和分针形成的⻆是什么⻆&#xff1f;&#xff08; &#xff09; A.钝⻆ B.锐⻆ C.直⻆ D.平⻆ 3.下⾯是⼀年级同学最喜欢的《⻄游记》…

如何下载 Apache + PHP + Mysql 集成安装环境并结合内网穿透工具实现公网访问内网服务

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. WampServer下载安装二. WampServer启动三. 安装cpolar内网穿透3.1 注册账号…

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

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

开启创造力之门:掌握Vue中Slot插槽的使用技巧与灵感

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、s…

Linux_一款好用的查看系统信息的桌面软件_包名hardinfo、软件名system profiler and Benchmark

1、安装软件 对源进行更新&#xff0c;sudo apt update 安装&#xff0c;sudo apt install hardinfo 打开&#xff0c;system profiler and Benchmark 2、查看系统信息 2.1、系统基本信息_操作系统信息、内核版本、处理器等 “Summary”汇总了一些基本信息&#xff1a; 处…

鸿蒙:从0到“Hello Harmony”

效果展示 一.概述 明年华为鸿蒙就不再兼容Android生态了&#xff0c;作为拥有7亿终端用户的华为&#xff0c;建立自己的生态也是理所当然。 所以对HarmonyOS的研究也是众多开发者绕不开的坎了。 今天这篇博文主要实现一个“Hello Harmony&#xff01;”的Demo。 二.官方链接…

winform窗体、控件的简单封装,重做标题栏

1标题栏封装中使用了以下技术&#xff1a; 知识点&#xff1a; 1.父类、子类的继承&#xff1b; 2.窗体之间的继承&#xff1b; 3.自定义控件的绘制&#xff1b; 4.多线程在窗体间的应用&#xff1b; 5.窗体和控件的封装&#xff1b; 6.回调函数&#xff08;委托&#xff09;&…

OpenCV入门2——图像视频的加载与展示一些API

文章目录 题目OpenCV创建显示窗口OpenCV加载显示图片题目 OpenCV保存文件利用OpenCV从摄像头采集视频从多媒体文件中读取视频帧将视频数据录制成多媒体文件OpenCV控制鼠标关于[np.uint8](https://stackoverflow.com/questions/68387192/what-is-np-uint8) OpenCV中的TrackBar控…

探索人工智能领域——每日30个名词详解【day3】

目录 前言 正文 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x1f4e3;如需转载&#xff0c;请事先与我联系以…

【C++初阶】STL详解(一)string类

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

春秋云境靶场CVE-2022-25578漏洞复现(利用htaccess文件进行任意文件上传)

文章目录 前言一、CVE-2022-25578靶场概述二、CVE-2022-25578复现需要知道的知识点1、什么是htaccess文件2、上传htaccess文件的条件是什么&#xff1f;3、htaccess文件的作用是什么&#xff1f; 三、CVE-2022-32991漏洞复现1、信息收集2、找上传点3、上传后蚁剑连接getshell 总…

vmware安装MacOS以及flutter遇到的问题

安装过程&#xff1a;参考下面的文章 链接&#xff1a; 虚拟机VMware安装苹果系统macOS&#xff0c;超级详细教程&#xff0c;附文件下载&#xff0c;真教程&#xff01;&#xff01; 无限重启情况&#xff1a; &#xff08;二&#xff09; 配置虚拟机找到你的虚拟机安装文件…

氢原子波函数等概率面的绘制

氢原子波函数等概率面的绘制 归一化后的氢原子波函数