`
hanqunfeng
  • 浏览: 1541931 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Thrift--Spring集成ThriftServlet

阅读更多

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。

 

分享到:
评论
2 楼 brilliant1984 2014-11-27  
真棒。 可以用,但目前0.9.1一个端口支持多个service类,正在楼主的基础上改进
1 楼 MrwenQ 2014-09-25  
楼主的代码 我部署报错是什么情况啊,求解释

相关推荐

    Thrift-server与spring集成

    - 创建Spring配置文件,如`thrift-server.xml`,配置Thrift服务器实例(通常是`TNonBlockingServer`或`TSimpleServer`)和Thrift服务处理器。 - 使用Spring的`&lt;bean&gt;`标签定义Thrift服务接口的实现,并通过`@...

    spring-cloud-starter-thrift:spring-cloud-starter-thrift提供SpringCloud对可伸缩的跨语言服务调用框架Apache Thrift的封装和集成

    spring-cloud-starter-thrift包括客户端spring-cloud-starter-thrift-client和服务端spring-cloud-starter-thrift-server两个模块。服务端:支持Apache Thrift的各种原生服务线程模型,包括单线程阻塞模型(simple)、...

    thrift-0.9.1.exe和thrift-0.9.2.exe

    标题中的"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-thrift-plugin-0.1.11-sources.jar

    maven-thrift-plugin-0.1.11.jar

    maven-thrift-plugin-0.1.11.jar

    maven-thrift-plugin-0.1.10

    maven插件 maven-thrift-plugin-0.1.10

    Laravel开发-thrift-laravel

    1. **集成Thrift**:Thrift-Laravel项目提供了集成Thrift到Laravel的工具和示例,使得开发者可以在Laravel应用中轻松地创建Thrift服务提供商和消费者。 2. **服务提供者**:在Laravel中,服务提供者负责注册和绑定...

    thrift-0.13.0.zip

    "thrift-0.13.0.zip"这个压缩包包含了Thrift 0.13.0版本的源码和工具,用于生成Go语言的Thrift接口。Thrift IDL文件描述了HBase服务的接口,包括批量读写操作。批量操作在HBase中是非常重要的,因为它们可以显著提高...

    thrift-0.9.3.exe

    "thrift-0.9.3.exe"是Thrift框架的一个特定版本(0.9.3)的可执行文件,主要用于Windows操作系统。这个文件在Thrift开发过程中扮演着至关重要的角色,它能帮助开发者将定义好的Thrift接口文件(.thrift)转换为不同...

    thrift-0.13.0.tar.gz

    在“thrift-0.13.0.tar.gz”这个压缩包中,包含了Thrift 0.13.0版本的相关源码、库文件和文档。 Thrift IDL是Thrift的关键组成部分,它允许开发者用类似C++或Java的语法定义数据类型和服务接口。例如,你可以定义一...

    thrift-0.9.2.exe

    thrift开发时,将thrift文件自动生成java文件需要用到thrift-0.9.0.exe

    thrift-0.9.0.exe

    thrift开发时,将thrift文件自动生成java文件需要用到thrift-0.9.0.exe

    thrift-0.9.0.tar.gz

    Thrift-0.9.0是这个框架的一个版本,包含源代码,用户可以编译并根据需要在自己的项目中使用。 在Thrift的实现中,它首先定义了一种中间表示(IDL,Interface Description Language),允许开发者描述服务接口、...

    maven-thrift-server

    【 Maven-Thrift-Server:构建Thrift服务的Maven实践】 在软件开发中,Thrift是一种高效的跨语言服务开发框架,由Facebook开发并开源。它允许定义数据类型和服务接口,然后自动生成各种编程语言的代码,使得不同...

    thrift-0.13.0在Windows上exe程序.rar

    标题"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-0.9.1.exe"和"thrift-0.9.2.exe"这两个版本中,主要包含了Thrift编译器和相关的库文件。编译器是一个命令行工具,用于将IDL文件转换为实际编程语言的代码。例如,你可以编写一个.thrift文件定义服务接口,...

    银河麒麟高级服务器版v10系统的thrift-0.17.0及其依赖安装包

    银河麒麟高级服务器版v10系统的thrift-0.17.0及其依赖安装包

    Spring集成Thrift--Server AND Client

    对于Java项目,通常会引入thrift-gen和libthrift的JAR包。 接下来,我们需要编写Thrift IDL文件。这个文件定义了服务接口和数据类型,例如: ```idl service MyService { string sayHello(1:string name) } ``` ...

Global site tag (gtag.js) - Google Analytics