Spring集成Thrift - Servlet

Thrift除了可以通过TCP协议访问,还可以通过HTTP/HTTPS协议访问,在java中,thrift提供了一个servlet:org.apache.thrift.server.TServlet,我们只需继承这个TServlet就可以很方便的将TCP服务转换成HTTP/HTTPS服务,下面我们仍然以前面的helloworld接口与实现为例演示。

1.导入所需的jar包

<dependency>
			<groupId>org.apache.thrift</groupId>
			<artifactId>libthrift</artifactId>
			<version>0.9.2</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.5.8</version>
		</dependency>
		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.0.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>4.0.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>4.0.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.0.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.0.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>
2.配置工程的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>ThriftTest</display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath:applicationContext-*.xml
		</param-value>
	</context-param>
	
	<filter>
		<filter-name>characterEncoding</filter-name>
		<filter-class>
			org.springframework.web.filter.CharacterEncodingFilter
		</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>characterEncoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	
	<listener>
		<listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
	</listener>
 
	<session-config>
		<session-timeout>30</session-timeout>
	</session-config>
	
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
	
</web-app>
3.配置spring mvc的dispatcherServlet-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tool="http://www.springframework.org/schema/tool" xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
			http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
			http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
			http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
			http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-4.0.xsd
			http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd"
	default-lazy-init="true">

	<!-- 定义视图查找规则 -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView">
		</property>
		<property name="prefix" value="/WEB-INF/jsp/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

	<!-- 定义注解驱动Controller方法处理适配器 -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

	<bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />

	<!-- 定义文件上传处理器 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
		p:defaultEncoding="UTF-8" />

	<!-- 定义本地化变更拦截器 -->
	<bean id="localeChangeInterceptor"
		class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />

	<util:list id="interceptors">
		<ref bean="localeChangeInterceptor" />
	</util:list>

	<!-- 定义注解URL映射处理器 -->
	<bean id="urlMapping"
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
		<property name="interceptors" ref="interceptors" />
		<property name="order" value="1" />
	</bean>
</beans>

继承TServlet实现

1、服务端

1)TServlet实现类HelloworldServlet.java
package cn.slimsmart.thrift.demo.spring.servlet;

import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.TServlet;

import cn.slimsmart.thrift.demo.helloworld.HelloWorld;

/**
 * 服务端TServlet
 */
public class HelloworldServlet extends TServlet {

	private static final long serialVersionUID = 1L;

	public HelloworldServlet(HelloWorld.Iface helloWorldImpl) {
		super(new HelloWorld.Processor<HelloWorld.Iface>(helloWorldImpl) , new TCompactProtocol.Factory());
	}
}
2)配置applicationContext-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
	default-lazy-init="true">
	
	<description>thrift-servlet服务</description>
	
	 <!-- 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" />
	</bean>
    
    <bean  id="helloWorldImpl" class="cn.slimsmart.thrift.demo.helloworld.HelloWorldImpl"/>
    
    <!-- servlet -->  
    <bean name="/helloworldServlet.do" class="cn.slimsmart.thrift.demo.spring.servlet.HelloworldServlet"> 
    	<constructor-arg>
    		<ref bean="helloWorldImpl"/>
    	</constructor-arg>  
    </bean>	
</beans>
3)启动tomcat服务
4)客户端调用测试
HelloWorldServletTest.java
package cn.slimsmart.thrift.demo.spring.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 cn.slimsmart.thrift.demo.helloworld.HelloWorld;

public class HelloWorldServletTest {

	public static void main(String[] args) {
		String url = "http://127.0.0.1:8080/thrift-demo/helloworldServlet.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 = null;
		try {
			thc = new THttpClient(url, new DefaultHttpClient(cm, params));
			TProtocol loPFactory = new TCompactProtocol(thc);
			HelloWorld.Client client = new HelloWorld.Client(loPFactory);
			System.out.println(client.sayHello("Jack"));
		} catch (TTransportException e) {
			e.printStackTrace();
		} catch (TException e) {
			e.printStackTrace();
		}
	}

}

2、客服端

通过代理实现

1、服务端

服务端代理ThriftServletServerProxy.java
package cn.slimsmart.thrift.demo.spring.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.thrift.TException;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TIOStreamTransport;
import org.apache.thrift.transport.TTransport;
import org.springframework.util.StringUtils;

@SuppressWarnings("serial")
public class ThriftServletServerProxy extends HttpServlet {

	private final TProcessor processor;

	private final TProtocolFactory inProtocolFactory;

	private final TProtocolFactory outProtocolFactory;

	private final Collection<Map.Entry<String, String>> customHeaders;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public ThriftServletServerProxy(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 ThriftServletServerProxy(String serviceInterface,
			Object serviceImplObject) throws Exception {
		this(serviceInterface,null,serviceImplObject);

	}

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ThriftServletServerProxy(TProcessor processor,
			TProtocolFactory inProtocolFactory,
			TProtocolFactory outProtocolFactory) {
		super();
		this.processor = processor;
		this.inProtocolFactory = inProtocolFactory;
		this.outProtocolFactory = outProtocolFactory;
		this.customHeaders = new ArrayList<Map.Entry<String, String>>();
	}

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ThriftServletServerProxy(TProcessor processor,
			TProtocolFactory protocolFactory) {
		this(processor, protocolFactory, protocolFactory);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	@Override
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		TTransport inTransport = null;
		TTransport outTransport = null;

		try {
			response.setContentType("application/x-thrift");

			if (null != this.customHeaders) {
				for (Map.Entry<String, String> header : this.customHeaders) {
					response.addHeader(header.getKey(), header.getValue());
				}
			}
			InputStream in = request.getInputStream();
			OutputStream out = response.getOutputStream();

			TTransport transport = new TIOStreamTransport(in, out);
			inTransport = transport;
			outTransport = transport;

			TProtocol inProtocol = inProtocolFactory.getProtocol(inTransport);
			TProtocol outProtocol = outProtocolFactory
					.getProtocol(outTransport);

			processor.process(inProtocol, outProtocol);
			out.flush();
		} catch (TException te) {
			throw new ServletException(te);
		}
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	public void addCustomHeader(final String key, final String value) {
		this.customHeaders.add(new Map.Entry<String, String>() {
			public String getKey() {
				return key;
			}

			public String getValue() {
				return value;
			}

			public String setValue(String value) {
				return null;
			}
		});
	}

	public void setCustomHeaders(Collection<Map.Entry<String, String>> headers) {
		this.customHeaders.clear();
		this.customHeaders.addAll(headers);
	}

}
在applicationContext-servlet.xml添加如下配置:
<!-- servlet proxy -->  
    <bean name="/helloworldServletProxy.do" class="cn.slimsmart.thrift.demo.spring.servlet.ThriftServletServerProxy"> 
    	<constructor-arg index="0" value="cn.slimsmart.thrift.demo.helloworld.HelloWorld"/>
    	<constructor-arg>
    		<ref bean="helloWorldImpl"/>
    	</constructor-arg>  
    </bean>

启动tomcat服务。

2、客户端

1)客户端代理ThriftServletClientProxy.java
package cn.slimsmart.thrift.demo.spring.servlet;

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) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			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) {
			e.printStackTrace();
		}
		return schemeRegistry;
	}
}
2)spring配置applicationContext-servlet-client.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
	default-lazy-init="true">
	<description>thrift配置文件 </description>
	<bean id="thriftServletClientProxy" class="cn.slimsmart.thrift.demo.spring.servlet.ThriftServletClientProxy">
		<property name="servletUrl">
			<value>
				http://127.0.0.1:8080/thrift-demo/helloworldServletProxy.do
			</value>
		</property>
		<property name="serviceInterface" value="cn.slimsmart.thrift.demo.helloworld.HelloWorld">
		</property>
	</bean>
</beans>
3)测试启动类
HelloWorldServletProxyTest.java
package cn.slimsmart.thrift.demo.spring.servlet;

import org.apache.thrift.TException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.slimsmart.thrift.demo.helloworld.HelloWorld;

public class HelloWorldServletProxyTest {
	@SuppressWarnings("resource")
	public static void main(String[] args) throws TException {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/servlet/applicationContext-servlet-client.xml");
		ThriftServletClientProxy thriftServletClientProxy = (ThriftServletClientProxy)context.getBean(ThriftServletClientProxy.class);
		HelloWorld.Iface client = (HelloWorld.Iface)thriftServletClientProxy.getClient();
		System.out.println(client.sayHello("han meimei"));
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值