1.Forest简介
2.SpringBoot集成Forest
3.常用注解
1.Forest简介
官方网站:http://forest.dtflyx.com/
forest是什么?
Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 的所有请求信息(包括 URL、Header 以及 Body 等信息)绑定到您自定义的 Interface 方法上,能够通过调用本地接口方法的方式发送 HTTP 请求。
Forest的好处
一个轻量级的类似于RPC的HTTP客户端的API框架,是feign之外的另一个好的选择。同时支持OKhttp和HTTPClient,比这两种更高层。封装了http调用的细节,使用简单。
Forest的工作原理
Forest会将定义好的接口通过动态代理的方式生成一个具体的实现类,然后组织、验证 HTTP 请求信息,绑定动态数据,转换数据形式,SSL 验证签名,调用后端 HTTP API(httpclient 等 API)执行实际请求,等待响应,失败重试,转换响应数据到 Java 类型等脏活累活都由这动态代理的实现类给包了。 请求发送方调用这个接口时,实际上就是在调用这个干脏活累活的实现类。
HTTP请求过程分为前端和后端部分,Forest是处理前端过程的框架,是对后端HTTP API的进一步封装。
前端部分:
-
Forest 配置: 负责管理 HTTP 发送请求所需的配置。
-
Forest 注解: 用于定义 HTTP 发送请求的所有相关信息,一般定义在 interface 上和其方法上。
-
动态代理: 用户定义好的 HTTP 请求的
interface
将通过动态代理产生实际执行发送请求过程的代理类。 -
模板表达式: 模板表达式可以嵌入在几乎所有的 HTTP 请求参数定义中,它能够将用户通过参数或全局变量传入的数据动态绑定到 HTTP 请求信息中。
-
数据转换: 此模块将字符串数据和
JSON
或XML
形式数据进行互转。目前 JSON 转换器支持Jackson
、Fastjson
、Gson
三种,XML 支持JAXB
一种。 -
拦截器: 用户可以自定义拦截器,拦截指定的一个或一批请求的开始、成功返回数据、失败、完成等生命周期中的各个环节,以插入自定义的逻辑进行处理。
-
过滤器: 用于动态过滤和处理传入 HTTP 请求的相关数据。
-
SSL: Forest 支持单向和双向验证的 HTTPS 请求,此模块用于处理 SSL 相关协议的内容。
后端部分:
后端为实际执行 HTTP 请求发送过程的第三方 HTTP API,目前支持okHttp3
和httpclient
两种后端 API。
版本说明
Forest 1.0.x 和 Forest 1.1.x 基于 JDK 1.7, Forest 1.2.x及以上版本基于 JDK 1.8
2.SpringBoot集成Forest
添加Maven依赖
<!--Forest依赖-->
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>1.5.0-RC7</version>
</dependency>
<!-- JSON依赖 :版本>= 1.2.48 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency>
增加配置
application.yml
forest:
bean-id: config0 # 在spring上下文中bean的id, 默认值为forestConfiguration
backend: okhttp3 # 后端HTTP API: okhttp3
max-connections: 1000 # 连接池最大连接数,默认值为500
max-route-connections: 500 # 每个路由的最大连接数,默认值为500
timeout: 3000 # 请求超时时间,单位为毫秒, 默认值为3000
connect-timeout: 3000 # 连接超时时间,单位为毫秒, 默认值为2000
retry-count: 1 # 请求失败后重试次数,默认为0次不重试
ssl-protocol: SSLv3 # 单向验证的HTTPS的默认SSL协议,默认为SSLv3
logEnabled: true # 打开或关闭日志,默认为true
log-request: true # 打开/关闭Forest请求日志(默认为 true)
log-response-status: true # 打开/关闭Forest响应状态日志(默认为 true)
log-response-content: true # 打开/关闭Forest响应内容日志(默认为 false)
配置一般有三种:
-
application.yml或通过ForestConfiguration配置类配置,这两种方式都是全局配置。针对全局所有请求,作用域最大,配置读取的优先级最小。
-
接口配置: 作用域为某一个
interface
中定义的请求,读取的优先级最小。您可以通过在interface
上修饰@BaseRequest
注解进行配置。 -
请求配置:作用域为某一个具体的请求,读取的优先级最高。您可以在接口的方法上修饰
@Request
注解进行 HTTP 信息配置的定义。
配置的优先级:优先级值的是是否优先读取该配置。比如您优先级最高@Request
中定义了timeout
为500
,那么即便在全局配置中定了timeout
为1000
,最终该请求实际的timeout
为优先级配置最高的@Request
中定义的500
。
编写http请求的接口
通过@Request
注解,将上面的MyClient
接口中的helloWorld()
方法绑定了一个 HTTP 请求, 其 URL 为http://localhost:2222/hello-world
,并默认使用GET
方式,且将请求响应的数据以String
的方式返回给调用者。
package com.snail.study.rpc.client;
import com.dtflys.forest.annotation.Request;
public interface HelloClient {
@Request(url = "http://localhost:2222/hello-world")
String helloWorld();
}
在启动类添加注解
Forest 会扫描@ForestScan
注解中basePackages
属性指定的包下面所有的接口
package com.snail.study;
import com.dtflys.forest.springboot.annotation.ForestScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@ForestScan(basePackages = "com.snail.study.rpc.client")
@SpringBootApplication
public class ForestApplication {
public static void main(String[] args) {
SpringApplication.run(ForestApplication.class, args);
}
}
Service层
package com.snail.study;
import com.snail.study.rpc.client.HelloClient;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class HelloService {
@Resource
private HelloClient helloClient;
public String helloWorld(){
String helloWorld = helloClient.helloWorld();
return helloWorld;
}
}
Controller层
import com.dtflys.forest.annotation.GetRequest;
import com.snail.study.service.HelloService;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class HelloController {
@Resource
private HelloService helloService;
@GetRequest("/hello")
public String helloWorld(){
return helloService.helloWorld();
}
}
3.常用注解
@Request
@Request用于修饰接口方法,表示绑定方法和一个HTTP请求,其属性url
表示远端的地址,默认是GET
请求。属性type
可以为GET POST PATCH PUT
等请求方式。headers
可添加请求头
@Post,@Get,@GetRequest,@PostRequest
相当于@Request
设置了type
值,用法和@Request
类似。除了GET
和POST
,也可以指定成其他几种 HTTP 请求方式(PUT
, HEAD
, OPTIONS
, DELETE
)。
其中type
属性的大小写不敏感,写成POST
和post
效果相同。
@GetRequest
, @PostRequest
等注解代替@Request
注解,这样就可以省去写type
属性
@DataVariable
@DataVariable修饰接口方法的参数
@Query
使用 @Query 注解,可以直接将该注解修饰的参数动态绑定到请求url中。
使用 @Query 注解,可以修饰 Map 类型的参数。Map 的 Key 将作为 URL 的参数名, Value 将作为 URL 的参数值,这时候 @Query 注解不定义名称。
@Query 注解也可以修饰自定义类型的对象参数,依据对象类的 Getter 和 Setter 的规则取出属性,其属性名为 URL 参数名,属性值为 URL 参数值。这时候 @Query 注解不定义名称
@Get("http://localhost:8080/hello")
String send2(@Query User user);
@Query 与 @DataParam 不同,@Query 注解修饰的参数一定会出现在 URL 中,而 @DataParam 修饰的参数则要视情况而定。
@Header
@Header
注解把方法的参数直接绑定到请求体中
/**
* 使用 @Header 注解将参数绑定到请求头上
* @Header 注解的 value 指为请求头的名称,参数值为请求头的值
* @Header("Accept") String accept将字符串类型参数绑定到请求头 Accept 上
* @Header("accessToken") String accessToken将字符串类型参数绑定到请求头 accessToken 上
*/
@Post("http://localhost:8080/hello/user?username=foo")
void postUser(@Header("Accept") String accept, @Header("accessToken") String accessToken);
如果有很多请求头参数
/**
* 使用 @Header 注解可以修饰 Map 类型的参数
* Map 的 Key 指为请求头的名称,Value 为请求头的值
* 通过此方式,可以将 Map 中所有的键值对批量地绑定到请求头中
*/
@Post("http://localhost:8080/hello/user?username=foo")
void headHelloUser(@Header Map<String, Object> headerMap);
/**
* 使用 @Header 注解可以修饰自定义类型的对象参数
* 依据对象类的 Getter 和 Setter 的规则取出属性
* 其属性名为 URL 请求头的名称,属性值为请求头的值
* 以此方式,将一个对象中的所有属性批量地绑定到请求头中
*/
@Post("http://localhost:8080/hello/user?username=foo")
void headHelloUser(@Header MyHeaderInfo headersInfo);
@Body
@Body
注解修饰的参数一定会绑定到请求体中。
@JSONBody
该注解自1.5.0-RC1
版本起可以使用。 使用@JSONBody注解的同时就可以省略 contentType = "application/json"属性设置。
/**
* 被@JSONBody注解修饰的参数会根据其类型被自定解析为JSON字符串
* 使用@JSONBody注解时可以省略 contentType = "application/json"属性设置
*/
@Post("http://localhost:8080/hello/user")
String helloUser(@JSONBody User user);