转载自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

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>3.0.7.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.apache.zookeeper</groupId>
  9. <artifactId>zookeeper</artifactId>
  10. <version>3.4.5</version>
  11. <!--<exclusions>-->
  12. <!--<exclusion>-->
  13. <!--<groupId>log4j</groupId>-->
  14. <!--<artifactId>log4j</artifactId>-->
  15. <!--</exclusion>-->
  16. <!--</exclusions>-->
  17. </dependency>
  18. <!--
  19. <dependency>
  20. <groupId>com.101tec</groupId>
  21. <artifactId>zkclient</artifactId>
  22. <version>0.4</version>
  23. </dependency>
  24. -->
  25. <dependency>
  26. <groupId>org.apache.thrift</groupId>
  27. <artifactId>libthrift</artifactId>
  28. <version>0.9.1</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.apache.curator</groupId>
  32. <artifactId>curator-recipes</artifactId>
  33. <version>2.3.0</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>commons-pool</groupId>
  37. <artifactId>commons-pool</artifactId>
  38. <version>1.6</version>
  39. </dependency>
  40. </dependencies>

本实例,使用了apache-curator作为zookeeper客户端.

2. spring-thrift-server.xml

  1. <!-- zookeeper -->
  2. <bean id="thriftZookeeper" class="com.demo.thrift.zookeeper.ZookeeperFactory" destroy-method="close">
  3. <property name="connectString" value="127.0.0.1:2181"></property>
  4. <property name="namespace" value="demo/thrift-service"></property>
  5. </bean>
  6. <bean id="sericeAddressReporter" class="com.demo.thrift.support.impl.DynamicAddressReporter" destroy-method="close">
  7. <property name="zookeeper" ref="thriftZookeeper"></property>
  8. </bean>
  9. <bean id="userService" class="com.demo.service.UserServiceImpl"/>
  10. <bean class="com.demo.thrift.ThriftServiceServerFactory" destroy-method="close">
  11. <property name="service" ref="userService"></property>
  12. <property name="configPath" value="UserServiceImpl"></property>
  13. <property name="port" value="9090"></property>
  14. <property name="addressReporter" ref="sericeAddressReporter"></property>
  15. </bean>

3. ThriftServiceServerFactory.java

此类严格上说并不是一个工厂类,它的主要作用就是封装指定的"service" ,然后启动一个server的过程,其中"service"属性表示服务的实现类,addressReporter表示当server启动成功后,需要指定的操作(比如,向zookeeper发送service的IP信息).

究竟当前server的ip地址是多少,在不同的设计中,有所不同,比如:有些管理员喜欢将本机的IP地址写入到os下的某个文件中,如果上层应用需要获取可靠的IP信息,就需要读取这个文件...你可以实现自己的ThriftServerIpTransfer来获取当前server的IP.

为了减少xml中的配置信息,在factory中,使用了反射机制来构建"Processor"类.

  1. public class ThriftServiceServerFactory implements InitializingBean {
  2. private Integer port;
  3. private Integer priority = 1;// default
  4. private Object service;// serice实现类
  5. private ThriftServerIpTransfer ipTransfer;
  6. private ThriftServerAddressReporter addressReporter;
  7. private ServerThread serverThread;
  8. private String configPath;
  9. public void setService(Object service) {
  10. this.service = service;
  11. }
  12. public void setPriority(Integer priority) {
  13. this.priority = priority;
  14. }
  15. public void setPort(Integer port) {
  16. this.port = port;
  17. }
  18. public void setIpTransfer(ThriftServerIpTransfer ipTransfer) {
  19. this.ipTransfer = ipTransfer;
  20. }
  21. public void setAddressReporter(ThriftServerAddressReporter addressReporter) {
  22. this.addressReporter = addressReporter;
  23. }
  24. public void setConfigPath(String configPath) {
  25. this.configPath = configPath;
  26. }
  27. @Override
  28. public void afterPropertiesSet() throws Exception {
  29. if (ipTransfer == null) {
  30. ipTransfer = new LocalNetworkIpTransfer();
  31. }
  32. String ip = ipTransfer.getIp();
  33. if (ip == null) {
  34. throw new NullPointerException("cant find server ip...");
  35. }
  36. String hostname = ip + ":" + port + ":" + priority;
  37. Class serviceClass = service.getClass();
  38. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  39. Class<?>[] interfaces = serviceClass.getInterfaces();
  40. if (interfaces.length == 0) {
  41. throw new IllegalClassFormatException("service-class should implements Iface");
  42. }
  43. // reflect,load "Processor";
  44. Processor processor = null;
  45. for (Class clazz : interfaces) {
  46. String cname = clazz.getSimpleName();
  47. if (!cname.equals("Iface")) {
  48. continue;
  49. }
  50. String pname = clazz.getEnclosingClass().getName() + "$Processor";
  51. try {
  52. Class pclass = classLoader.loadClass(pname);
  53. if (!pclass.isAssignableFrom(Processor.class)) {
  54. continue;
  55. }
  56. Constructor constructor = pclass.getConstructor(clazz);
  57. processor = (Processor) constructor.newInstance(service);
  58. break;
  59. } catch (Exception e) {
  60. //
  61. }
  62. }
  63. if (processor == null) {
  64. throw new IllegalClassFormatException("service-class should implements Iface");
  65. }
  66. //需要单独的线程,因为serve方法是阻塞的.
  67. serverThread = new ServerThread(processor, port);
  68. serverThread.start();
  69. // report
  70. if (addressReporter != null) {
  71. addressReporter.report(configPath, hostname);
  72. }
  73. }
  74. class ServerThread extends Thread {
  75. private TServer server;
  76. ServerThread(Processor processor, int port) throws Exception {
  77. TServerSocket serverTransport = new TServerSocket(port);
  78. Factory portFactory = new TBinaryProtocol.Factory(true, true);
  79. Args args = new Args(serverTransport);
  80. args.processor(processor);
  81. args.protocolFactory(portFactory);
  82. server = new TThreadPoolServer(args);
  83. }
  84. @Override
  85. public void run(){
  86. try{
  87. server.serve();
  88. }catch(Exception e){
  89. //
  90. }
  91. }
  92. public void stopServer(){
  93. server.stop();
  94. }
  95. }
  96. public void close() {
  97. serverThread.stopServer();
  98. }
  99. }

4. DynamicAddressReporter.java

在ThriftServiceServerFactory中,有个可选的属性:addressReporter, DynamicAddressReporter提供了向zookeeper注册service信息的能力,当server启动正常后,把server的IP + port发送到zookeeper中;那么此后服务消费client,就可以从zookeeper中获取server列表,并与它们建立链接(池).这样client端只需要关注zookeeper的节点名称即可,不需要配置大量的ip+port.

  1. public class DynamicAddressReporter implements ThriftServerAddressReporter {
  2. private CuratorFramework zookeeper;
  3. public DynamicAddressReporter(){}
  4. public DynamicAddressReporter(CuratorFramework zookeeper){
  5. this.zookeeper = zookeeper;
  6. }
  7. public void setZookeeper(CuratorFramework zookeeper) {
  8. this.zookeeper = zookeeper;
  9. }
  10. @Override
  11. public void report(String service, String address) throws Exception {
  12. if(zookeeper.getState() == CuratorFrameworkState.LATENT){
  13. zookeeper.start();
  14. zookeeper.newNamespaceAwareEnsurePath(service);
  15. }
  16. zookeeper.create()
  17. .creatingParentsIfNeeded()
  18. .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
  19. .forPath(service +"/i_",address.getBytes("utf-8"));
  20. }
  21. public void close(){
  22. zookeeper.close();
  23. }
  24. }

5. 测试类

  1. public class ServiceMain {
  2. /**
  3. * @param args
  4. */
  5. public static void main(String[] args) {
  6. try {
  7. ApplicationContext context = new ClassPathXmlApplicationContext("spring-thrift-server.xml");
  8. Thread.sleep(3000000);
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }

本文就不在展示如何使用thrift文件生成service API的过程,请参考[Thrift简介]

Thrift-client端代码开发与配合,请参见[Thrift-client]

更多代码,请参考附件.

[转载] Thrift-server与spring集成的更多相关文章

  1. [转载] Thrift-client与spring集成

    转载自http://shift-alt-ctrl.iteye.com/blog/1990030?utm_source=tuicool&utm_medium=referral Thrift-cl ...

  2. Memcached理解笔2---XMemcached&Spring集成

    一.Memcached Client简要介绍 Memcached Client目前有3种: Memcached Client for Java SpyMemcached XMemcached 这三种C ...

  3. RabbitMQ入门教程(十六):RabbitMQ与Spring集成

    原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...

  4. 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)

    Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...

  5. 【转】Dubbo使用例子并且和Spring集成使用

    一.编写客户端和服务器端共用接口类1.登录接口类public interface LoginService {    public User login(String name, String psw ...

  6. axis2+spring集成

    转载自:http://www.cnblogs.com/linjiqin/archive/2011/07/05/2098316.html 1.新建一个web project项目,最终工程目录如下: 注意 ...

  7. Spring集成jedis支持Redis3.0集群

    接着上一节,我们通过spring FactoryBean实现redis 3.0集群JedisCluster与spring集成.  http://www.linuxidc.com/Linux/2016- ...

  8. Spark SQL Thrift Server 配置 Kerberos身份认证和权限管理

    转载请注明出处:http://www.cnblogs.com/xiaodf/ 之前的博客介绍了通过Kerberos + Sentry的方式实现了hive server2的身份认证和权限管理功能,本文主 ...

  9. activiti搭建(二)与Spring集成

    转载请注明源地址:http://www.cnblogs.com/lighten/p/5876773.html 本文主要讲解如何将Activiti和Spring框架集成,再过一段时间将会将一个基础的de ...

  10. 使用CXF与Spring集成实现RESTFul WebService

    以下引用与网络中!!!     一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存 ...

随机推荐

  1. HDU1285 确定比赛名次

    有N个比赛队(<=N<=),编号依次为1,,,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结 ...

  2. js 将一大段时间均分为很多个小时间段

    最近写项目,遇到一个将选中时间段平均分割为若干小段,然后根据小段时间在数据库查询求均值的问题,后台大哥犯懒,非说后台做不了,让我分好传给他ヾ(. ̄□ ̄)ツ゜゜゜好气呦,但还要保持微笑,我就是这么懂礼貌 ...

  3. WPF控件 在XP下获得焦点有虚线框

    所有 Button.ListBox等控件获得焦点时有虚线框.如图:选中523这个按钮就出线虚框. 我在App.xaml中添加适应所有按钮的样式,无效 <Style  TargetType=&qu ...

  4. WPF ListBox数据绑定

    本文来源 http://wshoufeng1989.blog.163.com/blog/static/202047033201282911633670/  风随影动的博客 使用数据库AllData , ...

  5. YYHS-NOIP模拟赛-gcd

    题解 这道题题解里说用莫比乌斯反演做(我这个蒟蒻怎么会做呢) 但是不会,所以我们另想方法,这里我们用容斥来做 我们先把500000以内的所有质数筛出来 每次读入编号的时候,先把编号对应的这个数分解质因 ...

  6. win10 UWP 你写我读

    想要电脑读出我们写的内容,在win10,很简单 其实这个技术在windows7就有了,但是现在win10让写出一个你写我读的软件很简单. 我们需要一个类MediaElement来播放,因为window ...

  7. Python 初学者 入门 应该学习 python 2 还是 python 3?

    许多刚入门 Python 的朋友都在纠结的的问题是:我应该选择学习 python2 还是 python3? 对此,咪博士的回答是:果断 Python3 ! 可是,还有许多小白朋友仍然犹豫:那为什么还是 ...

  8. faster-rcnn中ROI_POOIING层的解读

    在没有出现sppnet之前,RCNN使用corp和warp来对图片进行大小调整,这种操作会造成图片信息失真和信息丢失.sppnet这个模型推出来之后(关于这个网络的描述,可以看看之前写的一篇理解:ht ...

  9. 关于python如果没有numpy模块如何处理

    1.在python中,你在python的shell输入>>>import numpy 但是编译器告诉你没有numpy库,这时候你就要导入python库,那么如何导入呢 2.收下访问h ...

  10. 【ASP.NET MVC 学习笔记】- 17 Model验证

    本文参考:http://www.cnblogs.com/willick/p/3434483.html 1.Model验证用于在实际项目中对用户提交的表单的信息进行验证,MVC对其提供了很好的支持. 2 ...