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]
更多代码,请参考附件.
相关推荐
spring-cloud-starter-thrift简介spring-cloud-starter-thrift提供Spring Cloud对可伸缩的跨语言服务调用框架Apache Thrift的封装和集成。spring-cloud-starter-thrift包括客户端spring-cloud-starter-thrift-client...
本篇文章将探讨如何在Spring框架中集成Thrift,构建一个Server和Client,以便在分布式系统中实现高效的数据通信。 首先,我们需要了解Thrift的基本原理。Thrift通过定义服务接口和数据结构的IDL(接口定义语言)...
将 Spring 与 Thrift 集成,可以利用 Spring 的强大功能来管理和调度 Thrift 服务,同时借助 Thrift 实现高效的数据传输和跨语言服务调用。 集成 Spring 和 Thrift 主要涉及以下几个步骤: 1. **创建 Thrift IDL ...
- **集成Jaeger或OpenTelemetry**:Zipkin也支持Jaeger的Thrift格式和OpenTelemetry协议,方便与其他分布式追踪系统互操作。 7. **持续集成与自动化**: - **Docker化**:将Zipkin服务器部署到Docker容器中,便于...
在本篇小讲中,我们将探讨如何将Thrift与Spring框架结合,以便于构建微服务架构。 首先,让我们了解Thrift的基本工作原理。Thrift IDL(接口定义语言)允许开发者声明服务方法和数据类型,类似于Java中的接口或C++...
Spring Data Hadoop官方文档涉及了多个关于如何使用Spring Data Hadoop框架及其与Hadoop生态系统的集成的相关知识点。以下为文档中提到的主要知识点: 1. **Hadoop基本配置、MapReduce和分布式缓存**: - Spring ...
### Spring与Hadoop集成知识点详解 #### 一、Spring与Hadoop集成概述 Spring与Hadoop集成是指在Spring框架中引入Hadoop的功能,利用Spring强大的依赖注入和面向切面编程能力来简化Hadoop应用程序的开发过程。通过...
此框架旨在简化在 Hadoop 生态系统中的开发工作,提供了一种更加面向 Spring 的方式来处理 MapReduce 任务、HDFS 文件系统操作以及与 HBase 和 Hive 等数据存储系统的集成。 #### 二、Spring 和 Hadoop ##### 2.1 ...
Zipkin 与许多流行的微服务框架和库兼容,如 Spring Cloud、Dropwizard 和 Apache Thrift,使得它在分布式系统中的应用非常广泛。了解并熟练使用 Zipkin 可以帮助你更好地理解和优化服务间的交互,提升整体系统的...
融数微服务架构可能采用了Spring Cloud作为核心框架,利用Eureka进行服务注册与发现,Ribbon和Zuul实现负载均衡和API网关,Archaius和Spring Cloud Config Server处理配置服务,Hystrix提供服务的高可用和容错能力。...
在实际项目中,`ThriftServerApplication`会先启动,注册自身到Zookeeper,然后`ThriftClientApplication`在启动时会从Zookeeper中查找可用的服务实例,建立起与ThriftServer的连接。这样的设计使得系统具有良好的可...
- **框架**:支持Spring、Spring Boot(含嵌入式Tomcat、Jetty、Undertow)、Spring异步通信等。 - **HTTP客户端**:如Apache HTTP Client 3.x/4.x、JDK Http Connector、Google HttpClient、OkHttpClient、Ning ...
2、权限控制到方法级别、统一的cas单点登录用户认证 和 thrift RPC 服务调用用于数据同步 3、此用于包含前台和后台2部分以及依赖cas用户单点登录项目() 4、前台:一个企业宣传网站展示 5、后台:系统管理->用户管理、...