请问各位大神Okhttp底层是如何实现拦截的?如何实现AOP的?研究了好久也看不出来,谢谢指教谢谢

图片说明
图片说明

5个回答

底层没研究过,我一般是这么使用的拦截器,你参考下:

1.创建对象

  mOkHttpClient.newBuilder()
                    .cache(cache)//缓存路径
                    .cookieJar(CookiesManager.getInstance())
                    .retryOnConnectionFailure(true)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .readTimeout(300, TimeUnit.SECONDS)
                    .writeTimeout(300, TimeUnit.SECONDS)
                    .addNetworkInterceptor(cacheIntercepter)//网络拦截器
                    .build();

2.拦截器

 //网络拦截器:设置缓存策略
    private Interceptor cacheIntercepter = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            //无网的时候强制使用缓存
            if (!NetworkUtil.isConnected()) {
                ToastUtil.showShortMessage("网络不可用,开始加载本地缓存");
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            }

            Response response = chain.proceed(request);

            //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
            if (NetworkUtil.isConnected()) {
                String cacheControl = request.cacheControl().toString();
                return response.newBuilder()
//                    .addHeader("TerminalCode", "android_app")
//                    .addHeader("TerminalVersion", "v" + FrameWorkSetting.clientVersion)
//                    .addHeader("TerminalSim", FrameWorkSetting.phoneMODEL)
                        .header("Cache-Control", cacheControl)
                        .removeHeader("Pragma")
                        .build();
            } else {
                int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
                return response.newBuilder()
//                    .addHeader("TerminalCode", "android_app")
//                    .addHeader("TerminalVersion", "v" + FrameWorkSetting.clientVersion)
//                    .addHeader("TerminalSim", FrameWorkSetting.phoneMODEL)
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                        .removeHeader("Pragma")
                        .build();
            }
        }

    };

使用OKHTTP发起一个GET请求:
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder() .url(url) .build();
Response response = client.newCall(request).execute();
return response.body().string(); 、
}

一直往下跟踪:

@Override public Call newCall(Request request) {
return new RealCall(this, request);
}

返回一个RealCall,
调用RealCall的execute()方法:
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}

调用getResponseWithInterceptorChain():
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}

这时候会创建一个拦截器链:
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
看看ApplicationInterceptorChain的构造函数:
ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
this.index = index;
this.request = request;
this.forWebSocket = forWebSocket;
}
其中第一个参数是一个index,此处请注意,最初我们传入的index的值是0,

继续看chain.proceed(originalRequest);
此时会调用到ApplicationInterceptorChain中:

@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
Interceptor interceptor = client.interceptors().get(index);
Response interceptedResponse = interceptor.intercept(chain);

    if (interceptedResponse == null) {
      throw new NullPointerException("application interceptor " + interceptor
          + " returned null");
    }

    return interceptedResponse;
  }

  // No more interceptors. Do HTTP.
  return getResponse(request, forWebSocket);

}

会根据index从0开始先取出拦截器并依次执行,但是我们需要注意的是,在重新构造chain的时候会把index的值加1,在调用拦截器的拦截方法的时候会将拦截器链作为参数传入,单此时index的值已经修改了,

我们再看拦截器的方法:
@Override public Response intercept(Chain chain) throws IOException {
Level level = this.level;

Request request = chain.request();
if (level == Level.NONE) {
  return chain.proceed(request);

}
在该方法中又会调用chain.proceed(request)方法;
相当于在返回最终结果前,会先依次调用我们注册的拦截器的方法,最后才会返回最终结果,从而实现了AOP类似的功能

如此来看,每个拦截器都可以看成是一个切面

这么有名的框架 还会存在逻辑错误?

附一张图
图片说明

检查一下 return 的格式,顺便看一下是否存在逻辑错误。代码检查比较麻烦,没办法

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
如何实现AOP 的静态方法拦截
打算用AOP做系统缓存,使用代理,拦截类及方法的调用,在网上着了一下,没有相关资料,msdn中对ProxyAttribute的注解是:rn可以使用 ProxyAttribute 类来截获 new语句...此类型的任何公共静态成员都是线程安全的,但不保证所有实例成员都是线程安全的.rn难道非要把大把的static方法修改为实例方法才可以实现aop吗?请高手指教!!!
printf的参数传递是如何实现的?望各位指教,谢谢
如题。最好能给出伪代码之类,谢谢!^_^
AOP是如何实现的?
Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责;Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。 JDK动态代理(默认使用): 代理类实现InvocationHandler接口,加上反射生...
struts2的底层是如何实现的?
struts2的底层是如何实现的啊,是servlet实现的吗
数据控件的底层是如何实现的?
操作Oracle的xmltypern因为可能插入超过4k的数据,所以需要用流rn然后ADOQuery和ADOdataset都用过,发现个问题rn[code=Delphi(Pascal)]rn//Queryrn with ADOQry_1 dorn beginrn Close;rn SQL.Clear;rn SQL.Add('insert into xmltest (id,xmldoc) values ( :id , xmlType(:clobs))');rn Parameters.ParamByName('id').Value := '0001';rn //全部测试不通过rn Parameters.ParamByName('clobs').LoadFromStream(strstream,ftBlob);rn Parameters.ParamByName('clobs').LoadFromStream(strstream,ftOraClob);rn TMemoField(Parameters.ParamByName('clobs')).LoadFromStream(strstream);rn rn Prepared;rn ExecSQL;rn end;rn[/code]rnrn而先查询,再在field里面导入流,然后保存进中间表,再调用存储过程xmltype(clob)强制转换导入却是可以的rn[code=Delphi(Pascal)]rnrn with ADOQry_1 dorn beginrn Close;rn Parameters.Clear;rn SQL.Clear;rn SQL.Add('select * from insertxml_tmp');rn Open;rn end;rnrn with ADOQry_1 dorn beginrn Edit;rn Append;rn FieldByName('id').value := '0001';rn TMemoField(FieldByName('xmlclob')).LoadFromStream(strstream);rn Post;rn ADOQry_1.UpdateStatus;rn end;rnrn with Adsp_1 dorn beginrn Close;rn ProcedureName := 'XmlInsertClob';rn ExecProc;rn end;rnrn[/code]rnrn当时就想能不能调用底层一点的API什么的,控件用着是真不放心啊rn然后又疑惑了,貌似查询操作记录也是调用的语句,流是怎么调用的呢rn[code=SQL]rnselect sql_text as "简略SQL语句",sql_fulltext as "SQL字串",parsing_schema_name as "执行者",module as "执行程序",last_active_time as "作用时间" rnfrom v$sqlarea rnwhere parsing_schema_name = '' and module = '' --执行者为parsing_schema_name ,执行程序为module rnorder by last_active_time descrn[/code]
KVO的底层是如何实现的
您好,我想问一下,当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,该派生类会重写set方法,然后在重写的方法里面实现真正的通知机制,但是如果没有访问器方法呢,只有setValue. forKey怎么办?,这个也是通过set方法实现的吗?麻烦您给我解答一下,谢谢![图片说明](http://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/001/face/21.gif)![图片说明](http://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/001/face/83.gif)
编辑控件如何实现多行显示?谢谢指教
我加了一个编辑控件,选了它的multiple line属性,并定义了一个变量CEDIT a,rn然后对a 赋值,想多行显示出来,不知道如何实现?请高手指教。
这个报表如何实现,谢谢指教!
报表功能:统计各部门男女人数.rnrn表table:rnname workname sexrn汪娜 计供科 女rn凌开明 技术科1 男rn周寅 质监科 男rn朱荷波 八车间 男 rn邬静娜 八车间 女 rn钱丹萍 八车间 女 rn杜丽娟 三车间 女rn毛易耀 三车间 男 rn王仲秋 四车间 男rnrn报表如下:rn性别 计供科 技术科1 质监科 八车间 三车间 四车间rn男 0 1 1 1 1 1rnrn女 1 0 0 2 1 0rnrn要求用存储过程实现,谢谢指教.rnrn男女只是报表中的一个项目,还有很多项目没有统计.rn
这个效果如何实现,一起研究,谢谢
http://www.fotop.net/slideshow/tpbear/PhoebeLawrence?r=fotoprnrnrn这个效果如何实现,一起研究,谢谢rnrn图片效果,想看原码,但是看不了,人家做处理了,图片轮换,跟FLASH一样,
请问各位大神一下,谢谢
我想知道MFC的DispatchMessage()函数是不是可以调出来自己改写的?如果可以,该怎样调,我找遍了类向导,没找到。还有消息挂起是什么意思,小弟MFC的新手,最近被MFC的消息搞死了,求打救。。。
AOP实现日志拦截
使用Spring AOP实现日志拦截
如何实现定时关机,谢谢!
我想让我的电脑在一个固定的时间关机,如何实现,谢谢
如何实现踢人,谢谢。
如何实现踢人,谢谢。
语音信箱如何实现?谢谢
求各位大侠帮忙,我如何能用AT实现语音信箱功能阿rn拜托了
请教如何实现?谢谢
sql2000数据库,库中有文章标题2个:rn1、机械行业需求端稳定rn2、食品饮料又到遍地黄金时rnrn现在想实现标题中含有能显示,也就是上面的第一条能显示,请教如何实现?谢谢
如何实现ftp?谢谢!
请问哪位大虾可以提供在linux下实现rnftp的资料,最好比较详细!谢谢!在rn线等待!
如何实现组合查询,,谢谢
我想在查询中实现组合查询:有员工编号edit1,姓名:edit2,部门:combobox1等,有个button1,有个dbgrid1,实现查询,edit1,edit2,combobox1,以上全选,或者,选几个,都能实现查询??rn代码该怎么写,,假如ado是:adoquery1,datasource1,rn我是这样写的,buttononclick事件;rnvar str:string;rnbeginrnstr:='select * from adoquery1 where ';rnif edit1.text<>'' thenrnbeginrn str:=str+' ygbh=edit1.text ';rnend;rn if edit2.text <>'' thenrnbeginrn str :=str+' xm =edit2.text';rnend;rn if combobox1.text <> '' thenrnbeginrn str :=str+' bm= combobox1.text ';rnend;rnwith adoquery1 dornclose;rnsql.clear;rnsql.add(str);rnopen;rnend;rnrn我知道以上这样写不对,,会错,,我只想,大虾们,,教小第,以上的功能该怎么实现!!谢谢!!
求大神指教,谢谢大神
#include rnusing namespace std;rnclass Complexrnrn float Real,Image;rnpublic:rn Complex()rn rn Real=0;rn Image=0; rn rn Complex(float r,float i)rn rn Real=r;rn Image=i;rn rn void Print()rn rn cout<0)rn rn cout<<'+';rn rn if(Image!=0)rn rn cout<
TC2.0下,如何实现串口的收发。谢谢各位了!!
TC2.0下,如何实现串口的收发。(RS232,9600bit)一个发,一个收就可以。rnrn是用inport和outport函数吗?怎么写呢?rn有源程序吗?rnrnrnrn谢谢各位了!!!rnrn我的e-mailrnduyhui@sina.com
多级下拉菜单无刷新 如何实现? 谢谢各位
多级下拉菜单无刷新 如何实现? 谢谢各位 rn假如是两级菜单 如何实现呢? rn先从数据库的出的出大类 然后选择 出现小类的下拉框rn里 谢谢 rnrn
如何实现Datagrid的打印啊,谢谢各位了
如题!
如何实现用户注销功能?谢谢各位。
我的网站在用户登陆后,要提供用户注销登陆的功能。即用户点击注销后,rn进入一个新页面,其中提示 “xxx用户已成功注销”,这时关键是用户若再rn单击 ie 浏览器工具栏中的 后退 按钮想进入前一个页面,必须提示诸如:rn“非法用户”或“该网页内容已过期” 的内容,请问最近的办法如何实现?rn真的很感谢。
请问这个图片滚动的效果如何实现呢?谢谢高手指教
[img=http://www18.babidou.com/pic/2008/3/7/coolhty/que.jpg][/img]rnrn上面这个效果请问用JS怎么实现..谢谢了,有点急用.
求指教谢谢各位大神。小白一枚
c#不同命名空间调用static方法不可以么是么?求指教谢谢各位大神。小白一枚
加载进度条是如何实现的。 谢谢
163邮箱那样的javascript加载进度条是如何实现的。 谢谢各位rn
C#下的皮肤技术是如何实现的 谢谢
比如IrisSkin.dll 多谢。VC中的皮肤很多利用钩子 C#也是吗?
倒计时是如何实现的呢?谢谢
[img=http://img.my.csdn.net/uploads/201301/30/1359506585_9912.jpg][/img]rnrn如图,想在桌面程序,非网页,做一个类似这样的倒计时,该如何实现呢?谢谢,
谢谢各位.看这个需求如何实现.谢谢.
如下是我写的一段代码:rnrn rn rn rnrnrn rn rnrn rn 按钮测试.谢谢各位 rn rn rn rn rn 全选rn rn rnrn rn rn 按钮1rnrn rn 按钮2rnrn rn 按钮3rnrnrn rnrnrnrnrnrnrn我打开这个页面时,都首先检测一下按钮1到按钮3,如果这三个都选中了.则把全选的那个按钮也选中;缺一个都不中选中此按钮.rn不知道如何实现.谢谢各位.
RMI的实现?谢谢各位!
RMI所需要的类全实现了,先运行了rmiregistry,但是在运行服务器端的类时,一直都不能成功,请问什么原因?谢谢各位!
请问如何实现PDA的打印功能?谢谢
如题.
请问如何实现这样的菜单?谢谢
我想实现“http://www.mfun86.com/index.asp”顶端的菜单,(就是鼠标放到‘诺基亚’上出来一下拉菜单)请问如何实现。多谢!
请问如何实现这样的编码?谢谢
20040321000001rnrn前几位是当时的时间,后面是自增编码,谢谢
请问如何实现动态标题?谢谢
比如一个网上商店有:电脑产品,数码产品等好多类rn怎么样实现点击这些类的时候标题也作相应的变化,显示为这些类名+站名这种rn各种商品页也可以实现标题显示为商品名相关.rnrn非常谢谢!非常需要
请问以下功能该如何实现,谢谢
小弟想做一个监听邮箱内是否有新邮件的程序。有于对pop3不是很熟悉。所以不知道该怎样监听pop3服务器,比如网易的。请问如何写TcpClient myClient = new TcpClient(string server,int port)里的rnserver和port
请问如何实现该效果,谢谢!
数据表:rnId Typern1 Arn2 Brn3 Crn4 Arn5 Brn6 Crn7 Arn8 Brn9 Crnrn如果得到以下结果rn7 Arn8 Brn9 Crn4 Arn5 Brn6 Crn1 Arn2 Brn3 Crnrn谢谢!
请问checkedlistbox如何实现单选,谢谢
如题,谢谢了
请问如何实现横向合计谢谢帮助!!!!!!!!!!!!
名称 fs1 fs2 fs3 fs4 fs5 hj rn绩效考核员 0 0 0 1 0rn网络管理员 0 1 0 0 0rn新产品开发员 0 0 0 0 2rn网络管理员 4 0 0 0 0rn新产品开发员 4 4 4 0 0rn
请问这种套打如何实现?谢谢!!!
要向一张用户表格中填数据,每次都是接着已有记录的下面打印,该如何实现?有点象存折明细的打印一样,每次去钱或存钱等后就接着上次的后面打印 rnrn 驾驶员记载 rn rn姓名 性别 年龄 登 记 证 号rn rn rn rn rn rnrn
请问如何实现下拉框动态改变内容.谢谢!
我现在需要在用户选择第一个下拉框后,根据第一个下拉框的内容自动填充第二个下拉框.rn比如用户选择"江苏"后第二个下拉框出现"南京,扬州,苏州……",用户选择"浙江"时第二个下拉框出现"杭州,嘉兴,绍兴"等.rnrn最好有现成的代码.分数全部给第一位给出答案的大侠.
请问如何实现下载统计的功能,谢谢!
我现在要做的是有一个downcounter.php来完成下载统计的工作,形式如downcounter.php?id=123&url=www.xxx.com/1.ziprn现在要完成的是将ID为123的产品下载数+1,再转到www.xxx.com/1.zip上去.如果直接用IE点击是可以正常的.但想也可以能Save Target As也能实现计数和文件重定向上目标下载文件上.同时在用FlashGet和NetAnts之类的软件也可完成统计和下载的功能.rn现在试下来header("Location: URL"); 可以完成上述三个要求的.但是其转向的URL好像不支持变量,只能先行写死的.rn如方法echo " "; 不可以用Save Target As正常保存和计数.rnrnrn谢谢!rnrn
相关热词 c#入门推荐书 c# 解码海康数据流 c# xml的遍历循环 c# 取 查看源码没有的 c#解决高并发 委托 c#日期转化为字符串 c# 显示问号 c# 字典对象池 c#5.0 安装程序 c# 分页算法