什么是Thrift

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)、Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk。虽然它以前是由Facebook开发的,但它现在是Apache软件基金会的开源项目了。

架构

Thrift包含一套完整的栈来创建客户端和服务端程序。顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现,如下官方示意图

支持的通讯协议

  • TBinaryProtocol
    一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
  • TCompactProtocol
    更紧凑的二进制格式,处理起来通常同样高效。
  • TDebugProtocol
    一种人类可读的文本格式,用来协助调试。
  • TDenseProtocol
    与TCompactProtocol类似,将传输数据的元信息剥离。
  • TJSONProtocol
    使用JSON对数据编码。
  • TSimpleJSONProtocol
    一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析

支持的传输协议

  • TFileTransport
    该传输协议会写文件。
  • TFramedTransport
    当使用一个非阻塞服务器时,要求使用这个传输协议。它按帧来发送数据,其中每一帧的开头是长度信
  • TMemoryTransport
    使用存储器映射输入输出。(Java的实现使用了一个简单的ByteArrayOutputStream。)
  • TSocket
    使用阻塞的套接字I/O来传输。
  • TZlibTransport
    用zlib执行压缩。用于连接另一个传输协议。

支持的服务模型

  • TNonblockingServer
    一个多线程服务器,它使用非阻塞I/O(Java的实现使用了NIO通道)。TFramedTransport必须跟这个服务器配套使用。
  • TSimpleServer
    一个单线程服务器,它使用标准的阻塞I/O。测试时很有用。
  • TThreadPoolServer
    一个多线程服务器,它使用标准的阻塞I/O
  • THsHaServer
    YHsHa引入了线程池去处理(需要使用TFramedTransport数据传输方式),其模型把读写任务放到线程池去处理;Half-sync/Half-async(半同步半异步)的处理模式;Half-sync是在处理IO时间上(sccept/read/writr io),Half-async用于handler对RPC的同步处理

Thrift的优点

  1. 跟一些替代选择,比如SOAP相比,跨语言序列化的代价更低,因为它使用二进制格式。
  2. 它有一个又瘦又干净的库,没有编码框架,没有XML配置文件。
  3. 绑定感觉很自然。例如,Java使用java.util.ArrayList;C++使用std::vectorstd::string。
  4. 应用层通讯格式与序列化层通讯格式是完全分离的。它们都可以独立修改。
  5. 预定义的序列化格式包括:二进制格式、对HTTP友好的格式,以及紧凑的二进制格式。
  6. 兼作跨语言文件序列化。
  7. 协议使用软版本号机制软件版本管理[需要解释]。Thrift不要求一个中心化的和显式的版本号机制,例如主版本号/次版本号。松耦合的团队可以轻松地控制RPC调用的演进。
  8. 没有构建依赖也不含非标准化的软件。不存在不兼容的软件许可证混用的情况

SpringBoot整合Thrift

为什么会出现RPC框架

  1. 高级语言越来越丰富,同时学习的成本越来越低,从而出现编程语言的百花齐放,同时,每种语言都有其在特定场景下的优势性,因此一个企业的系统架构可能存在这各种各样的编程语言发挥着光和热。因此跨语言间的通讯必须存在一个桥梁;
  2. 微服务的盛行,使得服务逐渐模块化,功能化;单个服务仅仅实现某个特定的功能或者模块,因此使得服务间的调用变得常见且频繁;
  3. 网络的发展速度快于了硬件的发展速度,使得服务承载负载压力越来越大;因此高性能且快速响应的服务调用成了必须去面对的问题
  4. 传统的Http请求能面对跨语言的问题,但是性能远远无法达到高并发的要求
  5. 多个服务会使用到相同的数据,比如用户;因此就需要将起模块化,统一对外提供服务

常见的RPC框架集成套路

  1. 编写接口代码生成文件(用于生成客户端服务端代码)
  2. 使用开源框架提供的工具,生成各种语言下的客户端、服务器源代码
  3. 基于服务器端源代码启动并配置业务代码
  4. 客户端基于生成的客户端代码,向远端服务器获取对应的数据;整个过程相当于于调用一个本地方法

开撸

官网下载代码生成工具

官网地址

本示例模拟的业务场景

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lcs01vgk-1647677064392)(img/20190917193852890.png)]

  1. thrift client : 用于对外提供接口,getStudentByName(根据名字获取学生信息)、save(保存学生信息)
  2. thrift server: 真正getStudentByName和save操作的服务提供者
  3. APP : 服务使用者

最终实现的基础效果

编写接口代码生成文件

  • thrift支持的数据类型
    当一个RPC框架支持的语言越多,那么他支持的数据类型就会越少,为什么?因为支持数据必须是所有支持都有的,因此语言越多,交集就越少,以下是thrift支持的数据类型:

bool: A boolean value (true or false)
byte: An 8-bit signed integer
i16: A 16-bit signed integer
i32: A 32-bit signed integer
i64: A 64-bit signed integer
double: A 64-bit floating point number
string: A text string encoded using UTF-8 encoding

  • 编写脚本
    创建student.thrift
    注:如果在Idea里面创建一个thrift文件的话,工具会提醒你安装插件,安装之后,编写脚本会有响应的提醒

    // 这里指明代码生成后,所处的文件路径
    namespace java com.yyds.thriftserver.shriftcode
    namespace py py.com.yyds.thriftserver.shriftcode// 将thrif数据格式转成java 习惯的格式
    typedef i16 short
    typedef i32 int
    typedef i64 long
    typedef string String
    typedef bool boolean// 定义学生类
    struct Student {//optional 可选 非必传1:optional String name ,2:optional int age,3:optional String address
    }// 定义数据异常
    exception DataException {1:optional int code;2:optional String message;3:optional String dateTime;
    }// 定义操作学生的服务
    service StudentService {//根据名称获取学生信息 返回一个学生对象  抛出DataException异常//required 必传项Student getStudentByName(1:required String name) throws (1:DataException dataException),// 保存一个学生信息,无返回值 抛出异常void save(1:required Student student) throws (1:DataException dataException)}
    
  • 生成源代码

    语法: thrift --gen <language> <Thrift filename>

  • 文件说明
    DataException.java : 异常对象
    Student.java : 交互的数据模型对象
    StudentService.java : 服务对象,提供了接口,客户端连接相关方法

thrift-server服务

  • 通过Idea创建一个基础的Maven项目

  • pom文件中添加thrift资源库

    <!--thrift 相关资源-->
    <dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.12.0</version>
    </dependency>
  • 将上面生成的代码拷贝至项目中

  • 实现业务逻辑

    创建一个Server服务,实现StudentService.Iface接口,同时这个接口添加@Service注解,将其交由Spring管理

    @Service
    public class MyServerServiceImpl implements StudentService.Iface {@Overridepublic Student getStudentByName(String name) throws DataException, TException {System.out.println("服务端收到客户端获取用户名:" + name + "信息");Student student = new Student();// 模拟数据student.setName(name);student.setAge(30);student.setAddress("西安");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("模拟获取成功并返回:" + student);return student;}@Overridepublic void save(Student student) throws DataException, TException {System.out.println("服务端收到客户端请求保存学生信息:" + student);//模拟耗时try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("模拟保存成功!!!");}
    }
    
  • 配置文件添加端口及线程池基础配置

    server:thrift:port: 8899 #监听的端口min-thread-pool: 100  #线程池最小线程数max-thread-pool: 1000 #线程池最大线程数
  • 创建服务对象

    这里使用的是半同步半异步的THsHaServer,代码本身不多,大部分都是注释;同时将代码交由Spring管理

    package com.yyds.thrift.server;import com.yyds.service.MyServerServiceImpl;
    import com.yyds.thriftserver.thriftcode.StudentService;
    import org.apache.thrift.TProcessorFactory;
    import org.apache.thrift.protocol.TCompactProtocol;
    import org.apache.thrift.server.THsHaServer;
    import org.apache.thrift.server.TServer;
    import org.apache.thrift.transport.TFramedTransport;
    import org.apache.thrift.transport.TNonblockingServerSocket;
    import org.apache.thrift.transport.TTransportException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;@Component
    public class ThriftServer2 {//监听的端口@Value("${server.thrift.port}")private Integer port;//线程池最小线程数@Value("${server.thrift.min-thread-pool}")private Integer minThreadPool;//线程池最大线程数@Value("${server.thrift.max-thread-pool}")private Integer maxThreadPool;//业务服务对象@AutowiredMyServerServiceImpl myServerService;public void start() {try {//thrift支持的scoker有很多种//非阻塞的sockerTNonblockingServerSocket socket = new TNonblockingServerSocket(port);//THsHaServer 一个高可用的server//minWorkerThreads 最小的工作线程2//maxWorkerThreads 最大的工作线程4//如果这里Args不使用executorService指定线程池的话,创建THsHaServer会创建一个默认的LinkedBlockingQueueTHsHaServer.Args arg = new THsHaServer.Args(socket).minWorkerThreads(minThreadPool).maxWorkerThreads(maxThreadPool);//可以自定义指定线程池//ExecutorService pool = Executors.newFixedThreadPool(minThreadPool);//arg.executorService(pool);//Processor处理区  用于处理业务逻辑//泛型就是实现的业务StudentService.Processor<MyServerServiceImpl> processor = new StudentService.Processor<MyServerServiceImpl>(myServerService);//---------------thrift传输协议------------------------------//1. TBinaryProtocol      二进制传输协议//2. TCompactProtocol     压缩协议 他是基于TBinaryProtocol二进制协议在进一步的压缩,使得体积更小//3. TJSONProtocol        Json格式传输协议//4. TSimpleJSONProtocol  简单JSON只写协议,生成的文件很容易通过脚本语言解析,实际开发中很少使用//5. TDebugProtocol       简单易懂的可读协议,调试的时候用于方便追踪传输过程中的数据//-----------------------------------------------------------//设置工厂//协议工厂 TCompactProtocol压缩工厂  二进制压缩协议arg.protocolFactory(new TCompactProtocol.Factory());//---------------thrift传输格式------------------------------//---------------thrift数据传输方式------------------------------//1. TSocker            阻塞式Scoker 相当于Java中的ServerSocket//2. TFrameTransport    以frame为单位进行数据传输,非阻塞式服务中使用//3. TFileTransport     以文件的形式进行传输//4. TMemoryTransport   将内存用于IO,Java实现的时候内部实际上是使用了简单的ByteArrayOutputStream//5. TZlibTransport     使用zlib进行压缩,与其他传世方式联合使用;java当前无实现所以无法使用//传输工厂 更加底层的概念arg.transportFactory(new TFramedTransport.Factory());//arg.transportFactory(new TTransportFactory());//---------------thrift数据传输方式------------------------------//设置处理器(Processor)工厂arg.processorFactory(new TProcessorFactory(processor));//---------------thrift支持的服务模型------------------------------//1.TSimpleServer  简单的单线程服务模型,用于测试//2.TThreadPoolServer 多线程服务模型,使用的标准的阻塞式IO;运用了线程池,当线程池不够时会创建新的线程,当线程池出现大量空闲线程,线程池会对线程进行回收//3.TNonBlockingServer 多线程服务模型,使用非阻塞式IO(需要使用TFramedTransport数据传输方式)//4.THsHaServer YHsHa引入了线程池去处理(需要使用TFramedTransport数据传输方式),其模型把读写任务放到线程池去处理;Half-sync/Half-async(半同步半异步)的处理模式;Half-sync是在处理IO时间上(sccept/read/writr io),Half-async用于handler对RPC的同步处理//----------------------------//根据参数实例化server//半同步半异步的serverTServer server = new THsHaServer(arg);//---------------thrift支持的服务模型------------------------------System.out.println("thrift server started; port:" + port);//启动server// 异步非阻塞的死循环server.serve();} catch (TTransportException e) {e.printStackTrace();}}
    }
  • 启动类中添加Server的启动配置

    @SpringBootApplication
    public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}/*** 向Spring注册一个Bean对象* initMethod = "start"  表示会执行名为start的方法* start方法执行之后,就会阻塞接受客户端的请求** @return*/@Bean(initMethod = "start")public ThriftServer2 init() {ThriftServer2 thriftServer = new ThriftServer2();return thriftServer;}
    }
    
  • 启动项目
    到此,服务端的项目就已经配置完成了,启动服务出现下图剪头所指向的日志即可;

thrift-client客户端服务

  • 项目创建

    由于这个项目是一个中间服务,是thrift-server的客户端,是APP的服务端;因为要向APP提供接口,因此这里就创建一个基础的Web服务

  • pom文件中添加thrift资源库

    <!--thrift 相关资源-->
    <dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.12.0</version>
    </dependency>
    
  • 将上面生成的代码拷贝至项目中

  • 配置服务端信息

    server:port: 8887 #当前服务监听的端口,给APP端提供服务的接口thrift:host: 'localhost' #远端thrift服务IPport: 8899 #远端thrift服务端口
    
  • 创建一个远端连接对象

    public class ThriftClient {private String host;private Integer port;private TTransport tTransport;private TProtocol tProtocol;private StudentService.Client client;private void init() {tTransport = new TFramedTransport(new TSocket(host, port), 600);//协议对象 这里使用协议对象需要和服务器的一致tProtocol = new TCompactProtocol(tTransport);client = new StudentService.Client(tProtocol);}public StudentService.Client getService() {return client;}public void open() throws TTransportException {if (null != tTransport && !tTransport.isOpen())tTransport.open();}public void close() {if (null != tTransport && tTransport.isOpen())tTransport.close();}public void setHost(String host) {this.host = host;}public void setPort(Integer port) {this.port = port;}
    }
    
  • 创建一个连接自动注入帮助类

    该类用于将ThriftClient注入到Spring容器,交由Spring管理,同时每一个request请求都创建一个新的ThriftClient连接;

    @Configuration
    public class ThriftClientConfig {//服务端的地址@Value("${server.thrift.host}")private String host;//服务端的端口@Value("${server.thrift.port}")private Integer port;//初始化Bean的时候调用对象里面的init方法@Bean(initMethod = "init")//每次请求实例化一个新的ThriftClient连接对象@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)public ThriftClient init() {ThriftClient thriftClient = new ThriftClient();thriftClient.setHost(host);thriftClient.setPort(port);return thriftClient;}
    }
    
  • 定义调用远端服务的service接口

    public interface StudentServiceInf {//根据名称获取学生信息Student getStudentByName(String name);//保存学生信息void save(Student student);
    }
    
  • 添加Service的具体实现

    @Service
    public class StudentServiceImpl implements StudentServiceInf {@AutowiredThriftClient thriftClient;@Overridepublic Student getStudentByName(String name) {try {thriftClient.open();System.out.println("客户端请求用户名为:" + name + "的数据");Student student = thriftClient.getService().getStudentByName(name);System.out.println("获取成功!!!服务端返回的对象:" + student);return student;} catch (Exception e) {e.printStackTrace();} finally {thriftClient.close();}return null;}@Overridepublic void save(Student student) {try {thriftClient.open();System.out.println("客户端请求保存对象:" + student);thriftClient.getService().save(student);System.out.println("保存成功!!!");} catch (Exception e) {e.printStackTrace();} finally {thriftClient.close();}}
    }
    
  • 创建前端Controller对象
    用于对移动端提供接口

    @RestController
    public class TestController {@AutowiredStudentServiceInf studentService;@GetMapping("get")public Student getStudeByName(String name) {return studentService.getStudentByName(name);}@GetMapping("save")public Student save() {//直接模拟前端传递的数据Student student = new Student();student.setName("AAA");student.setAge(10);student.setAddress("BBB");//调用保存服务studentService.save(student);return student;}
    }
    
  • 启动服务

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLppLsWC-1647677064402)(img/image-20211021114542968.png)]

  • 测试

Thrift客户端连接池

上面的示例中,每次前端有请求上来的时候,thrift-client都是与thrift-server创建了一个新的连接,用完就直接关闭掉;Thrift框架本身是没有提供客户端的连接池的,但是,实际使用中,如果每次建立一个socket连接用完就释放掉,再次使用再次建立连接的话,其实很浪费性能;因此,连接池就是提升性能的一种很好的手段;一个Service建立一个连接之后,放在一个池子里面,需要使用的时候就直接拿出来用,用完再还回去;如果一定时间内一直没有人使用,就把资源释放掉;以上是连接池的一个基本思路;Apache Commons Pool为我们提供了一个基础的框架,使得我们能够很轻松、快速的就实现一个连接池的功能;下面我们就来通过Apache Commons Pool实现一个thrift客户端的连接池。

引入资源

<dependency><groupId>commons-pool</groupId><artifactId>commons-pool</artifactId><version>1.6</version></dependency>

连接池编码

  • 创建一个客户端的连接对象

    public class TTSocket {//thrift socket对象private TSocket tSocket;// 传输对象private TTransport tTransport;// 协议对象private TProtocol tProtocol;// 服务客户端对象private StudentService.Client client;/*** 构造方法初始化各个连接对象** @param host server的地址* @param port server的端口*/public TTSocket(String host, Integer port) {tSocket = new TSocket(host, port);tTransport = new TFramedTransport(tSocket, 600);//协议对象 这里使用协议对象需要和服务器的一致tProtocol = new TCompactProtocol(tTransport);client = new StudentService.Client(tProtocol);}/*** 获取服务客户端对象** @return*/public StudentService.Client getService() {return client;}/*** 打开通道** @throws TTransportException*/public void open() throws TTransportException {if (null != tTransport && !tTransport.isOpen())tTransport.open();}/*** 关闭通道*/public void close() {if (null != tTransport && tTransport.isOpen())tTransport.close();}/*** 判断通道是否是正常打开状态** @return*/public boolean isOpen() {Socket socket = tSocket.getSocket();if (socket.isConnected() && !socket.isClosed())return true;return false;}
    }
    
  • 创建一个工厂对象

    public class ThriftClientConnectPoolFactory {/*** 对象池*/public GenericObjectPool pool;/*** 实例化池工厂帮助类** @param config* @param ip* @param port*/public ThriftClientConnectPoolFactory(GenericObjectPool.Config config, String ip, int port) {ConnectionFactory factory = new ConnectionFactory(ip, port);//实例化池对象this.pool = new GenericObjectPool(factory, config);//设置获取对象前校验对象是否可以this.pool.setTestOnBorrow(true);}/*** 在池中获取一个空闲的对象* 如果没有空闲且池子没满,就会调用makeObject创建一个新的对象* 如果满了,就会阻塞等待,直到有空闲对象或者超时** @return* @throws Exception*/public TTSocket getConnect() throws Exception {return (TTSocket) pool.borrowObject();}/*** 将对象从池中移除** @param ttSocket*/public void invalidateObject(TTSocket ttSocket) {try {pool.invalidateObject(ttSocket);} catch (Exception e) {e.printStackTrace();}}/*** 将一个用完的对象返还给对象池** @param ttSocket*/public void returnConnection(TTSocket ttSocket) {try {pool.returnObject(ttSocket);} catch (Exception e) {if (ttSocket != null) {try {ttSocket.close();} catch (Exception ex) {//}}}}/*** 池里面保存的对象工厂*/class ConnectionFactory extends BasePoolableObjectFactory {//远端地址private String host;//端口private Integer port;/*** 构造方法初始化地址及端口** @param ip* @param port*/public ConnectionFactory(String ip, int port) {this.host = ip;this.port = port;}/*** 创建一个对象** @return* @throws Exception*/@Overridepublic Object makeObject() throws Exception {// 实例化一个自定义的一个thrift 对象TTSocket ttSocket = new TTSocket(host, port);// 打开通道ttSocket.open();return ttSocket;}/*** 销毁对象** @param obj*/public void destroyObject(Object obj) {try {if (obj instanceof TTSocket) {//尝试关闭连接((TTSocket) obj).close();}} catch (Exception e) {e.printStackTrace();}}/*** 校验对象是否可用* 通过 pool.setTestOnBorrow(boolean testOnBorrow) 设置* 设置为true这会在调用pool.borrowObject()获取对象之前调用这个方法用于校验对象是否可用** @param obj 待校验的对象* @return*/public boolean validateObject(Object obj) {if (obj instanceof TTSocket) {TTSocket socket = ((TTSocket) obj);if (!socket.isOpen()) {return false;}return true;}return false;}}
    }
    
  • 修改ThriftClientConfig,将池工厂对象通过Spring管理

    @Configuration
    public class ThriftClientConfig {//服务端的地址@Value("${server.thrift.host}")private String host;//服务端的端口@Value("${server.thrift.port}")private Integer port;//初始化Bean的时候调用对象里面的init方法@Bean(initMethod = "init")//每次请求实例化一个新的ThriftClient连接对象@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)public ThriftClient init() {ThriftClient thriftClient = new ThriftClient();thriftClient.setHost(host);thriftClient.setPort(port);return thriftClient;}@Beanpublic ThriftClientConnectPoolFactory ThriftClientPool() {//对象池的配置对象//这里测试就直接使用默认的配置//可以通过config 设置对应的参数//参数说明见  http://commons.apache.org/proper/commons-pool/api-1.6/org/apache/commons/pool/impl/GenericObjectPool.htmlGenericObjectPool.Config config = new GenericObjectPool.Config();//创建一个池工厂对象ThriftClientConnectPoolFactory thriftClientConnectPoolFactory = new ThriftClientConnectPoolFactory(config, host, port);//交由Spring管理return thriftClientConnectPoolFactory;}
    }
    
  • 使用示例

    @Service
    public class StudentServiceImpl implements StudentServiceInf {//每次创建一个新的连接的工具类//@Autowired//ThriftClient thriftClient;/*** 连接池*/@AutowiredThriftClientConnectPoolFactory thriftClientPool;@Overridepublic Student getStudentByName(String name) {TTSocket ttSocket = null;try {//通过对象池,获取一个服务客户端连接对象ttSocket = thriftClientPool.getConnect();System.out.println(ttSocket);System.out.println("客户端请求用户名为:" + name + "的数据");//调用远端对象Student student = ttSocket.getService().getStudentByName(name);System.out.println("获取成功!!!服务端返回的对象:" + student);//用完之后把对象还给对象池thriftClientPool.returnConnection(ttSocket);return student;} catch (Exception e) {e.printStackTrace();//出现异常则将当前对象从池子移除thriftClientPool.invalidateObject(ttSocket);} finally {}return null;}@Overridepublic void save(Student student) {TTSocket ttSocket = null;try {ttSocket = thriftClientPool.getConnect();System.out.println("客户端请求保存对象:" + student);ttSocket.getService().save(student);System.out.println("保存成功!!!");thriftClientPool.returnConnection(ttSocket);} catch (Exception e) {e.printStackTrace();thriftClientPool.returnConnection(ttSocket);} finally {}}
    }
    
  • 测试

    测试两个并发的情况下,如图所示的两个对象具体复用了

参考

springboot整合Thrift相关推荐

  1. SpringBoot整合Apache Thrift

    文章目录 引言 目标 代码仓库 & Demo 从Spring Starter项目结构说起 项目结构 连接池 连接池整体配置 连接池工厂 创建连接池 Client整合 注解定义 工作原理 项目启 ...

  2. SpringBoot整合RPC框架---Thrift

    文章目录 什么是Thrift 架构 支持的通讯协议 支持的传输协议 支持的服务模型 Thrift的优点 SpringBoot整合Thrift 为什么会出现RPC框架 常见的RPC框架集成套路 开撸 官 ...

  3. Springboot 整合 Netty 实战(附源码)

    作者:pjmike_pj juejin.im/post/5bd584bc518825292865395d 前言 这一篇文章主要介绍如何用Springboot 整合 Netty,由于本人尚处于学习Net ...

  4. SpringBoot第九篇: springboot整合Redis

    这篇文章主要介绍springboot整合redis,至于没有接触过redis的同学可以看下这篇文章:5分钟带你入门Redis. 引入依赖: 在pom文件中添加redis依赖: <dependen ...

  5. es springboot 不设置id_原创 | 一篇解决Springboot 整合 Elasticsearch

    ElasticSearch 结合业务的场景,在目前的商品体系需要构建搜索服务,主要是为了提供用户更丰富的检索场景以及高速,实时及性能稳定的搜索服务. ElasticSearch是一个基于Lucene的 ...

  6. springboot整合shiro使用shiro-spring-boot-web-starter

    此文章仅仅说明在springboot整合shiro时的一些坑,并不是教程 增加依赖 <!-- 集成shiro依赖 --> <dependency><groupId> ...

  7. db2 springboot 整合_springboot的yml配置文件通过db2的方式整合mysql的教程

    springboot整合MySQL很简单,多数据源就master,slave就行了,但是在整合DB2就需要另起一行,以下是同一个yml文件 先配置MySQL,代码如下 spring: datasour ...

  8. 九、springboot整合rabbitMQ

    springboot整合rabbitMQ 简介 rabbitMQ是部署最广泛的开源消息代理. rabbitMQ轻量级,易于在内部和云中部署. 它支持多种消息传递协议. RabbitMQ可以部署在分布式 ...

  9. 八、springboot整合Spring Security

    springboot整合Spring Security 简介 Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架.它是保护基于Spring的应用程序的事实标准. Spr ...

最新文章

  1. emacs 搭建racket开发环境
  2. js调整数组某些元素到指定位置顺序_Js数组里剔除指定的元素(不是指定的位置)...
  3. 产品开发管理方法工具流程 pdf_pdf转化为word的方法有什么?实用工具就有这两个...
  4. 删除对于job收缩日志失败547_MySQL中常见的几种日志
  5. 2020年泰国物联网五大部门中 制造业物联网市值为13亿美元
  6. 发动机性能测试软件,发动机的性能测试方法
  7. 2021年中国制药机械市场趋势报告、技术动态创新及2027年市场预测
  8. UOS U盘已经复制成功,有时卡死
  9. 如何下载中国卫星地图高清版大图
  10. 坐标系(Coordinate System)
  11. 他本硕博连跨3大专业,毕业后没多久被破格聘为985高校教授!
  12. 代码从svn到工作空间,Myeclipse中java项目转成Web项目
  13. 车床零件加工调度问题
  14. 【玩转ESP32】17、PWM调光
  15. 咕咕数据 HTML 转 Word API 接口
  16. matlab中buttord用法_matlab butter函数
  17. Win系统 - 单通道 16G 内存 VS 双通道 16G 内存
  18. Android开发宇视监控播放,宇视科技视频监控(EZPlayer)
  19. 读书笔记-程序员修炼之道-注重实效的哲学(二)
  20. 程序数据集散地:数据库(3)

热门文章

  1. 2020年电力电缆考试试卷及电力电缆模拟考试题库
  2. 远程连接vscode git提示 git not found. install it or configure it using the gitpath.
  3. 商业合作保密协议书范本(中英文对照版))
  4. Bootstrap响应式框架,组件化开发
  5. WM_NCHITTEST消息欺骗Windows(一)
  6. 单片机之动态数码管的显示数字1-8
  7. 网鼎杯网络安全大赛玄武组_经典的一道CTF-WriteUP-SSRFME
  8. 2020网鼎杯青龙组部分题目WP
  9. 机械员培训建筑八大员培训机械设备液压系统故障诊断技术现状
  10. 清华大学计算机百度云,清华大学《工程热力学》共53讲+精品