Thrift多路复用RPC(JavaSE)

1.初识RPC

关于RPC,它能够解决不同编程语言间的服务调用与通讯问题。

【百度百科:Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。】

【拓展:RMI 是一个良好的、特殊的RPC实现,但它适用在服务端与客户端都为JAVA语言的情况下,不可以跨语言使用。】

使用Thrift时,需要写IDL(Interface Definition Language)文件,再通过Thrift提供的编译器生成市面上主流开发语言的接口代码及实体类代码,这点与googleRPC在写xx.proto文件时相似。

通过Thrift编写的程序,在传输层上提供服务(基于TCP),其数据传输效率远远超过基于应用层HTTP协议通讯的程序。

2.编写Demo

由于日常业务中,服务端只提供单一的ServiceProcessor无法满足业务的需求,好在Thrift支持多路复用器:TMultiplexedProcessor。

2.1两个Processor的IDL:

// Student.thrift

namespace java com.thrift.generatecode.student
namespace * generatecode.student
//thrift --gen java ./Student.thrift

typedef i32 int
typedef string String

//数据结构
struct Student{
    1:optional String name,
    2:optional int age
}

//异常
exception MyException{
    1:optional String data
}

//接口
service StudentService{
    list<Student> queryStudents() ,
	int addStudent(1:required String name,2:required int age) ,
	int delStudent(1:String name) ,
    int updStudent(1:required String name,2:required int age) throws(1:MyException e)
}
// School.thrift

namespace java com.thrift.generatecode.school
namespace * generatecode.school

typedef i32 int
typedef string String

//数据结构
struct School{
    1:optional String code,
    2:optional String school_name
}

//异常
exception MyException{
    1:optional String data
}

//接口
service SchoolService{
    list<School> querySchools() ,
	int addSchool(1:required School school) ,
	int delSchool(1:String school_name) ,
    int updSchool(1:required School school) throws(1:MyException e)
}

生成接口文件需要提前下载Thrift工具Apache Thrift - Home,如果使用maven工程,可以整合到plugins。进入到含有IDL文件的目录,使用以下命令生成接口文件,并将生成的文件粘贴到工程中。

thrift --gen java ./Student.thrift
thrift --gen java ./School.thrift

2.2接口的实现类

package com.thrift.server.daoimpl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.thrift.TException;

import com.common.util.DBUtilTransactional;
import com.thrift.generatecode.student.MyException;
import com.thrift.generatecode.student.Student;
import com.thrift.generatecode.student.StudentService;

public class StudentServiceImpl implements StudentService.Iface {

	@Override
	public List<Student> queryStudents() throws TException {
		Connection c = DBUtilTransactional.getConnection();
		String sql = "SELECT NAME,AGE FROM STUDENT;";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		Student student = null;
		List<Student> stuList = null;
		try {
			pstmt = c.prepareStatement(sql);
			rs = pstmt.executeQuery();
			/*
			 * 判断结果集(元组)数量,移动游标
			 */
			rs.last();
			int totalCount = rs.getRow();
			rs.beforeFirst();
			// 初始化数组并填充数据
			if ( totalCount > 0 ) {
				stuList = new ArrayList<>(totalCount);
				while ( rs.next() ) {
					student  = new Student();
					String  name = rs.getString("name");
					int age  = rs.getInt("age");
					student.setName(name);
					student.setAge(age);
					stuList.add(student);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(rs);
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return stuList;
	}

	@Override
	public int addStudent(String name, int age) throws TException {
		int affectLine = 0;
		Connection c = DBUtilTransactional.getConnection();
		String sql = "INSERT INTO STUDENT(NAME,AGE) VALUES(?,?);";
		PreparedStatement pstmt = null;
		try {
			pstmt = c.prepareStatement(sql);
			pstmt.setString(1, name);
			pstmt.setInt(2, age);
			affectLine = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return affectLine;
	}

	@Override
	public int delStudent(String name) throws TException {
		int affectLine = 0;
		Connection c = DBUtilTransactional.getConnection();
		String sql = "DELETE FROM STUDENT WHERE NAME = ?;";
		PreparedStatement pstmt = null;
		try {
			pstmt = c.prepareStatement(sql);
			pstmt.setString(1, name);
			affectLine = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return affectLine;
	}

	@Override
	public int updStudent(String name, int age) throws MyException, TException {
		int affectLine = 0;
		Connection c = DBUtilTransactional.getConnection();
		String sql = "UPDATE STUDENT SET AGE = ? WHERE NAME = ?;";
		PreparedStatement pstmt = null;
		try {
			pstmt = c.prepareStatement(sql);
			pstmt.setInt(1, age);
			pstmt.setString(2, name);
			affectLine = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return affectLine;
	}
	
	
}
package com.thrift.server.daoimpl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.thrift.TException;

import com.common.util.DBUtilTransactional;
import com.thrift.generatecode.school.MyException;
import com.thrift.generatecode.school.School;
import com.thrift.generatecode.school.SchoolService;

public class SchoolServiceImpl implements SchoolService.Iface {

	@Override
	public List<School> querySchools() throws TException {
		Connection c = DBUtilTransactional.getConnection();
		String sql = "SELECT CODE,SCHOOL_NAME FROM SCHOOL;";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		School school = null;
		List<School> schList = null;
		try {
			pstmt = c.prepareStatement(sql);
			rs = pstmt.executeQuery();
			/*
			 * 判断结果集(元组)数量,移动游标
			 */
			rs.last();
			int totalCount = rs.getRow();
			rs.beforeFirst();
			// 初始化数组并填充数据
			if ( totalCount > 0 ) {
				schList = new ArrayList<>(totalCount);
				while ( rs.next() ) {
					school  = new School();
					String code = rs.getString("code");
					String school_name = rs.getString("school_name");
					school.setCode(code);
					school.setSchool_name(school_name);
					schList.add(school);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(rs);
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return schList;
	}

	@Override
	public int addSchool(School school) throws TException {
		int affectLine = 0;
		Connection c = DBUtilTransactional.getConnection();
		String sql = "INSERT INTO SCHOOL(CODE,SCHOOL_NAME) VALUES(?,?);";
		PreparedStatement pstmt = null;
		try {
			pstmt = c.prepareStatement(sql);
			pstmt.setString(1, school.getCode());
			pstmt.setString(2, school.getSchool_name());
			affectLine = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return affectLine;
	}

	@Override
	public int delSchool(String school_name) throws TException {
		int affectLine = 0;
		Connection c = DBUtilTransactional.getConnection();
		String sql = "DELETE FROM SCHOOL WHERE SCHOOL_NAME = ?;";
		PreparedStatement pstmt = null;
		try {
			pstmt = c.prepareStatement(sql);
			pstmt.setString(1, school_name);
			affectLine = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return affectLine;
	}

	@Override
	public int updSchool(School school) throws MyException, TException {
		int affectLine = 0;
		Connection c = DBUtilTransactional.getConnection();
		String sql = "UPDATE SCHOOL SET SCHOOL_NAME = ? WHERE CODE = ?;";
		PreparedStatement pstmt = null;
		try {
			pstmt = c.prepareStatement(sql);
			pstmt.setString(1, school.getSchool_name());
			pstmt.setString(2, school.getCode());
			affectLine = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtilTransactional.close(pstmt);
//			DBUtilTransactional.closeConnection();
		}
		return affectLine;
	}

}

2.3服务端

package com.thrift.server;

import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.TProcessorFactory;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.transport.layered.TFramedTransport;

import com.thrift.generatecode.school.SchoolService;
import com.thrift.generatecode.student.StudentService;
import com.thrift.server.daoimpl.SchoolServiceImpl;
import com.thrift.server.daoimpl.StudentServiceImpl;

public class ServerStarter {

	public static void main(String[] args) throws TTransportException{
		// 使用多线程,非阻塞的工作模式
		TNonblockingServerSocket server = new TNonblockingServerSocket(8888);
		THsHaServer.Args serverArgs = new THsHaServer.Args(server)
				.minWorkerThreads(3).maxWorkerThreads(5);
		TMultiplexedProcessor processor = new TMultiplexedProcessor();
        processor.registerProcessor( "studentService", new StudentService.Processor<StudentService.Iface>(new StudentServiceImpl()));
        processor.registerProcessor( "schoolService", new SchoolService.Processor<SchoolService.Iface>(new SchoolServiceImpl()));
		// 使用二进制格式传输数据   
		serverArgs.protocolFactory(new TBinaryProtocol.Factory());
		// 使用TFramedTransport方式传输数据
		serverArgs.transportFactory(new TFramedTransport.Factory());
		serverArgs.processorFactory(new TProcessorFactory(processor));
		TServer tserver = new THsHaServer(serverArgs);
		// 启动服务
		tserver.serve();
	}
	
}

/**
	如果在Win环境上启动进程监听后,无法找到观察进程的窗口,可以根据端口号使用命令杀进程
	cmd> netstat -ano | findstr 8888
	cmd> TASKKILL /F /PID 12305
*/

2.4客户端

package com.thrift.client;

import java.util.List;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TMultiplexedProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.layered.TFramedTransport;

import com.thrift.generatecode.school.School;
import com.thrift.generatecode.school.SchoolService;
import com.thrift.generatecode.student.*;

public class ClientStarter {

	public static void main(String[] args){
		
		TTransport transport = null;
        try{
        	transport = new TFramedTransport(new TSocket("127.0.0.1",8888),1000) ;
            TProtocol protocol =  new TBinaryProtocol(transport) ;
            //创建用于访问服务端的对象
            TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "studentService");
            StudentService.Client client =  new StudentService.Client(mp) ;
            TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "schoolService");
            SchoolService.Client client2 =  new SchoolService.Client(mp2) ;
            //与服务端建立连接
            transport.open();
            
            /**
             * 学生表相关业务接口
             */
            // 查
            System.out.println("查询学生表信息:");
            List<Student> stuList = client.queryStudents();
            if ( stuList != null )
            	for ( Student stu : stuList )
            		System.out.println(
            				new StringBuilder()
            				.append("NAME=").append(stu.getName()).append(",")
            				.append("AGE=").append(stu.getAge())
            				.toString()
            		);
            
            
            /**
             * 院校表相关业务接口
             */
            // 查
            System.out.println("查询院校信息表:");
            List<School> schList = client2.querySchools();
            if ( schList != null )
            	for ( School school : schList )
            		System.out.println(
            				new StringBuilder()
            				.append("CODE=").append(school.getCode()).append(",")
            				.append("SCHOOL=").append(school.getSchool_name())
            				.toString()
            		);
            
            
        }catch (TException e){
            e.printStackTrace();
        }finally {
        	if ( transport != null )
        		transport.close();
        }
		
	}
	
}

代码仓库:传送门

如有问题,请多指教

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值