// 网络请求配置对象
// 作用:存储网络请求相关的配置,如解析网络请求的方法、数据转换器(Converter)、网络请求适配器(CallAdapter)、网络请求工厂(CallFactory)、基础地址(BaseUrl)等
private final Map> serviceMethodCache = new ConcurrentHashMap<>();
//网络请求器的工厂
//作用:生产网络请求器(Call)
//Retrofit是默认使用okhttp(后面会解释)
final okhttp3.Call.Factory callFactory;
//网络请求的基础url地址
final HttpUrl baseUrl;
//数据转换器工厂的集合
//作用:放置数据转换器工厂
//数据转换器工厂作用:生产数据转换器(converter)
final List converterFactories;
//网络请求适配器工厂的集合
//作用:放置网络请求适配器工厂
//网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
final List adapterFactories;
//回调方法执行器
final Executor callbackExecutor;
//标志位
//作用:是否提前对业务接口中的注解进行验证转换的标志位
final boolean validateEagerly;
//Builder类
public static final class Builder {
//平台
private final Platform platform;
//一下几个变量与Retrofit的构造函数大致相同
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List converterFactories = new ArrayList<>();
private final List adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
//构造函数
public Builder() {
this(Platform.get());
}
}
public interface ITest
{
@GET("/wx")
public void add(int a, int b);
}
public static void main(String[] args)
{
ITest iTest = (ITest) Proxy.newProxyInstance(ITest.class.getClassLoader(), new Class>[]{ITest.class}, new InvocationHandler()
{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Integer a = (Integer) args[0];
Integer b = (Integer) args[1];
System.out.println("方法名:" + method.getName());
System.out.println("参数:" + a + " , " + b);
GET get = method.getAnnotation(GET.class);
System.out.println("注解:" + get.value());
return null;
}
});
iTest.add(3, 5);
}
结果为:
方法名:add
参数:3 , 5
注解:/wx
是不是觉得很神奇?有了这个例子我们接下来就很好理解create()方法了。
public T create(final Class service) {
Utils.validateServiceInterface(service);
//判断是否需要提前验证
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 创建了网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例 (并最终返回)
// 该动态代理是为了拿到网络请求接口实例上所有注解
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//注意点1
ServiceMethod
public ServiceMethod build() {
//注意点1,从Retrofit对象中获取对应的网络请求适配器
callAdapter = createCallAdapter();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
// 解析获取Http请求的方法,如GET、POST、HEAD
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
// 为方法中的每个参数创建一个ParameterHandler>对象并解析每个参数使用的注解类型
// 该对象的创建过程就是对方法参数中注解进行解析
// 这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
//最后创建一个新的ServiceMethod实例
return new ServiceMethod<>(this);
}
我们看看注意点1,在ServiceMethod 中是如何创建CallAdapter的:
private CallAdapter createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//调用Retrofit类里面的callAdapter方法
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
最近受我的朋友委托用js+HTML做一个像手册一样的程序,里面要有可展开的大纲,模糊查找等功能。我这个人说实在的懒,本来是不愿意的,但想起了父亲以前教我要给朋友搞好关系,再加上这也可以巩固自己的js技术,于是就开始开发这个程序,没想到却出了点小问题,我做的查找只能绝对查找。具体的js代码如下:
function search(){
var arr=new Array("my
实例:
CREATE OR REPLACE PROCEDURE test_Exception
(
ParameterA IN varchar2,
ParameterB IN varchar2,
ErrorCode OUT varchar2 --返回值,错误编码
)
AS
/*以下是一些变量的定义*/
V1 NUMBER;
V2 nvarc
Spark Streaming简介
NetworkWordCount代码
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
代码示例:
# include <stdio.h>
//冒泡排序
void sort(int * a, int len)
{
int i, j, t;
for (i=0; i<len-1; i++)
{
for (j=0; j<len-1-i; j++)
{
if (a[j] > a[j+1]) // >表示升序
nginx日志分割 for linux 默认情况下,nginx是不分割访问日志的,久而久之,网站的日志文件将会越来越大,占用空间不说,如果有问题要查看网站的日志的话,庞大的文件也将很难打开,于是便有了下面的脚本 使用方法,先将以下脚本保存为 cutlog.sh,放在/root 目录下,然后给予此脚本执行的权限
复制代码代码如下:
chmo
http://bukhantsov.org/2011/08/how-to-determine-businessobjects-service-pack-and-fix-pack/
The table below is helpful. Reference
BOE XI 3.x
12.0.0.
y BOE XI 3.0 12.0.
x.
y BO
大家都知道吧,这很坑,尤其是用惯了mysql里的自增字段设置,结果oracle里面没有的。oh,no 我用的是12c版本的,它有一个新特性,可以这样设置自增序列,在创建表是,把id设置为自增序列
create table t
(
id number generated by default as identity (start with 1 increment b