前言: thrift的基础知识
1.Thrift的服务端
1.1.引入maven依赖
<parent>
<artifactId>com.ajc.demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thrift 相关资源-->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version><!--版本号自己选一个就行-->
</dependency>
</dependencies>
1.2.定义thrift文件
student.thrift:
//指明生成的代码在哪个包下
namespace java com.ajc.thrift.server.model
//讲shrift的数据类型格式转为java习惯的格式
typedef i16 short
typedef i32 int
typedef i64 long
typedef string String
typedef bool boolean
/**
* 学生对象
**/
struct Student{
//姓名
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 dataTime
}
/**
* 学生服务
**/
service StudentService{
//根据名称获取学生信息
Student getStudentByName(1:required String name) throws (1:DataException dataException),
//保存一个学生信息
void save(1:required Student student) throws (1:DataException dataException)
}
在该文件下的终端执行命令
thrift -gen java student.thrift
然后会生成对应的java文件,根据自己的文件目录进行分配。
注意:这里不要修改任何一个生成的文件
1.3.定义service实现类,完成业务逻辑
StudentServiceImpl:
@Service
@Slf4j
public class StudentServiceImpl implements StudentService.Iface {
@Override
public Student getStudentByName(String name) throws DataException, TException {
log.info("服务端收到了客户端获取用户名的请求 name={}",name);
Student student = new Student();
student.setName("小李");
student.setAge(18);
student.setAddress("中国河南郑州");
return student;
}
@Override
public void save(Student student) throws DataException, TException {
log.info("服务端收到了客户端保存学生信息的请求,{}",student);
try{
//模拟保存时间
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
log.info("学生信息保存成功~");
}
}
1.1.3.客户端配置文件
application.yml
server:
port: 8081
spring:
application:
name: thrift-server
thrift:
port: 8899 #监听的端口
min-thread-pool: 100 #线程池最小线程数
max-thread-pool: 1000 #线程池最大线程数
1.4.服务端配置类
@Component
@Slf4j
public class ThriftServer {
//监听的端口
@Value("${thrift.port}")
private Integer port;
//线程池最小线程数
@Value("${thrift.min-thread-pool}")
private Integer minThreadPool;
//线程池最大线程数
@Value("${thrift.max-thread-pool}")
private Integer maxThreadPool;
//业务服务对象
@Autowired
StudentServiceImpl studentService;
@PostConstruct
public void start() {
try {
/**
* thrift支持的scoker有很多种
* 这里采用非阻塞的socker
*/
TNonblockingServerSocket socket = new TNonblockingServerSocket(port);
/**
* THsHaServer 一个高可用的server
* minWorkerThreads 最小的工作线程2
* maxWorkerThreads 最大的工作线程4
* 如果这里Args不使用executorService指定线程池的话,创建THsHaServer会创建一个默认的LinkedBlockingQueue
*/
THsHaServer.Args arg =
new THsHaServer.Args(socket).minWorkerThreads(minThreadPool).maxWorkerThreads(maxThreadPool);
//可以自定义指定线程池
//ExecutorService pool = Executors.newFixedThreadPool(minThreadPool);
//arg.executorService(pool);
/**
* Processor处理区 用于处理业务逻辑
* 泛型就是实现的业务
*/
StudentService.Processor<StudentServiceImpl> processor = new StudentService.Processor<>(studentService);
/**
*---------------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
* 半同步半异步的server
*/
TServer server = new THsHaServer(arg);
//---------------thrift支持的服务模型------------------------------
log.info("shrift server started; port: {}", port);
//启动server
// 异步非阻塞的死循环
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
}
1.5.启动服务端
看到以上日志内容,说明容器正常启动。
2.Thrift的客户端
2.1.引入依赖
<parent>
<artifactId>com.ajc.demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thrift 相关资源-->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version><!--版本号自己选一个就行-->
</dependency>
</dependencies>
2.2.生成对应的java文件并放在合适的包下。
具体操作,一般是服务端提供*.thrift文件或者java文件给客户端(maven依赖)。
2.3.客户端配置 application.yml
server:
port: 8081
spring:
application:
name: thrift-server
thrift:
port: 8899 #监听的端口
min-thread-pool: 100 #线程池最小线程数
max-thread-pool: 1000 #线程池最大线程数
2.4.客户端配置 ThriftClient
@Component
//每次请求实例化一个新的ThriftClient连接对象
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ThriftClient {
@Value("${thrift.host}")
private String host;
@Value("${thrift.port}")
private Integer port;
private TTransport tTransport;
private TProtocol tProtocol;
private StudentService.Client client;
@PostConstruct
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();
}
}
}
2.5.Controller 接受web请求
@RestController
@RequestMapping("/thrift")
@Slf4j
public class ThriftTestController {
@Autowired
ThriftClient thriftClient;
@RequestMapping("/get")
public Student getStudentByName(String name){
try{
thriftClient.open();
log.info("客户端请求用户名为: {}",name);
StudentService.Client service = thriftClient.getService();
System.out.println(service);
Student student = thriftClient.getService().getStudentByName(name);
log.info("学生信息: {}",student);
return student;
}catch (Exception e){
e.printStackTrace();
}finally {
thriftClient.close();
}
return null;
}
}
2.6.启动客户端工程,浏览器请求接口
到此 springBoot整合Thrift的基本流程已经完毕了,在日常开发中,client一般是由客户端进行封装,提供给客户端直接使用的。