Thrift除了可以通过TCP协议访问,还可以通过HTTP/HTTPS协议访问,在java中,thrift提供了一个servlet:org.apache.thrift.server.TServlet,我们只需继承这个TServlet就可以很方便的将TCP服务转换成HTTP/HTTPS服务,参考http://hanqunfeng.iteye.com/blog/1936556,为其中的ContractManage服务提供servlet接口,如下:
一。基本实现方法
1)服务端
package servlet; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.server.TServlet; import thrift.service.ContactManager; import thrift.service.impl.ContactManagerImpl; @SuppressWarnings("serial") public class ContractManageServlet extends TServlet { @SuppressWarnings({ "unchecked", "rawtypes" }) public ContractManageServlet(ContactManagerImpl contractManage) { super(new ContactManager.Processor(contractManage), new TCompactProtocol.Factory()); } }
只需要改写构造函数即可,将实现类通过参数的形式传递给父类。
通过spring对servlet的管理(参考:http://hanqunfeng.iteye.com/blog/605174)来注入参数:
<!-- servlet适配器,这里必须明确声明,因为spring默认没有初始化该适配器 --> <bean id="servletHandlerAdapter" class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="order" value="2"></property> </bean> <!-- servlet --> <bean name="/contractManageServlet.do" class="servlet.ContractManageServlet"> <constructor-arg> <ref bean="contactManagerImpl"/> </constructor-arg> </bean>
2)客户端
模拟一个客户端调用:
package servlet; import org.apache.http.HttpVersion; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.BasicClientConnectionManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpConnectionParams; import org.apache.thrift.TException; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.THttpClient; import org.apache.thrift.transport.TTransportException; import thrift.service.ContactManager; public class ContractMain { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String url = "http://localhost:8080/ThriftServer/contractManageServlet.do"; BasicHttpParams params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); // Disable Expect-Continue params.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); // Enable staleness check params.setParameter("http.connection.stalecheck", true); HttpConnectionParams.setSoTimeout(params, 10000); // 10 secondes HttpConnectionParams.setConnectionTimeout(params, 10000); // 10 secondes SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", 8080, PlainSocketFactory .getSocketFactory())); schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory .getSocketFactory())); BasicClientConnectionManager cm = new BasicClientConnectionManager( schemeRegistry); THttpClient thc; try { thc = new THttpClient(url, new DefaultHttpClient(cm, params)); TProtocol loPFactory = new TCompactProtocol(thc); ContactManager.Client client = new ContactManager.Client(loPFactory); System.out.println(client.getAll()); } catch (TTransportException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
OK,每增加一个thrift服务只需要写一个servlet即可,不过每个servlet只是存在一个构造函数,每次都要增加一个类略显繁琐,所以可以使用一个代理类来实现。
二。代理实现方法
1)服务端
代理类copy了org.apache.thrift.server.TServlet的代码,并且增加了两个构造函数,使其可以按需创建对象。
public class ThriftServletProxy extends HttpServlet { ………………copy……………… @SuppressWarnings({ "rawtypes", "unchecked" }) public ThriftServletProxy(String serviceInterface, String serviceIface, Object serviceImplObject) throws Exception { super(); Class Processor = Class.forName(serviceInterface + "$Processor"); Class Iface = Class .forName(StringUtils.hasText(serviceIface) ? serviceIface : serviceInterface + "$Iface"); Constructor con = Processor.getConstructor(Iface); TProcessor processor = (TProcessor) con.newInstance(serviceImplObject); this.processor = processor; this.inProtocolFactory = new TCompactProtocol.Factory(); this.outProtocolFactory = new TCompactProtocol.Factory(); this.customHeaders = new ArrayList<Map.Entry<String, String>>(); } public ThriftServletProxy(String serviceInterface, Object serviceImplObject) throws Exception { this(serviceInterface,null,serviceImplObject); } ………………copy…………………… }
这样,每增加一个服务只需要在spring配置文件中增加配置即可,不需要再单独创建一个servlet:
<!-- servlet适配器,这里必须明确声明,因为spring默认没有初始化该适配器 --> <bean id="servletHandlerAdapter" class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="order" value="2"></property> </bean> <!-- servlet proxy --> <bean name="/contractManageServletProxy.do" class="servlet.ThriftServletProxy"> <constructor-arg index="0" value="thrift.service.ContactManager"/> <constructor-arg index="1" value="interfaceI.ContractManage.Iface"/> <constructor-arg> <ref bean="contactManagerImpl"/> </constructor-arg> </bean> <bean name="/userServiceServletProxy.do" class="servlet.ThriftServletProxy"> <constructor-arg index="0" value="thrift.service.UserService"/> <constructor-arg index="1" value="interfaceI.Userservice.Iface"/> <constructor-arg> <ref bean="userServiceImpl"/> </constructor-arg> </bean>
2)客户端
客户端同样采用代理的方式来实现
package thrift.proxy; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import org.apache.http.HttpVersion; import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.params.ConnPerRouteBean; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.BasicClientConnectionManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpConnectionParams; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.THttpClient; import org.apache.thrift.transport.TTransportException; @SuppressWarnings("deprecation") public class ThriftServletClientProxy { /** * servlet 地址 */ private String servletUrl; public String getServletUrl() { return servletUrl; } public void setServletUrl(String servletUrl) { this.servletUrl = servletUrl; } /** * thrift 接口 */ private String serviceInterface; public String getServiceInterface() { return serviceInterface; } public void setServiceInterface(String serviceInterface) { this.serviceInterface = serviceInterface; } private static BasicHttpParams params; static { params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); // Disable Expect-Continue params.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); // Enable staleness check params.setParameter("http.connection.stalecheck", true); HttpConnectionParams.setSoTimeout(params, 10000); // 10 secondes HttpConnectionParams.setConnectionTimeout(params, 10000); // 10 secondes ConnManagerParams.setMaxTotalConnections(params, 20); ConnPerRouteBean connPerRoute = new ConnPerRouteBean(20); ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute); } @SuppressWarnings({ "rawtypes", "unchecked" }) public Object getClient() { Object object = null; try { BasicClientConnectionManager cm = new BasicClientConnectionManager( getSchemeRegistry()); THttpClient thc = new THttpClient(getServletUrl(), new DefaultHttpClient(cm, params)); TProtocol loPFactory = new TCompactProtocol(thc); Class client = Class.forName(getServiceInterface() + "$Client"); Constructor con = client.getConstructor(TProtocol.class); object = con.newInstance(loPFactory); } catch (TTransportException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return object; } public SchemeRegistry getSchemeRegistry() { SchemeRegistry schemeRegistry = new SchemeRegistry(); URL url; try { // 分析url,取出端口 url = new URL(getServletUrl()); String protocol = url.getProtocol(); int port = url.getPort(); if (-1 == port) { if ("https".equals(protocol)) { port = 443; } else { port = 80; } } if ("https".equals(protocol)) { schemeRegistry.register(new Scheme("https", port, SSLSocketFactory.getSocketFactory())); } else { schemeRegistry.register(new Scheme("http", port, PlainSocketFactory.getSocketFactory())); } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return schemeRegistry; } }
每调用一个接口,在spring中增加一个配置即可:
<bean id="contractManage" class="thrift.proxy.ThriftServletClientProxy"> <property name="servletUrl"> <value> http://localhost:8080/ThriftServer/contractManageServletProxy.do </value> </property> <property name="serviceInterface" value="thrift.service.ContactManager"> </property> </bean> <bean id="userService" class="thrift.proxy.ThriftServletClientProxy"> <property name="servletUrl"> <value> http://localhost:8080/ThriftServer/userServiceServletProxy.do </value> </property> <property name="serviceInterface" value="thrift.service.UserService"> </property> </bean>
调用方式参考代码中的IndexController。
相关推荐
- 创建Spring配置文件,如`thrift-server.xml`,配置Thrift服务器实例(通常是`TNonBlockingServer`或`TSimpleServer`)和Thrift服务处理器。 - 使用Spring的`<bean>`标签定义Thrift服务接口的实现,并通过`@...
spring-cloud-starter-thrift包括客户端spring-cloud-starter-thrift-client和服务端spring-cloud-starter-thrift-server两个模块。服务端:支持Apache Thrift的各种原生服务线程模型,包括单线程阻塞模型(simple)、...
maven-thrift-plugin-0.1.11.jar
标题中的"thrift-0.9.1.exe"和"thrift-0.9.2.exe"是Thrift框架的不同版本。这些文件是Windows平台上的可执行程序,用于生成与Thrift相关的代码。0.9.1和0.9.2分别代表了Thrift的两个发行版本,每个版本可能包含了新...
maven-thrift-plugin-0.1.11-sources.jar
maven插件 maven-thrift-plugin-0.1.10
1. **集成Thrift**:Thrift-Laravel项目提供了集成Thrift到Laravel的工具和示例,使得开发者可以在Laravel应用中轻松地创建Thrift服务提供商和消费者。 2. **服务提供者**:在Laravel中,服务提供者负责注册和绑定...
"thrift-0.13.0.zip"这个压缩包包含了Thrift 0.13.0版本的源码和工具,用于生成Go语言的Thrift接口。Thrift IDL文件描述了HBase服务的接口,包括批量读写操作。批量操作在HBase中是非常重要的,因为它们可以显著提高...
"thrift-0.9.3.exe"是Thrift框架的一个特定版本(0.9.3)的可执行文件,主要用于Windows操作系统。这个文件在Thrift开发过程中扮演着至关重要的角色,它能帮助开发者将定义好的Thrift接口文件(.thrift)转换为不同...
在“thrift-0.13.0.tar.gz”这个压缩包中,包含了Thrift 0.13.0版本的相关源码、库文件和文档。 Thrift IDL是Thrift的关键组成部分,它允许开发者用类似C++或Java的语法定义数据类型和服务接口。例如,你可以定义一...
thrift开发时,将thrift文件自动生成java文件需要用到thrift-0.9.0.exe
thrift开发时,将thrift文件自动生成java文件需要用到thrift-0.9.0.exe
Thrift-0.9.0是这个框架的一个版本,包含源代码,用户可以编译并根据需要在自己的项目中使用。 在Thrift的实现中,它首先定义了一种中间表示(IDL,Interface Description Language),允许开发者描述服务接口、...
【 Maven-Thrift-Server:构建Thrift服务的Maven实践】 在软件开发中,Thrift是一种高效的跨语言服务开发框架,由Facebook开发并开源。它允许定义数据类型和服务接口,然后自动生成各种编程语言的代码,使得不同...
标题"thrift-0.13.0在Windows上exe程序.rar"表明这个压缩包包含了Thrift 0.13.0版本的Windows可执行文件。这个版本可能包含了一些新特性、修复了已知问题,或者对性能进行了优化。在Windows环境下,.exe文件是可直接...
在"thrift-0.9.1.exe"和"thrift-0.9.2.exe"这两个版本中,主要包含了Thrift编译器和相关的库文件。编译器是一个命令行工具,用于将IDL文件转换为实际编程语言的代码。例如,你可以编写一个.thrift文件定义服务接口,...
银河麒麟高级服务器版v10系统的thrift-0.17.0及其依赖安装包
对于Java项目,通常会引入thrift-gen和libthrift的JAR包。 接下来,我们需要编写Thrift IDL文件。这个文件定义了服务接口和数据类型,例如: ```idl service MyService { string sayHello(1:string name) } ``` ...