Thrift学习整理之环境搭建

项目中使用到了Thrift,一直没有整理这些知识碎片,主管在项目前期将spring与thrift集成,代码还是不错的,值得借鉴和思考,所以我就整理了一番,细节的地方还是不太明白,但也能运行起来,明白大题思路。首先thrift大家要了解这种技术:

Apache thrift 实现了跨语言的RPC框架,尽力的为各种语言实现相同的抽象的RPC客户端与服务器。这里我们讲的是基于Java的。Thrift拥有简介的4层接口抽象,每一层都可以独立的扩展增强或者替换,是另外一个优点。其中,Transport层提供了一个简单的网络读写抽象层,有阻塞和非阻塞的TOC与http实现。Protocol层定义了IDL中的数据结构和Transport层的传输数据格式之间的编码解码机制,传输格式有二进制压缩二进制,JSON等格式,IDL中的数据结构包括Message,struct,list,map,int,string,byte等。Processor层由编译器编程IDL文件生成,生成的代码会将传输层的数据解码为参数对象,然后调用由用户实现的函数,并将结果编码送回,服务端,Server层创建并管理上面的三层,同事提供线程的调度管理。此类的内容大家还可以通过百度等其他方式学习并了解。


这里,我介绍下本篇文章主要要做的是,基于spring搭建一个thrift环境。要完成的功能包括集成C3P0数据库,完成服务注册机制(通过配置文件注册thrift服务接口),完成客户端调用封装。首先,我们需要创建一个MAVEN工程,结构如下:



1、从数据源讲起,我们使用C3P0作为数据库连接池,spring对其有良好的封装,另外我们的持久层框架使用的是spring data jpa,本篇并不侧重于讲这些内容,所以直接截图配置文件,在dao的工程的reource目录下我们可以看到两个配置文件,分别是数据源和JPA的事务控制等:

dataSource.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:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">

	<context:property-placeholder order="1" location="file:/maizuo/config/server/dao/dao.properties" ignore-unresolvable="true" />

	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="driverClass" value="${dao.jdbc.driverClassName}" />
		<property name="jdbcUrl" value="${dao.jdbc.url}" />
		<property name="user" value="${dao.jdbc.username}" />
		<property name="password" value="${dao.jdbc.password}" />
		<property name="initialPoolSize" value="${dao.jdbc.initialPoolSize}" />
		<property name="minPoolSize" value="${dao.jdbc.minPoolSize}" />
		<property name="maxPoolSize" value="${dao.jdbc.maxPoolSize}" />
		<property name="maxIdleTime" value="${dao.jdbc.maxIdleTime}" />
		<property name="acquireIncrement" value="${dao.jdbc.acquireIncrement}" />
		<property name="idleConnectionTestPeriod" value="${dao.jdbc.idleConnectionTestPeriod}" />
		<property name="testConnectionOnCheckout" value="${dao.jdbc.testConnectionOnCheckout}" />
		<property name="testConnectionOnCheckin" value="${dao.jdbc.testConnectionOnCheckin}" />
		<property name="checkoutTimeout" value="${dao.jdbc.checkoutTimeout}" />
		<property name="preferredTestQuery">
			<value>SELECT NOW() FROM DUAL</value>
		</property>
	</bean>
</beans>

JPA.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:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
	http://www.springframework.org/schema/data/jpa
	http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">


	<!-- jpa配置  begin --><!-- JPA注解Bean后置处理器 -->
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
 	
	<!-- JPA实体管理器工厂 -->
	<bean id="mplusJpaEntityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="cn.mplus.thrift.dao" />
        <property name="persistenceUnitName" value="mplusPersistenceUnit" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="generateDdl" value="false" />
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
				<property name="showSql" value="true" />
			</bean>
		</property>
	</bean>

	<!-- 在服务启动时,将dao层接加入到容器管理中。CustomImpl为扩展实现类标识(如果有实现类的话) -->
	<jpa:repositories base-package="cn.mplus.thrift.dao"
                      query-lookup-strategy="create-if-not-found"
                      repository-impl-postfix="CustomImpl"
                      entity-manager-factory-ref="mplusJpaEntityManagerFactory"
                      transaction-manager-ref="mplusJpaTransactionManager"
                      factory-class="cn.mplus.thrift.spring.data.repository.CriteriaRepositoryFactoryBean">
	</jpa:repositories>
	
	<bean id="mplusJpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="mplusJpaEntityManagerFactory" />
	</bean>

    <!--<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"/>-->

    <tx:annotation-driven transaction-manager="mplusJpaTransactionManager" />
	<!-- jpa配置  end-->

</beans>

2、第二步,spring的配置文件,通过加载spring配置文件,使用注解完成bean管理,以及使用注解完成事务控制都比较简单,spring的配置文件我们放置在了server下:

<?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:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
  			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
  			
  			
  			
	<import resource="classpath:dao-datasource.xml"/>
	<import resource="classpath:dao-jpa.xml"/>
	<import resource="classpath:thrift-service.xml"/>
	
	
</beans>


从配置文件里,我们可以看到spring容器再完成数据源和jpa的加载后,又加载了thrift-service.xml 。这个xml配置了关于thrift的加载策略,也是我们讲解的重点地方。首先看一下thrift-service.xml的内容:


3、第三步、加载thrift-service.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:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
  			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
  			
  			
  	<context:component-scan base-package="cn.mplus.thrift" />
  	<bean id="testServer" class="cn.mplus.thrift.utils.register.RegisterServer" init-method="start">
		<property name="serviceImplClass">
			<map>
				<entry key="cn.mplus.thrift.core.test.TestService.Processor">
					<value>cn.mplus.thrift.server.test.impl.TestServiceImpl</value>
				</entry>
			</map>	
		</property>
		<property name="port" value="9501"/>
	</bean>
</beans>


配置文件也很简单,但做的事情可不少,首先使用component-scan完成bean加载。之后注册了一个名字为RegisterServer的类,这个类的初始化方法是start方法。在这个类里,它有一个serviceImplClass的map对象,这个map对象就是我们真正的对外提供的接口服务,通过spring对map的支持,我们将thrift生成的类的Processor和实现类放置在map中备用。这里你一定有一些奇怪,这个Processor是什么,这个类是thrift自动生成的,thrift需要使用此类作为参数来完成服务的创建,而TestServiceImpl是接口的实现类是我们自己写的。下面,我们先来看一下这个Processor的样子:


public static class Processor<I extends Iface> extends org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {
    private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName());
    public Processor(I iface) {
      super(iface, getProcessMap(new HashMap<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));
    }

    protected Processor(I iface, Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {
      super(iface, getProcessMap(processMap));
    }

    private static <I extends Iface> Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> getProcessMap(Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {
      processMap.put("testMethod", new testMethod());
      return processMap;
    }

    public static class testMethod<I extends Iface> extends org.apache.thrift.ProcessFunction<I, testMethod_args> {
      public testMethod() {
        super("testMethod");
      }

      public testMethod_args getEmptyArgsInstance() {
        return new testMethod_args();
      }

      protected boolean isOneway() {
        return false;
      }

      public testMethod_result getResult(I iface, testMethod_args args) throws org.apache.thrift.TException {
        testMethod_result result = new testMethod_result();
        result.success = iface.testMethod(args.params);
        return result;
      }
    }

  }
这个类是怎么生成的,这里我们不细说了,了解thrift的朋友都应该知道有thrift-0.9.1.exe这个工具,它可以根据我们定义的实体信息和服务信息来自动生成各自语言对应的接口实现,这些定义的内容如下:

namespace java mplus.thrift

/**
* 公共返回对象
*/
struct Response {
    1:i32 code;
    2:string msg;
    3:string data;
}


/**
* 任务中心
*/
service TestService{
	/**
	* 测试
	*/
    Response testMethod(
    	1:string params
    );
    
}

通过命令:

@echo off
thrift-0.9.1.exe -o d:\thrift --gen java test.thrift
@echo file generator ok, output to d:\thrift\java
pause;

就可以使用 thrift-0.9.1.exe这个工具来读取test.thrift生成对应的Java类,或者c#类等:



然后将这些类拷贝到我们的工程目录下,即thrift-core里就可以了。其中Resonse是我们定义的用于thrift的返回值,TestService就是我们的接口,我们要做的就是写一个实现类,实现TestService中的Iface接口(同步)或者其他异步接口就可以了,下面这个类就是我们的实现类:


import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.thrift.TException;
import org.springframework.stereotype.Controller;

import cn.mplus.thrift.core.test.TestService.Iface;
import cn.mplus.thrift.entity.base.Response;
import cn.mplus.thrift.server.test.operate.TestOperate;


/**
 * 测试接口
 * @author lvpeng
 *
 */
@Controller
public class TestServiceImpl implements Iface {

	@Resource
	private TestOperate testOperate;
	
	/**
	 * 测试接口
	 */
	@Override
	public Response testMethod(String params) throws TException {
		Response response = new Response();
		try {
			List<Long> ids = new ArrayList<Long>();
			ids.add(1L);ids.add(2L);
			boolean b = testOperate.updateTestList(ids);
			System.out.println("线程结果:"+b);
			response.setCode(200);
			response.setMsg("成功");
		} catch (Exception e) {
			e.printStackTrace();
			response.setCode(500);
			response.setMsg("异常");
		}
		return response;
	}

}


这样我们就讲明白了配置文件里提到的map 的概念了。

<map>
	<entry key="cn.mplus.thrift.core.test.TestService.Processor">
			<value>cn.mplus.thrift.server.test.impl.TestServiceImpl</value>
	</entry>
</map>	


4、下面我们侧重的看一下RegisterServer这个类的核心代码,类定义如下:

public class RegisterServer implements BeanFactoryAware {

	private static final Log log = LogFactory.getLog(RegisterServer.class);

	private Map<Class<? extends TProcessor>, Class<?>> serviceImplClass;

	private BeanFactory beanFactory;

	protected int port;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}

我们发现这个类首先实现了BeanFactoryAware,这个接口是干什么用的,了解Spring的同学应该知道,BeanFactory让你可以不依赖注入的方式,随意的读取IOC容器里面的对象。我们用它做什么呢, 我们要用它来获取TestServiceImpl在spring容器中的实例,其实我们完全可以使用反射自己获取这个对象的实例,但因为我们使用了spring 的容器,所以还是要用容器的对象,如果获取呢?通过调用Object serviceImpl = beanFactory.getBean(implClazz);方法即可,getBean方法接受的参数有很多,这里我们使用第一种方式:



获取了实现类的实例,然后再通过TProcessor processor = BeanUtils.instantiateClass(constructor, serviceImpl);通过反射找到服务对应的Processor 。得到了processor,processor通过register来暂时的注册服务,之后将processor放入线程池中。

TMultiplexedProcessor tmprocessor = new TMultiplexedProcessor();

tmprocessor.registerProcessor(implClazz.getSimpleName().replace("Impl", ""), processor);


这里,我们用到了一个Thrift的TMultiplexedProcessor类,百度了一下,

TMultiplexedProcessor,支持一个Server支持部署多个Service的情况,在Processor外面再加一层Map,消息名从“add”会变为“Caculator:add”,当然,这需要需要客户端发送时使用 TMultiplexedProtocol修饰原来的Protocol来实现。


完整的获取Processor的方法如下:

protected TMultiplexedProcessor getProcessor() {
		TMultiplexedProcessor tmprocessor = new TMultiplexedProcessor();
		for (Class<?> processorClazz : serviceImplClass.keySet()) {
			Class<?> implClazz = serviceImplClass.get(processorClazz);
			Constructor<TProcessor> constructor = (Constructor<TProcessor>) processorClazz.getConstructors()[0];
			Object serviceImpl = beanFactory.getBean(implClazz);
			TProcessor processor = BeanUtils.instantiateClass(constructor, serviceImpl);//通过反射找到服务对应的Processor
			tmprocessor.registerProcessor(implClazz.getSimpleName().replace("Impl", ""), processor);
		}
		return tmprocessor;
	}

通过获取Processor后,我们接下来核心的一步就是注册服务,这里我们使用了TThreadedSelectorServer,这是其中的一个实现,还有其他很多的实现, TThreadedSelectorServer属于half-sync/half-async模式。 使用此模式。客户端必须使用FrameTransport来发送数据以解决粘包的问题 。这里不细说,我也不太懂。

那如何注册服务,使用服务启动呢?看下面的核心代码:

/**
	 * 启动服务
	 * 	1、获取TProcessor 通过反射找到服务对应的Processor
	 *  2、使用TThreadedSelectorServer创建服务
	 */
	protected void startServerInternal() {
		try {
			TProcessor process = getProcessor();
			// 使用高密度二进制协议
			TBinaryProtocol.Factory proFactory = new TBinaryProtocol.Factory();
			TNonblockingServerTransport trans = new TNonblockingServerSocket(port);
			TThreadedSelectorServer.Args args = new TThreadedSelectorServer.Args(trans);
			args.maxReadBufferBytes = 16384000;
			args.transportFactory(new TFramedTransport.Factory());
			args.protocolFactory(proFactory);
			args.processor(process);
			args.selectorThreads(24);
			args.workerThreads(64);
			TServer server = new TThreadedSelectorServer(args);
			for (Class<?> clazz : serviceImplClass.values()) {
				log.info("[Server] >>> "
						+ clazz.getSimpleName().replace("Impl", "")
						+ " is starting on port " + port + " protocal = "
						+ proFactory.getClass());
			}
			server.serve();

		} catch (TTransportException e) {
			log.error("Start server error!", e);
		}
	}

如此,我们的服务就启动了,但这里还需要注意一个问题就是我们是依赖spring容器注册的thrift服务,如果我们在主线程做这个工程,就会导致剩余的加载工作会停止了,所以避免这种停止,我们需要在主线程里开启一个子线程来完成服务的注册和启动工作,所以在这个类的start方法里,我们这么写:

/**
	 * 另外开启一个线程的原因:防止spring线程卡死
	 */
	public void start() {
		new Thread() {
			public void run() {
				startServerInternal();
			}
		}.start();
	}

这样我们的RegisterServer这个类的逻辑我们就讲清楚了,也就完成了服务的注册,接下来我们要做的就是使用ClasspathXml...这种方式来读取spring的配置文件创建application就可以了:

public class App {
	
	private static Logger logger = LoggerFactory.getLogger(App.class);
	static {
		try {
			Log4jConfigurer.initLogging("classpath:thrift-log4j.properties", 5000);
		} catch (Exception e) {
			logger.error("favorite.server.App", e);
		}
	}
	
	private static ApplicationContext factory = null;
	public static ApplicationContext factory() {
		return factory;
	}
	public static void main(String[] args) throws Exception {
		String springConfig = "classpath:thrift-server.xml";
		factory = new ClassPathXmlApplicationContext(springConfig);
	}
}

5、客户端封装

为什么我们要对客户端封装呢,原则上可以不封装,但封装的原因是因为有一些重复的代码需要我们每次都编写,例如开启一个连接释放这个链接等,所以我们有必要将此类公用的逻辑进行封装。客户端调用服务器,其实是使用了Thrift提供的client。这个client也是由thrift.exe生成:

public static class Client extends org.apache.thrift.TServiceClient implements Iface {
    public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
      public Factory() {}
      public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
        return new Client(prot);
      }
      public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
        return new Client(iprot, oprot);
      }
    }

    public Client(org.apache.thrift.protocol.TProtocol prot)
    {
      super(prot, prot);
    }

    public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
      super(iprot, oprot);
    }

    public Response testMethod(String params) throws org.apache.thrift.TException
    {
      send_testMethod(params);
      return recv_testMethod();
    }

    public void send_testMethod(String params) throws org.apache.thrift.TException
    {
      testMethod_args args = new testMethod_args();
      args.setParams(params);
      sendBase("testMethod", args);
    }

    public Response recv_testMethod() throws org.apache.thrift.TException
    {
      testMethod_result result = new testMethod_result();
      receiveBase(result, "testMethod");
      if (result.isSetSuccess()) {
        return result.success;
      }
      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "testMethod failed: unknown result");
    }

  }

而我们的工作其实就是来构造Client的实现,构造client的实现,要通过调用其构造方法,通过观察我们发现构造方法里需要我们传入org.apache.thrift.protocol.TProtocal 对象。 所以我们第一步就是来看这个对象如何构造,刚才我们提到了服务端使用的是 TMultiplexedProcessor,所以客户端也需要使用对应的Protocol来处理才可以,所以客户端需要包装TMultiplexedProtocol来修改原来的Protocol,原来的protocal是:TBinaryProtocol,意为高密度二进制协议。


得到了TMultiplexedProcessor,也就等同于得到了Client的构造方法的参数,此时我们再使用反射机制newInstance()来构造client对象就可以了。得到了client对象,就可以调用它的目标方法来完成调用了。当然一切还没有那么简单,首先我们来看TBinaryProtocol如何构造:TProtocol protocol = new TBinaryProtocol(transport); 通过构造方法传入Transport就可以构造,transport是什么?这里我们还是要回顾一下,上面讲过的:TThreadedSelectorServer属于half-sync/half-async模式。使用此模式。客户端必须使用FrameTransport来发送数据以解决粘包的问题,所以我们需要用TrameTransport来包装:

TFramedTransport transport =
				new TFramedTransport(new TSocket(ip, port,timeout));

		transport.open();

这里我们使用TSocket这个类,TSocket: TSocket使用经典的JDK Blocking IO的Transport实现。1K的BufferedStream, TCP配置项:KeepAlive=true,TCPNoDelay=true,SoLinger=false,SocketTimeout与ConnectionTimeout可配。


这样我们再总结下,首先构造TramedTransport,使用它构造TBinaryProtocol,再构造TMultiplexedProcessor,现在都构造OK了,接下来我们就要使用反射来构造我们的Client对象了:核心代码如下:

Class<?> clientClass = Class.forName(serviceName + "$Client");
		Class<?>[] cl = new Class[]{TProtocol.class};
		Constructor<?> con = clientClass.getDeclaredConstructor(cl);  
	    Object t = con.newInstance(tmprotocol); 
第一行代码可能很少人能看懂为什么,原因是因为Client属于内部类,它是在TestService这个类里面定义的一个静态类,如果我们想得到它,首先我们得知道它属于哪个类?肯定是属于由Thrift.exe生成的类里。那我们如何得到这个类的名字呢?很简单Class.getName();就可以,我们可以写一个通用的方法,让用户将这个类的名字传过来。之后我们使用上述的代码完成client实例的调用,然后调用目标方法就可以。但很显然,这个过程是比较通用的,我们只需要知道用户想得到那个类的内部Client,我们就可以动态的获取Client代理对象,并不需要每一个Client都写一遍类似的代码,所以这个过程我们完全可以使用反射和动态代理完成。这段代码有点复杂,首先你要看明白我上面写的,接下来的你才有可能看懂:


(1)定义一个方法,传入你想实例化的Client的外层类名:

/**
	 * 获取service接口代理 【与实际代码比有简化】
	 * @param serviceClass
	 * @return
	 */
	public static <T> T getService2(Class<?> serviceClass){
		ProxyFactory<T> factory = new ProxyFactory<T>();
		T obj = null;
		try {
			obj = factory.createProxy(serviceClass);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}

我们通过ProxyFactory来构造我们的目标类的代理对象,使用的是JDK1.5的动态代理机制,了解代理机制的应该知道,我们需要知道这个client的接口集合,以及classloader,还有一个handler,下面是createProxy的方法


(2)ProxyFactory类:

public class ProxyFactory<T> {
	public T createProxy(Class<?> service)
			throws Exception {
		Class<?> iFaceClass = Class.forName(service.getName() + "$Iface");
		InvocationHandler handler = new ThriftProxy(service.getName());
		Class<?> clientClass = Class.forName(service.getName() + "$Client");
		Object proxy = Proxy.newProxyInstance(iFaceClass.getClassLoader(),
				clientClass.getInterfaces(), handler);
		return (T)proxy;
	}
}

<1>获取接口以此得到classLoader <2>获取Client字节码得到接口数组 <3>构造Handler 在handler完成 TMultiplexedProcessor的创建,创建真正的Client实例对象。调用目标方法。这里有一个比较拐弯的地方就是,虽然我们得到了Client的代理对象,但这个代理对象并不能真正成立我们的目标方法,我们需要在InvocationHandler里处理我们真正的调用逻辑,所以这块逻辑被单独封装在了ThriftProxy里,也是最为核心的代码之一


(3)ThriftProxy类;

public class ThriftProxy implements InvocationHandler {
	
	public static final int TIMEOUT = 60000;
	private String serviceName;
	public ThriftProxy(String serviceName){
		this.serviceName = serviceName;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object[] address = ConnectManager.getAddressMap(serviceName);
		TTransport transport = 
				ConnectManager.getConnect((String)address[0],(Integer)address[1],TIMEOUT);
		try{
			Object client = createClient(transport,serviceName);
			Method clientMethod = client.getClass().getMethod(method.getName(), method.getParameterTypes());
			return clientMethod.invoke(client, args);
		}finally{
			ConnectManager.close(transport);
		}
	}
	
	/**
	 * Object serviceName : 服务对象名称
	 * @return 服务对象的Client
	 */
	private Object createClient(TTransport transport,String serviceName) throws Exception{
		Object client = ClientManager.getClient(serviceName, transport);
		return client;
	}
	
}

在createClient方法里,调用ClientManager.getClient获取真实的Client代理对象:


(4)ClientManger类:

public class ClientManager {

	/**
	 * 获取服务客户端
	 * @param serviceName
	 * @param transport
	 * @return
	 * @throws ClassNotFoundException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	public static Object getClient(String serviceName,TTransport transport) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		// 协议要和服务端一致
		TProtocol protocol = new TBinaryProtocol(transport);
		String simpleName = serviceName.substring(serviceName.lastIndexOf(".") + 1, serviceName.length());
		TMultiplexedProtocol tmprotocol = 
				new TMultiplexedProtocol(protocol, simpleName);
		Class<?> clientClass = Class.forName(serviceName + "$Client");
		Class<?>[] cl = new Class[]{TProtocol.class};
		Constructor<?> con = clientClass.getDeclaredConstructor(cl);  
	    Object t = con.newInstance(tmprotocol); 
	    
	    return t;
	}
	
}

总结下,首先我们对外提供了一个getService接口用以获取客户端对象。在getService里,我们实际上是使用了ProxyFactory的动态代理机制获取Client的实例对象。另外我们在Handler里(实际的方法处理者)完成Client实例的创建以及目标方法的执行,创建Client实例我们将核心的代码封装在了ThriftProxy里和ClientManger里,尽管我看到了源码,也不知道自己讲解的对不对呵呵。


6、如此,我们就算完成了客户端的获取封装。服务端也讲过了,使用了RegisterServer来注册。这样就都OK了,下面我们就按照正常的流程完成一个DEMO演示就可以了,首先定义我们的结构体和接口,然后通过thrift.exe生成对应的类分别放入core和entity里:



第二步,写我们的实现类,放置在service工程下

第三部,通过依赖注入获取层对象,依次调接口完成数据库操作,事务通过注解控制。

客户端调用getService方法获取client,直接调目标方法:


public class TestServiceClient {
	/**
	 * getTicketFaceService
	 * @return
	 */
	public TestService.Iface getTestService(){
		return ServiceFactory.getService(TestService.class);
	}
}

总结:关于thrift的封装就到这里了,基本上算是我自己的一个工作小结,通过这种方式帮助自己了解的自己的项目的封装和运行机制,也学到了很多知识。由于项目还属于保密阶段不适合对外公布源代码,所以代码就先不公开,有特别想要的再单独联系我吧,如果我领导没意见可以给你。接下来我可能会整理关于quartz的相关代码。


很多同学看不到TestService这个类的代码会感到很困惑,原因是因为这个类是由Thrift.exe生成的,且代码很长,我就没贴,最后贴一下。


/**
 * Autogenerated by Thrift Compiler (0.9.1)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
package cn.mplus.thrift.core.test;

import org.apache.thrift.scheme.IScheme;
import org.apache.thrift.scheme.SchemeFactory;
import org.apache.thrift.scheme.StandardScheme;

import org.apache.thrift.scheme.TupleScheme;
import org.apache.thrift.protocol.TTupleProtocol;
import org.apache.thrift.protocol.TProtocolException;
import org.apache.thrift.EncodingUtils;
import org.apache.thrift.TException;
import org.apache.thrift.async.AsyncMethodCallback;
import org.apache.thrift.server.AbstractNonblockingServer.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.Set;
import java.util.HashSet;
import java.util.EnumSet;
import java.util.Collections;
import java.util.BitSet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.mplus.thrift.entity.base.Response;

public class TestService {

  /**
   * 任务中心
   */
  public interface Iface {

    /**
     * 测试
     * 
     * @param params
     */
    public Response testMethod(String params) throws org.apache.thrift.TException;

  }

  public interface AsyncIface {

    public void testMethod(String params, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;

  }

  public static class Client extends org.apache.thrift.TServiceClient implements Iface {
    public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
      public Factory() {}
      public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
        return new Client(prot);
      }
      public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
        return new Client(iprot, oprot);
      }
    }

    public Client(org.apache.thrift.protocol.TProtocol prot)
    {
      super(prot, prot);
    }

    public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
      super(iprot, oprot);
    }

    public Response testMethod(String params) throws org.apache.thrift.TException
    {
      send_testMethod(params);
      return recv_testMethod();
    }

    public void send_testMethod(String params) throws org.apache.thrift.TException
    {
      testMethod_args args = new testMethod_args();
      args.setParams(params);
      sendBase("testMethod", args);
    }

    public Response recv_testMethod() throws org.apache.thrift.TException
    {
      testMethod_result result = new testMethod_result();
      receiveBase(result, "testMethod");
      if (result.isSetSuccess()) {
        return result.success;
      }
      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "testMethod failed: unknown result");
    }

  }
  public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {
    public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
      private org.apache.thrift.async.TAsyncClientManager clientManager;
      private org.apache.thrift.protocol.TProtocolFactory protocolFactory;
      public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {
        this.clientManager = clientManager;
        this.protocolFactory = protocolFactory;
      }
      public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {
        return new AsyncClient(protocolFactory, clientManager, transport);
      }
    }

    public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {
      super(protocolFactory, clientManager, transport);
    }

    public void testMethod(String params, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
      checkReady();
      testMethod_call method_call = new testMethod_call(params, resultHandler, this, ___protocolFactory, ___transport);
      this.___currentMethod = method_call;
      ___manager.call(method_call);
    }

    public static class testMethod_call extends org.apache.thrift.async.TAsyncMethodCall {
      private String params;
      public testMethod_call(String params, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
        super(client, protocolFactory, transport, resultHandler, false);
        this.params = params;
      }

      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("testMethod", org.apache.thrift.protocol.TMessageType.CALL, 0));
        testMethod_args args = new testMethod_args();
        args.setParams(params);
        args.write(prot);
        prot.writeMessageEnd();
      }

      public Response getResult() throws org.apache.thrift.TException {
        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
          throw new IllegalStateException("Method call not finished!");
        }
        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
        return (new Client(prot)).recv_testMethod();
      }
    }

  }

  public static class Processor<I extends Iface> extends org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {
    private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName());
    public Processor(I iface) {
      super(iface, getProcessMap(new HashMap<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));
    }

    protected Processor(I iface, Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {
      super(iface, getProcessMap(processMap));
    }

    private static <I extends Iface> Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> getProcessMap(Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {
      processMap.put("testMethod", new testMethod());
      return processMap;
    }

    public static class testMethod<I extends Iface> extends org.apache.thrift.ProcessFunction<I, testMethod_args> {
      public testMethod() {
        super("testMethod");
      }

      public testMethod_args getEmptyArgsInstance() {
        return new testMethod_args();
      }

      protected boolean isOneway() {
        return false;
      }

      public testMethod_result getResult(I iface, testMethod_args args) throws org.apache.thrift.TException {
        testMethod_result result = new testMethod_result();
        result.success = iface.testMethod(args.params);
        return result;
      }
    }

  }

  public static class AsyncProcessor<I extends AsyncIface> extends org.apache.thrift.TBaseAsyncProcessor<I> {
    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncProcessor.class.getName());
    public AsyncProcessor(I iface) {
      super(iface, getProcessMap(new HashMap<String, org.apache.thrift.AsyncProcessFunction<I, ? extends org.apache.thrift.TBase, ?>>()));
    }

    protected AsyncProcessor(I iface, Map<String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase, ?>> processMap) {
      super(iface, getProcessMap(processMap));
    }

    private static <I extends AsyncIface> Map<String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase,?>> getProcessMap(Map<String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase, ?>> processMap) {
      processMap.put("testMethod", new testMethod());
      return processMap;
    }

    public static class testMethod<I extends AsyncIface> extends org.apache.thrift.AsyncProcessFunction<I, testMethod_args, Response> {
      public testMethod() {
        super("testMethod");
      }

      public testMethod_args getEmptyArgsInstance() {
        return new testMethod_args();
      }

      public AsyncMethodCallback<Response> getResultHandler(final AsyncFrameBuffer fb, final int seqid) {
        final org.apache.thrift.AsyncProcessFunction fcall = this;
        return new AsyncMethodCallback<Response>() { 
          public void onComplete(Response o) {
            testMethod_result result = new testMethod_result();
            result.success = o;
            try {
              fcall.sendResponse(fb,result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);
              return;
            } catch (Exception e) {
              LOGGER.error("Exception writing to internal frame buffer", e);
            }
            fb.close();
          }
          public void onError(Exception e) {
            byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;
            org.apache.thrift.TBase msg;
            testMethod_result result = new testMethod_result();
            {
              msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;
              msg = (org.apache.thrift.TBase)new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage());
            }
            try {
              fcall.sendResponse(fb,msg,msgType,seqid);
              return;
            } catch (Exception ex) {
              LOGGER.error("Exception writing to internal frame buffer", ex);
            }
            fb.close();
          }
        };
      }

      protected boolean isOneway() {
        return false;
      }

      public void start(I iface, testMethod_args args, org.apache.thrift.async.AsyncMethodCallback<Response> resultHandler) throws TException {
        iface.testMethod(args.params,resultHandler);
      }
    }

  }

  public static class testMethod_args implements org.apache.thrift.TBase<testMethod_args, testMethod_args._Fields>, java.io.Serializable, Cloneable, Comparable<testMethod_args>   {
    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("testMethod_args");

    private static final org.apache.thrift.protocol.TField PARAMS_FIELD_DESC = new org.apache.thrift.protocol.TField("params", org.apache.thrift.protocol.TType.STRING, (short)1);

    private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
    static {
      schemes.put(StandardScheme.class, new testMethod_argsStandardSchemeFactory());
      schemes.put(TupleScheme.class, new testMethod_argsTupleSchemeFactory());
    }

    public String params; // required

    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
      PARAMS((short)1, "params");

      private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();

      static {
        for (_Fields field : EnumSet.allOf(_Fields.class)) {
          byName.put(field.getFieldName(), field);
        }
      }

      /**
       * Find the _Fields constant that matches fieldId, or null if its not found.
       */
      public static _Fields findByThriftId(int fieldId) {
        switch(fieldId) {
          case 1: // PARAMS
            return PARAMS;
          default:
            return null;
        }
      }

      /**
       * Find the _Fields constant that matches fieldId, throwing an exception
       * if it is not found.
       */
      public static _Fields findByThriftIdOrThrow(int fieldId) {
        _Fields fields = findByThriftId(fieldId);
        if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
        return fields;
      }

      /**
       * Find the _Fields constant that matches name, or null if its not found.
       */
      public static _Fields findByName(String name) {
        return byName.get(name);
      }

      private final short _thriftId;
      private final String _fieldName;

      _Fields(short thriftId, String fieldName) {
        _thriftId = thriftId;
        _fieldName = fieldName;
      }

      public short getThriftFieldId() {
        return _thriftId;
      }

      public String getFieldName() {
        return _fieldName;
      }
    }

    // isset id assignments
    public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
    static {
      Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
      tmpMap.put(_Fields.PARAMS, new org.apache.thrift.meta_data.FieldMetaData("params", org.apache.thrift.TFieldRequirementType.DEFAULT, 
          new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
      metaDataMap = Collections.unmodifiableMap(tmpMap);
      org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(testMethod_args.class, metaDataMap);
    }

    public testMethod_args() {
    }

    public testMethod_args(
      String params)
    {
      this();
      this.params = params;
    }

    /**
     * Performs a deep copy on <i>other</i>.
     */
    public testMethod_args(testMethod_args other) {
      if (other.isSetParams()) {
        this.params = other.params;
      }
    }

    public testMethod_args deepCopy() {
      return new testMethod_args(this);
    }

    @Override
    public void clear() {
      this.params = null;
    }

    public String getParams() {
      return this.params;
    }

    public testMethod_args setParams(String params) {
      this.params = params;
      return this;
    }

    public void unsetParams() {
      this.params = null;
    }

    /** Returns true if field params is set (has been assigned a value) and false otherwise */
    public boolean isSetParams() {
      return this.params != null;
    }

    public void setParamsIsSet(boolean value) {
      if (!value) {
        this.params = null;
      }
    }

    public void setFieldValue(_Fields field, Object value) {
      switch (field) {
      case PARAMS:
        if (value == null) {
          unsetParams();
        } else {
          setParams((String)value);
        }
        break;

      }
    }

    public Object getFieldValue(_Fields field) {
      switch (field) {
      case PARAMS:
        return getParams();

      }
      throw new IllegalStateException();
    }

    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
    public boolean isSet(_Fields field) {
      if (field == null) {
        throw new IllegalArgumentException();
      }

      switch (field) {
      case PARAMS:
        return isSetParams();
      }
      throw new IllegalStateException();
    }

    @Override
    public boolean equals(Object that) {
      if (that == null)
        return false;
      if (that instanceof testMethod_args)
        return this.equals((testMethod_args)that);
      return false;
    }

    public boolean equals(testMethod_args that) {
      if (that == null)
        return false;

      boolean this_present_params = true && this.isSetParams();
      boolean that_present_params = true && that.isSetParams();
      if (this_present_params || that_present_params) {
        if (!(this_present_params && that_present_params))
          return false;
        if (!this.params.equals(that.params))
          return false;
      }

      return true;
    }

    @Override
    public int hashCode() {
      return 0;
    }

    @Override
    public int compareTo(testMethod_args other) {
      if (!getClass().equals(other.getClass())) {
        return getClass().getName().compareTo(other.getClass().getName());
      }

      int lastComparison = 0;

      lastComparison = Boolean.valueOf(isSetParams()).compareTo(other.isSetParams());
      if (lastComparison != 0) {
        return lastComparison;
      }
      if (isSetParams()) {
        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.params, other.params);
        if (lastComparison != 0) {
          return lastComparison;
        }
      }
      return 0;
    }

    public _Fields fieldForId(int fieldId) {
      return _Fields.findByThriftId(fieldId);
    }

    public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
      schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
    }

    public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
      schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
    }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder("testMethod_args(");
      boolean first = true;

      sb.append("params:");
      if (this.params == null) {
        sb.append("null");
      } else {
        sb.append(this.params);
      }
      first = false;
      sb.append(")");
      return sb.toString();
    }

    public void validate() throws org.apache.thrift.TException {
      // check for required fields
      // check for sub-struct validity
    }

    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
      try {
        write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
      } catch (org.apache.thrift.TException te) {
        throw new java.io.IOException(te);
      }
    }

    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
      try {
        read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
      } catch (org.apache.thrift.TException te) {
        throw new java.io.IOException(te);
      }
    }

    private static class testMethod_argsStandardSchemeFactory implements SchemeFactory {
      public testMethod_argsStandardScheme getScheme() {
        return new testMethod_argsStandardScheme();
      }
    }

    private static class testMethod_argsStandardScheme extends StandardScheme<testMethod_args> {

      public void read(org.apache.thrift.protocol.TProtocol iprot, testMethod_args struct) throws org.apache.thrift.TException {
        org.apache.thrift.protocol.TField schemeField;
        iprot.readStructBegin();
        while (true)
        {
          schemeField = iprot.readFieldBegin();
          if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
            break;
          }
          switch (schemeField.id) {
            case 1: // PARAMS
              if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
                struct.params = iprot.readString();
                struct.setParamsIsSet(true);
              } else { 
                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
              }
              break;
            default:
              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
          }
          iprot.readFieldEnd();
        }
        iprot.readStructEnd();

        // check for required fields of primitive type, which can't be checked in the validate method
        struct.validate();
      }

      public void write(org.apache.thrift.protocol.TProtocol oprot, testMethod_args struct) throws org.apache.thrift.TException {
        struct.validate();

        oprot.writeStructBegin(STRUCT_DESC);
        if (struct.params != null) {
          oprot.writeFieldBegin(PARAMS_FIELD_DESC);
          oprot.writeString(struct.params);
          oprot.writeFieldEnd();
        }
        oprot.writeFieldStop();
        oprot.writeStructEnd();
      }

    }

    private static class testMethod_argsTupleSchemeFactory implements SchemeFactory {
      public testMethod_argsTupleScheme getScheme() {
        return new testMethod_argsTupleScheme();
      }
    }

    private static class testMethod_argsTupleScheme extends TupleScheme<testMethod_args> {

      @Override
      public void write(org.apache.thrift.protocol.TProtocol prot, testMethod_args struct) throws org.apache.thrift.TException {
        TTupleProtocol oprot = (TTupleProtocol) prot;
        BitSet optionals = new BitSet();
        if (struct.isSetParams()) {
          optionals.set(0);
        }
        oprot.writeBitSet(optionals, 1);
        if (struct.isSetParams()) {
          oprot.writeString(struct.params);
        }
      }

      @Override
      public void read(org.apache.thrift.protocol.TProtocol prot, testMethod_args struct) throws org.apache.thrift.TException {
        TTupleProtocol iprot = (TTupleProtocol) prot;
        BitSet incoming = iprot.readBitSet(1);
        if (incoming.get(0)) {
          struct.params = iprot.readString();
          struct.setParamsIsSet(true);
        }
      }
    }

  }

  public static class testMethod_result implements org.apache.thrift.TBase<testMethod_result, testMethod_result._Fields>, java.io.Serializable, Cloneable, Comparable<testMethod_result>   {
    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("testMethod_result");

    private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRUCT, (short)0);

    private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
    static {
      schemes.put(StandardScheme.class, new testMethod_resultStandardSchemeFactory());
      schemes.put(TupleScheme.class, new testMethod_resultTupleSchemeFactory());
    }

    public Response success; // required

    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
      SUCCESS((short)0, "success");

      private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();

      static {
        for (_Fields field : EnumSet.allOf(_Fields.class)) {
          byName.put(field.getFieldName(), field);
        }
      }

      /**
       * Find the _Fields constant that matches fieldId, or null if its not found.
       */
      public static _Fields findByThriftId(int fieldId) {
        switch(fieldId) {
          case 0: // SUCCESS
            return SUCCESS;
          default:
            return null;
        }
      }

      /**
       * Find the _Fields constant that matches fieldId, throwing an exception
       * if it is not found.
       */
      public static _Fields findByThriftIdOrThrow(int fieldId) {
        _Fields fields = findByThriftId(fieldId);
        if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
        return fields;
      }

      /**
       * Find the _Fields constant that matches name, or null if its not found.
       */
      public static _Fields findByName(String name) {
        return byName.get(name);
      }

      private final short _thriftId;
      private final String _fieldName;

      _Fields(short thriftId, String fieldName) {
        _thriftId = thriftId;
        _fieldName = fieldName;
      }

      public short getThriftFieldId() {
        return _thriftId;
      }

      public String getFieldName() {
        return _fieldName;
      }
    }

    // isset id assignments
    public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
    static {
      Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
      tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, 
          new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Response.class)));
      metaDataMap = Collections.unmodifiableMap(tmpMap);
      org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(testMethod_result.class, metaDataMap);
    }

    public testMethod_result() {
    }

    public testMethod_result(
      Response success)
    {
      this();
      this.success = success;
    }

    /**
     * Performs a deep copy on <i>other</i>.
     */
    public testMethod_result(testMethod_result other) {
      if (other.isSetSuccess()) {
        this.success = new Response(other.success);
      }
    }

    public testMethod_result deepCopy() {
      return new testMethod_result(this);
    }

    @Override
    public void clear() {
      this.success = null;
    }

    public Response getSuccess() {
      return this.success;
    }

    public testMethod_result setSuccess(Response success) {
      this.success = success;
      return this;
    }

    public void unsetSuccess() {
      this.success = null;
    }

    /** Returns true if field success is set (has been assigned a value) and false otherwise */
    public boolean isSetSuccess() {
      return this.success != null;
    }

    public void setSuccessIsSet(boolean value) {
      if (!value) {
        this.success = null;
      }
    }

    public void setFieldValue(_Fields field, Object value) {
      switch (field) {
      case SUCCESS:
        if (value == null) {
          unsetSuccess();
        } else {
          setSuccess((Response)value);
        }
        break;

      }
    }

    public Object getFieldValue(_Fields field) {
      switch (field) {
      case SUCCESS:
        return getSuccess();

      }
      throw new IllegalStateException();
    }

    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
    public boolean isSet(_Fields field) {
      if (field == null) {
        throw new IllegalArgumentException();
      }

      switch (field) {
      case SUCCESS:
        return isSetSuccess();
      }
      throw new IllegalStateException();
    }

    @Override
    public boolean equals(Object that) {
      if (that == null)
        return false;
      if (that instanceof testMethod_result)
        return this.equals((testMethod_result)that);
      return false;
    }

    public boolean equals(testMethod_result that) {
      if (that == null)
        return false;

      boolean this_present_success = true && this.isSetSuccess();
      boolean that_present_success = true && that.isSetSuccess();
      if (this_present_success || that_present_success) {
        if (!(this_present_success && that_present_success))
          return false;
        if (!this.success.equals(that.success))
          return false;
      }

      return true;
    }

    @Override
    public int hashCode() {
      return 0;
    }

    @Override
    public int compareTo(testMethod_result other) {
      if (!getClass().equals(other.getClass())) {
        return getClass().getName().compareTo(other.getClass().getName());
      }

      int lastComparison = 0;

      lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(other.isSetSuccess());
      if (lastComparison != 0) {
        return lastComparison;
      }
      if (isSetSuccess()) {
        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success);
        if (lastComparison != 0) {
          return lastComparison;
        }
      }
      return 0;
    }

    public _Fields fieldForId(int fieldId) {
      return _Fields.findByThriftId(fieldId);
    }

    public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
      schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
    }

    public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
      schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
      }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder("testMethod_result(");
      boolean first = true;

      sb.append("success:");
      if (this.success == null) {
        sb.append("null");
      } else {
        sb.append(this.success);
      }
      first = false;
      sb.append(")");
      return sb.toString();
    }

    public void validate() throws org.apache.thrift.TException {
      // check for required fields
      // check for sub-struct validity
      if (success != null) {
        success.validate();
      }
    }

    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
      try {
        write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
      } catch (org.apache.thrift.TException te) {
        throw new java.io.IOException(te);
      }
    }

    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
      try {
        read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
      } catch (org.apache.thrift.TException te) {
        throw new java.io.IOException(te);
      }
    }

    private static class testMethod_resultStandardSchemeFactory implements SchemeFactory {
      public testMethod_resultStandardScheme getScheme() {
        return new testMethod_resultStandardScheme();
      }
    }

    private static class testMethod_resultStandardScheme extends StandardScheme<testMethod_result> {

      public void read(org.apache.thrift.protocol.TProtocol iprot, testMethod_result struct) throws org.apache.thrift.TException {
        org.apache.thrift.protocol.TField schemeField;
        iprot.readStructBegin();
        while (true)
        {
          schemeField = iprot.readFieldBegin();
          if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
            break;
          }
          switch (schemeField.id) {
            case 0: // SUCCESS
              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
                struct.success = new Response();
                struct.success.read(iprot);
                struct.setSuccessIsSet(true);
              } else { 
                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
              }
              break;
            default:
              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
          }
          iprot.readFieldEnd();
        }
        iprot.readStructEnd();

        // check for required fields of primitive type, which can't be checked in the validate method
        struct.validate();
      }

      public void write(org.apache.thrift.protocol.TProtocol oprot, testMethod_result struct) throws org.apache.thrift.TException {
        struct.validate();

        oprot.writeStructBegin(STRUCT_DESC);
        if (struct.success != null) {
          oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
          struct.success.write(oprot);
          oprot.writeFieldEnd();
        }
        oprot.writeFieldStop();
        oprot.writeStructEnd();
      }

    }

    private static class testMethod_resultTupleSchemeFactory implements SchemeFactory {
      public testMethod_resultTupleScheme getScheme() {
        return new testMethod_resultTupleScheme();
      }
    }

    private static class testMethod_resultTupleScheme extends TupleScheme<testMethod_result> {

      @Override
      public void write(org.apache.thrift.protocol.TProtocol prot, testMethod_result struct) throws org.apache.thrift.TException {
        TTupleProtocol oprot = (TTupleProtocol) prot;
        BitSet optionals = new BitSet();
        if (struct.isSetSuccess()) {
          optionals.set(0);
        }
        oprot.writeBitSet(optionals, 1);
        if (struct.isSetSuccess()) {
          struct.success.write(oprot);
        }
      }

      @Override
      public void read(org.apache.thrift.protocol.TProtocol prot, testMethod_result struct) throws org.apache.thrift.TException {
        TTupleProtocol iprot = (TTupleProtocol) prot;
        BitSet incoming = iprot.readBitSet(1);
        if (incoming.get(0)) {
          struct.success = new Response();
          struct.success.read(iprot);
          struct.setSuccessIsSet(true);
        }
      }
    }

  }

}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值