java初探之代理模式

代理模式

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

在这里插入图片描述

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

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

代理对象的好处?

使用者(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中
    }
}

}


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++二分查找算法:132 模式解法二枚举2

题目及解法一&#xff1a; https://blog.csdn.net/he_zhidan/article/details/134362273 分析 第一步&#xff0c;选择各3对应的1&#xff0c;如果有多个符合对应最小的1&#xff0c;记录num[0,j)中的最小值iMin&#xff0c;如果nums[j]大于iMin&#xff0c;则m3To1 [nums[j…

开源博客项目Blog .NET Core源码学习(6:雪花算法)

Blog .NET项目中有多种数据类生成对象实例时需要唯一标识&#xff0c;一般做法要么使用GUID&#xff0c;也可以保存到数据库时使用数据库表的自增长ID&#xff0c;也可以自定义规则以确保产生不重复的唯一标识&#xff0c;而在Blog .NET项目中使用雪花算法生成唯一标识。   关…

windows安装maven,配置环境变量

官网下载&#xff1a; 其他版本找 Other Releases 配置环境变量 1、解压缩之后开始配置环境变量 2、右键此电脑&#xff0c;选中属性->高级系统设置->高级->环境变量。 3、①和②任选一个都可 ①在系统变量那边增加MAVEN_HOME&#xff0c;路径是解压缩后的文件路径。…

asp.net数字档案管理系统VS开发sqlserver数据库web结构c#编程web网页设计

一、源码特点 asp.net 数字档案管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语 言开发。 asp.net数字档案系统1 应用技…

C进阶---字符函数和字符串函数

目录 一、长度不受限限制的字符串函数 1.1strlen 1.2strcpy 1.3strcat 1.4strcmp 二、长度受限制的字符串函数 2.1strncpy 2.2strncat 2.3strncmp 三、其他字符串函数 3.1strstr 3.2strtok 3.3sterror 3.4memcpy 3.5memmove 3.6memcmp 四、字符分类函…

【Java】详解多线程同步的三种方式

&#x1f33a;个人主页&#xff1a;Dawn黎明开始 &#x1f380;系列专栏&#xff1a;Java ⭐每日一句&#xff1a;等风来&#xff0c;不如追风去 &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️ 文章目录 一.&#x1f510;线…

如何使用postman调用若依系统接口(报错401,认证失败,无法访问系统资源)

有时候我们想使用postman调用若依接口&#xff0c;会报下面的401错误&#xff0c;认证失败&#xff0c;无法访问系统资源。 原因是请求中没有token&#xff0c;没法通过若依的权限认证&#xff0c;下面来说一下如何解决。 {"msg": "请求访问&#xff1a;/syste…

物联网主机E6000:动环监控的新革命

多协议、多接口的全能主机 在物联网时代&#xff0c;数据的采集和处理已经成为了企业运营的重要环节。而物联网主机E6000&#xff0c;就是这个时代的全能选手。它支持多种协议和接口&#xff0c;无论是视频、设备还是DCS系统的数据&#xff0c;都能轻松接入并进行采集处理。这种…

基于SpringBoot的教务管理系统

基于SpringBoot的教务管理系统 教务管理系统开发技术功能模块代码结构运行截图数据库源码获取 教务管理系统 欢迎访问此博客&#xff0c;是否为自己的毕业设计而担忧呢&#xff1f;是否感觉自己的时间不够做毕业设计呢&#xff1f;那你不妨看一下下面的文章&#xff01; 开发…

从房地产先后跨界通信、文旅演艺领域,万通发展未来路在何方?

近年来&#xff0c;房地产市场可谓负重前行&#xff0c;各大房企纷纷谋求新出路。 作为中国最早的房企之一&#xff0c;万通发展再次处在转型变革的十字路口。自去年以来&#xff0c;万通发展在转型升级之路上动作频频&#xff0c;可谓忙得不亦乐乎。 大幕落下之时&#xff0c;…

【word密码】word设置只读方式的四个方法

想要将word文档设置为只读模式&#xff0c;方法有很多&#xff0c;今天小奥超人介绍几个方法给大家。 方法一&#xff1a;文件属性 常见的、简单的设置方法&#xff0c;不用打开word文件&#xff0c;只需要右键选择文件&#xff0c;打开文件属性&#xff0c;勾选上【只读】选…

Java多线程之CAS及原子操作

一、CAS是什么&#xff1f; Java 并发机制实现原子操作有两种&#xff1a; 一种是锁&#xff0c;还有一种是CAS。 在Java中&#xff0c;锁在并发处理中占据了一席之地&#xff0c;但是使用锁有一个不好的地方&#xff0c;就是当一个线程没有获取到锁时会被阻塞挂起&…

35 _ Trie树:如何实现搜索引擎的搜索关键词提示功能?

搜索引擎的搜索关键词提示功能,我想你应该不陌生吧?为了方便快速输入,当你在搜索引擎的搜索框中,输入要搜索的文字的某一部分的时候,搜索引擎就会自动弹出下拉框,里面是各种关键词提示。你可以直接从下拉框中选择你要搜索的东西,而不用把所有内容都输入进去,一定程度上…

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

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

Rust图形界面编程:egui平直布局

文章目录 平直布局with_layout 平直布局 在前面的示例中&#xff0c;已经用到了ui.horizontal用来布局&#xff0c;其特点是水平摆放控件。相应地&#xff0c;ui.vertical则是垂直摆放控件。根据控件的摆放顺序不同&#xff0c;这两个布局组件衍生出一系列布局函数 horizonta…

21 Linux 自带的LED驱动

一、Linux 自带 LED 驱动使能 其实 Linux 内核自带 LED 抢夺那个&#xff0c;但在此之前需要配置 Linux 驱动来使能 LED 驱动。 输入以下命令&#xff1a; cd linux/atk-mpl/linux/my_linux/linux-5.4.31 make menuconfig 根据以下路径找到 LED 驱动&#xff1a; → Device D…

MySQL表的增查(进阶)

目录 1.插入查询结果 2.查询 2.1聚合查询 2.1.1聚合函数 2.1.2GROUP BY子句 2.1.3HAVING 2.2联合查询 2.2.1内连接 2.2.2外连接 2.2.3自连接 2.3子查询 2.4合并查询 1.插入查询结果 在一张表中插入另一张表的查询结果。 语法为&#xff1a; insert into 表名 (列…

【算法】区间(差分约束)

题目 给定 n 个区间 [ai,bi] 和 n 个整数 ci。 你需要构造一个整数集合 Z&#xff0c;使得 ∀i∈[1,n]&#xff0c;Z 中满足 ai≤x≤bi 的整数 x 不少于 ci 个。 求这样的整数集合 Z 最少包含多少个数。 输入格式 第一行包含整数 n。 接下来 n 行&#xff0c;每行包含三个…

解决Github上的README无法显示图片

首先感谢博主的思路&#xff1a;思路 最近写了点东西提交到git 发现本地能查看md里的图片用的相对路径&#xff0c;提交到github就看不见&#xff0c;并且发现不只是我自己的仓库看不见&#xff0c;其他人的我也看不见。那就有问题了 解决&#xff1a;正常使用相对路径&…

【BIM入门实战】Revit图元的选择方式,总有一款适合你

Revit图元的五种常见选择方式,总有一款适合你。 文章目录 一、直接单击二、加选和减选三、连续框选四、按类别选择五、全选过滤选择操作可以在三维视图、平面视图等多种视图中进行。 一、直接单击 直接单击,即可选中某一个图元,如选择一个扶手。 二、加选和减选 按住ctrl键…