[转载] Thrift-server与spring集成
转载自http://shift-alt-ctrl.iteye.com/blog/1990026
Thrift服务server端,其实就是一个ServerSocket线程 + 处理器,当Thrift-client端建立链接之后,处理器负责解析socket流信息,并根据其指定的"方法名"+参数列表,来调用"服务实现类"的方法,并将执行结果(或者异常)写入到socket中.
一个server,就需要创建一个ServerSocket,并侦听本地的一个端口,这种情况对分布式部署,有一些额外的要求:client端需要知道一个"service"被部署在了那些server上.
设计思路:
1) 每个server内部采用threadPool的方式,来提升并发能力.
2) 当server启动成功后,向zookeeper注册服务节点,此后client端就可以"感知到"服务的状态
3) 通过spring的方式,配置thrift-server服务类.
其中zookeepeer注册是可选选项
1.pom.xml
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>3.0.7.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.apache.zookeeper</groupId>
- <artifactId>zookeeper</artifactId>
- <version>3.4.5</version>
- <!--<exclusions>-->
- <!--<exclusion>-->
- <!--<groupId>log4j</groupId>-->
- <!--<artifactId>log4j</artifactId>-->
- <!--</exclusion>-->
- <!--</exclusions>-->
- </dependency>
- <!--
- <dependency>
- <groupId>com.101tec</groupId>
- <artifactId>zkclient</artifactId>
- <version>0.4</version>
- </dependency>
- -->
- <dependency>
- <groupId>org.apache.thrift</groupId>
- <artifactId>libthrift</artifactId>
- <version>0.9.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-recipes</artifactId>
- <version>2.3.0</version>
- </dependency>
- <dependency>
- <groupId>commons-pool</groupId>
- <artifactId>commons-pool</artifactId>
- <version>1.6</version>
- </dependency>
- </dependencies>
本实例,使用了apache-curator作为zookeeper客户端.
2. spring-thrift-server.xml
- <!-- zookeeper -->
- <bean id="thriftZookeeper" class="com.demo.thrift.zookeeper.ZookeeperFactory" destroy-method="close">
- <property name="connectString" value="127.0.0.1:2181"></property>
- <property name="namespace" value="demo/thrift-service"></property>
- </bean>
- <bean id="sericeAddressReporter" class="com.demo.thrift.support.impl.DynamicAddressReporter" destroy-method="close">
- <property name="zookeeper" ref="thriftZookeeper"></property>
- </bean>
- <bean id="userService" class="com.demo.service.UserServiceImpl"/>
- <bean class="com.demo.thrift.ThriftServiceServerFactory" destroy-method="close">
- <property name="service" ref="userService"></property>
- <property name="configPath" value="UserServiceImpl"></property>
- <property name="port" value="9090"></property>
- <property name="addressReporter" ref="sericeAddressReporter"></property>
- </bean>
3. ThriftServiceServerFactory.java
此类严格上说并不是一个工厂类,它的主要作用就是封装指定的"service" ,然后启动一个server的过程,其中"service"属性表示服务的实现类,addressReporter表示当server启动成功后,需要指定的操作(比如,向zookeeper发送service的IP信息).
究竟当前server的ip地址是多少,在不同的设计中,有所不同,比如:有些管理员喜欢将本机的IP地址写入到os下的某个文件中,如果上层应用需要获取可靠的IP信息,就需要读取这个文件...你可以实现自己的ThriftServerIpTransfer来获取当前server的IP.
为了减少xml中的配置信息,在factory中,使用了反射机制来构建"Processor"类.
- public class ThriftServiceServerFactory implements InitializingBean {
- private Integer port;
- private Integer priority = 1;// default
- private Object service;// serice实现类
- private ThriftServerIpTransfer ipTransfer;
- private ThriftServerAddressReporter addressReporter;
- private ServerThread serverThread;
- private String configPath;
- public void setService(Object service) {
- this.service = service;
- }
- public void setPriority(Integer priority) {
- this.priority = priority;
- }
- public void setPort(Integer port) {
- this.port = port;
- }
- public void setIpTransfer(ThriftServerIpTransfer ipTransfer) {
- this.ipTransfer = ipTransfer;
- }
- public void setAddressReporter(ThriftServerAddressReporter addressReporter) {
- this.addressReporter = addressReporter;
- }
- public void setConfigPath(String configPath) {
- this.configPath = configPath;
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- if (ipTransfer == null) {
- ipTransfer = new LocalNetworkIpTransfer();
- }
- String ip = ipTransfer.getIp();
- if (ip == null) {
- throw new NullPointerException("cant find server ip...");
- }
- String hostname = ip + ":" + port + ":" + priority;
- Class serviceClass = service.getClass();
- ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- Class<?>[] interfaces = serviceClass.getInterfaces();
- if (interfaces.length == 0) {
- throw new IllegalClassFormatException("service-class should implements Iface");
- }
- // reflect,load "Processor";
- Processor processor = null;
- for (Class clazz : interfaces) {
- String cname = clazz.getSimpleName();
- if (!cname.equals("Iface")) {
- continue;
- }
- String pname = clazz.getEnclosingClass().getName() + "$Processor";
- try {
- Class pclass = classLoader.loadClass(pname);
- if (!pclass.isAssignableFrom(Processor.class)) {
- continue;
- }
- Constructor constructor = pclass.getConstructor(clazz);
- processor = (Processor) constructor.newInstance(service);
- break;
- } catch (Exception e) {
- //
- }
- }
- if (processor == null) {
- throw new IllegalClassFormatException("service-class should implements Iface");
- }
- //需要单独的线程,因为serve方法是阻塞的.
- serverThread = new ServerThread(processor, port);
- serverThread.start();
- // report
- if (addressReporter != null) {
- addressReporter.report(configPath, hostname);
- }
- }
- class ServerThread extends Thread {
- private TServer server;
- ServerThread(Processor processor, int port) throws Exception {
- TServerSocket serverTransport = new TServerSocket(port);
- Factory portFactory = new TBinaryProtocol.Factory(true, true);
- Args args = new Args(serverTransport);
- args.processor(processor);
- args.protocolFactory(portFactory);
- server = new TThreadPoolServer(args);
- }
- @Override
- public void run(){
- try{
- server.serve();
- }catch(Exception e){
- //
- }
- }
- public void stopServer(){
- server.stop();
- }
- }
- public void close() {
- serverThread.stopServer();
- }
- }
4. DynamicAddressReporter.java
在ThriftServiceServerFactory中,有个可选的属性:addressReporter, DynamicAddressReporter提供了向zookeeper注册service信息的能力,当server启动正常后,把server的IP + port发送到zookeeper中;那么此后服务消费client,就可以从zookeeper中获取server列表,并与它们建立链接(池).这样client端只需要关注zookeeper的节点名称即可,不需要配置大量的ip+port.
- public class DynamicAddressReporter implements ThriftServerAddressReporter {
- private CuratorFramework zookeeper;
- public DynamicAddressReporter(){}
- public DynamicAddressReporter(CuratorFramework zookeeper){
- this.zookeeper = zookeeper;
- }
- public void setZookeeper(CuratorFramework zookeeper) {
- this.zookeeper = zookeeper;
- }
- @Override
- public void report(String service, String address) throws Exception {
- if(zookeeper.getState() == CuratorFrameworkState.LATENT){
- zookeeper.start();
- zookeeper.newNamespaceAwareEnsurePath(service);
- }
- zookeeper.create()
- .creatingParentsIfNeeded()
- .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
- .forPath(service +"/i_",address.getBytes("utf-8"));
- }
- public void close(){
- zookeeper.close();
- }
- }
5. 测试类
- public class ServiceMain {
- /**
- * @param args
- */
- public static void main(String[] args) {
- try {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring-thrift-server.xml");
- Thread.sleep(3000000);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
本文就不在展示如何使用thrift文件生成service API的过程,请参考[Thrift简介]
Thrift-client端代码开发与配合,请参见[Thrift-client]
更多代码,请参考附件.
[转载] Thrift-server与spring集成的更多相关文章
- [转载] Thrift-client与spring集成
转载自http://shift-alt-ctrl.iteye.com/blog/1990030?utm_source=tuicool&utm_medium=referral Thrift-cl ...
- Memcached理解笔2---XMemcached&Spring集成
一.Memcached Client简要介绍 Memcached Client目前有3种: Memcached Client for Java SpyMemcached XMemcached 这三种C ...
- RabbitMQ入门教程(十六):RabbitMQ与Spring集成
原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...
- 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)
Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...
- 【转】Dubbo使用例子并且和Spring集成使用
一.编写客户端和服务器端共用接口类1.登录接口类public interface LoginService { public User login(String name, String psw ...
- axis2+spring集成
转载自:http://www.cnblogs.com/linjiqin/archive/2011/07/05/2098316.html 1.新建一个web project项目,最终工程目录如下: 注意 ...
- Spring集成jedis支持Redis3.0集群
接着上一节,我们通过spring FactoryBean实现redis 3.0集群JedisCluster与spring集成. http://www.linuxidc.com/Linux/2016- ...
- Spark SQL Thrift Server 配置 Kerberos身份认证和权限管理
转载请注明出处:http://www.cnblogs.com/xiaodf/ 之前的博客介绍了通过Kerberos + Sentry的方式实现了hive server2的身份认证和权限管理功能,本文主 ...
- activiti搭建(二)与Spring集成
转载请注明源地址:http://www.cnblogs.com/lighten/p/5876773.html 本文主要讲解如何将Activiti和Spring框架集成,再过一段时间将会将一个基础的de ...
- 使用CXF与Spring集成实现RESTFul WebService
以下引用与网络中!!! 一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存 ...
随机推荐
- Jquery实现按钮点击遮罩加载,处理完后恢复
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="EasyUiLoad.aspx. ...
- Echarts数据可视化series-scatter散点图,开发全解+完美注释
全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...
- Git命令(1)
windows中文乱码: http://www.cnblogs.com/Gukw/archive/2012/01/16/2323417.html 学习地址 :http://www.liaoxuefen ...
- 使用phpExcel导出excel时,报500错
在自己本地导出excel没有问题,但是放到服务器出现500的错误! 解决方法:查看控制器引用的header文件,是否包含空格,如下: header('Pragma:public'); ...
- win10 & Ubuntu16 双系统安装
忽然心血来潮吧,本机在已经安装了win10的背景下,想要再加一个linux系统学习学习,几经波折,终于成功. 博主笔记本里有两块固态,一个250G的装了win10,装的时间不久,镜像是在msdn上下载 ...
- JavaScript函数之实际参数对象(arguments) / callee属性 / caller属性 / 递归调用 / 获取函数名称的方法
函数的作用域:调用对象 JavaScript中函数的主体是在局部作用域中执行的,该作用域不同于全局作用域.这个新的作用域是通过将调用对象添加到作用域链的头部而创建的(没怎么理解这句话,有理解的亲可以留 ...
- 【转】C语言中内存分配
原文:C语言中内存分配 在任何程序设计环境及语言中,内存管理都十分重要.在目前的计算机系统或嵌入式系统中,内存资源仍然是有限的.因此在程序设计中,有效地管理内存资源是程序员首先考虑的问题. 第1节主要 ...
- JS中OOP之模拟封装和继承和this指向详解
大家好,今天我带大家学习一下js的OOP, 大家都知道,面向对象有三个基本特征,继承,封装和多态,面向对象的语言有那么几种,C++,PHP,JAVA等,而功能强大的JS可以模拟实现面向对象的两大特征, ...
- LeetCode 122. Best Time to Buy and Sell Stock II (买卖股票的最好时机之二)
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- 10大H5前端框架,让你开发不愁
![](http://upload-images.jianshu.io/upload_images/8373224-7903a1466f7b9722?imageMogr2/auto-orient/st ...