目录
疯狂版Java发布聊天室【亿级流量】实战系列之-26【博客公园总入口】
写在前面
? 你好,我是作者tmdqyg。 现在,和几个伙伴一起,组织了高合并的实战社区【疯狂的创造圈】。 高同时,开始了亿级流程的IM聊天项目的学习和实战
? 在疯狂版亿万进程IM聊天项目的学习项目中,短连接Web服务器和长连接IM服务器之间是相互协作的。 在分布式群集环境中,用户首先通过短连接登录Web服务器。 当Web服务器完成用户的帐户/密码验证并返回uid和token时,还必须通过一定的策略获取目标IM服务器的IP地址和端口号列表,并将其返回给客户端。 客户端启动与IM服务器的连接,连接成功时发送认证请求,认证成功时正式建立允许的长连接。
?
? 短连接调用,使用Feign技术。 详细情况在这里。
? 完成后,Feign可以独立使用以完全替换当前的Http客户端调用方法。
? 1.1. Feign短接rest风格的呼叫
通常,短连接的服务接口用基于APP应用层Http协议的Http api或rest风格的API实现,并以JSON文本格式返回数据。 我如何在Java服务端调用其他节点的Http api或rest风格的API?
至少有几种方法。
)1) JDK本机URL连接
)2) Apache的http客户端http组件
(3)网络异步http客户端
(4) Spring的rest模板
目前使用最多的,基本上是第二种,这也是单机服务时代,最成熟稳定的方式,也是高效的短接方式。
插入说明。 什么是rest风格的API? REST的全名是Representational State Transfer,是API接口的样式,它提供一组调用原则和约束,而不是标准。 这意味着在短连接服务领域,它是一种特殊格式的HTTP api。
言归正传,在同一http API/rest风格的API接口上,如果多个节点提供服务,而不是由多个短连接服务器提供,则无法轻松使用http客户端调用。
Http Client/HttpComponents调用无法根据接口负载或其他条件来确定应该调用哪个接口,不应该调用哪个接口。 解决这个问题的方法是什么呢?
可以使用Feign调用多个服务器上的同一接口。 除了平衡同一接口多服务器的负载外,如果使用Feign作为http api的客户端,fign调用远程http接口就像调用本地方法一样简单。
Feign哪里神圣? 这是由Netflix开发的声明性模板化HTTP客户端,Feign的目标是让Java工程师更快、更优雅地调用http API//rest风格的API。 Feign还无缝集成到SpringCloud微服务框架中,使用Feign,项目的SpringCloud微服务技术非常有用。
如果项目使用SpringCloud技术,则可以更容易地以声明方式使用Feign。 如果没有使用SpringCloud,使用Feign也很容易。 Netflix Feign目前改名为OpenFeign,最新版本为9.7.0版(2018.5版)。 OpenFeign是一个Java APP应用程序,处理与远程Web服务的请求响应,最大限度地降低编码复杂性。 可以说是在Java APP上调用Web服务的客户端的利器。
让我们来看看在单独使用Feign的情况下如何调用远程http服务。
将依赖于Feign的jar包部署到pom.xml中:
io.github.openfeign
费格核
9.7.0
io.github.openfeign
费因-格森
9.7.0
然后,可以使用Feign调用远程Http API。
1.1.1 .短连接API的接口准备
如上所述,在高并发的IM系统中,用户的登录和认证、朋友的更新和取得等低频度的要求,都是使用短链接实现的。
作为演示,这里只列举了两个短连接的API接口。
)1) 3358本地主机:8080/user/{ userid }
此接口的功能是一种典型的rest风格的接口,用户通过该接口获取用户信息。 {userid}是占位符,调用时必须替换为用户id。 例如,如果用户id为1,则调用的链接为http://localhost:8080/user/1。
)2) http://localhost :8080/log in/{ username }/{ password }
这个界面的功能,用户注册的认证。 占位符{username}表示用户名,占位符{password}表示用户的密码。 例如,如果用户名为zhangsan,则密码为12
3调用的链接为:http://localhost:8080/login/zhangsan/123 。上面的接口很简单,仅仅是为了演示,不能用于生产场景。这些API可以使用Spring MVC 等常见的WEB技术来实现。
1.1.2. 申明远程接口的本地代理
如何通过Feign技术,来调用上面的这些Http API呢?
第一步,需要创建一个本地的API的代理接口。具体如下:
package com.crazymakercircle.imServer.feignClient;
import feign.Param;
import feign.RequestLine;
public interface UserAction
{
@RequestLine("GET /login/{username}/{password}")
public String loginAction(
@Param("username") String username,
@Param("password") String password);
@RequestLine("GET /user/{userid}")
public String getById(
@Param("userid") Integer userid);
}
在代理接口中,为每一个远程Http API定义一个方法。
如何将方法对应到远程接口呢?
在方法的前面,加上一个@RequestLine 注解,注明远程Http API的请求地址。这个地址不需要从域名和端口开始,只需要从URI的根目录“/”开始即可。
比如,如果远程Http API的URL为:http://localhost:8080/user/{userid} ,@RequestLine 声明的值,只需要配成 /user/{userid} 即可。
如何给接口传递参数值呢?
在方法的参数前面, 加上一个 @Param 注解即可。 @Param内容为HTTP链接中参数占位符的名称。绑定好之后,实际这个Java接口中的参数值,会替换到@Param注解中的占位符。
比如:由于getById的唯一参数 userid的 @Param注解中,用到的占位符是userid。那么,通过调用 userAction.getById(100) ,那么userid的值100,就会用来替换掉请求链接http://localhost:8080/user/{userid} 中占位符userid,最终得到的请求链接为:http://localhost:8080/user/100。
1.1.3. 远程API的本地调用
在完成远程API的本地代理接口的定以后,接下来的工作就是调用本地代理,这个工作也是非常的简单。
还是以疯狂创客圈的实战项目,获取用户信息、和用户登录两个API的代理接口的调用为例。
实战的代码如下:
import com.crazymakercircle.imServer.feignClient.UserAction;
import feign.Feign;
import feign.Request;
import feign.Retryer;
import feign.codec.StringDecoder;
import org.junit.Test;
/**
* Created by tmdqyg at 疯狂创客圈
*/
//@ContextConfiguration(
// locations = { "classpath:application.properties" })
//@RunWith(SpringJUnit4ClassRunner.class)
//@Configuration
//自动加载配置信息
//@EnableAutoConfiguration
public class LoginActionTest
{
/* // 服务器ip地址
@Value("${server.web.user.url}")
private String userBase;*/
@Test
public void testLogin()
{
UserAction action = Feign.builder()
// .decoder(new GsonDecoder())
.decoder(new StringDecoder())
.options(new Request.Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3))
.target(
UserAction.class,
// userBase
"http://localhost:8080/"
);
String s = action.loginAction(
"zhangsan",
"zhangsan"
);
System.out.println("s = " + s);
}
@Test
public void testGetById()
{
UserAction action = Feign.builder()
// .decoder(new GsonDecoder())
.decoder(new StringDecoder())
.target(
UserAction.class,
"http://localhost:8080/"
);
String s = action.getById(2);
System.out.println("s = " + s);
}
}
主要的也是最为核心的就一步,构建一个远程代理接口的本地实例。使用Feign.builder() 构造器模式方法,带上一票配置方法的链式调用。主要的链式调用的配置方法介绍如下:
(1)target 配置方法
为构造器配置本地的代理接口,和远程的根目录。代理接口类的每一个接口方法前@RequestLine 声明的值,最终都会加上这个根目录。这个是最为重要的一个配置方法。代理接口类很重要,最终Feign.builder() 构造器返回的本地代理实例类型,就这个接口。
(2)options配置方法
options方法指定连接超时时长及响应超时时长。
(3)retryer配置方法
retryer方法主要是指定重试策略。
(4)decoder配置方法
decoder方法指定对象解码方式,这里用的是基于String字符串的解码方式。如果需要使用gxdxyz的解码方式,需要在pom.xml中添加gxdxyz的依赖。
主要的配置方法,就介绍这些,具体使用和其他的方法,请参见官网。
通过Feign.builder() 构造完成代理实例后,调用远程API,就变成了调用Java函数一样的简单。
建议,如果是独立调用Http服务,尽量使用Feign。
一是简单,
二是如果采用httpclient或其他相对较重的框架,对初学者来说编码量与学习曲线都会是一个挑战。
三是,既可以独立使用Feign,又可以方便后续的和Spring Could微服务框架继承。
总之,何乐而不为呢?
写在最后
下一篇: zookeeper + netty 实现高并发IM 聊天
疯狂创客圈 亿级流量 高并发IM 学习实战
Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战
Netty 源码、原理、JAVA NIO 原理
Java 面试题 一网打尽