thrift中required和optional的用处

使用技术:thrift的rpc服务

问题提出:在java和.net交互的时候,默认值导致数据修改问题。

基本数据类型在服务端传输前没有设置isset值,传输到客户端还是出现isset=true的现象。

 

解决方案:将所有非必须变量添加修饰符optional,这样thrift在序列化的时候发现修饰符为optional并且

isset=false的值时,就会忽略。

 

下面的问题测试demo:

idl定义文件(BorrowPerson.thrift):
namespace java littlehow.thrift.demo.optional
#person结构,其中身高是可选的
struct Person
{
  1:i64 id,
  2:string name,
  3:i32 age,
  4:optional i16 height,
  5:optional Work work
}

#工作信息,工作年限是可选的,工资有可选参数,并且有默认值
struct Work
{
  1:i32 workid,
  2:optional i16 workage,
  3:optional string salary = "2500.00" 
}

service BorrowPerson
{
  Person borrowPerson(1:i64 personId)
} 
 
//使用命令thrift.exe -gen java BorrowPerson.thrift生成文件
文件主要结构如下:
person主体如下:
 
public long id; // required
public String name; // required
public int age; // required
public short height; // optional
public Work work; // optional

 

 
work主体如下:
 
public int workid; // required
public short workage; // optional
public String salary; // optional

 

 
borrowperson主体如下
 
public static class Client extends org.apache.thrift.TServiceClient implements Iface {
  public static class Factory implements org.apache.thrift.TServiceClientFactory {
    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 Person borrowPerson(long personId) throws TException
  {
    send_borrowPerson(personId);
    return recv_borrowPerson();
  }

  public void send_borrowPerson(long personId) throws TException
  {
    borrowPerson_args args = new borrowPerson_args();
    args.setPersonId(personId);
    sendBase("borrowPerson", args);
  }

  public Person recv_borrowPerson() throws TException
  {
    borrowPerson_result result = new borrowPerson_result();
    receiveBase(result, "borrowPerson");
    if (result.isSetSuccess()) {
      return result.success;
    }
    throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "borrowPerson failed: unknown result");
  }

}

 

 
实际业务类:
 
package littlehow.thrift.demo.call.optional;

import littlehow.thrift.demo.optional.BorrowPerson;
import littlehow.thrift.demo.optional.Person;
import littlehow.thrift.demo.optional.Work;
import org.apache.thrift.TException;

import java.util.HashMap;
import java.util.Map;

/**
 * BorrowPerson
 *
 * @author littlehow
 * @time 2016-06-27 10:18
 */
public class BorrowPersonImpl implements BorrowPerson.Iface{
    private static Map persons = new HashMap();
    static {
        //所有信息齐全
        Person person = new Person();
        person.setId(1);
        person.setName("littlehow");
        person.setAge(18);
        person.setHeight((short) 140);
        Work work = new Work();
        work.setSalary("500.00");
        work.setWorkage((short) 8);
        work.setWorkid(1);
        person.setWork(work);
        persons.put(Long.valueOf(1), person);
        //所有信息不全
        person = new Person();
        person.setId(2);
        person.setName("不全");
        work = new Work();
        work.setWorkid(2);
        person.setWork(work);
        persons.put(Long.valueOf(2), person);
    }

    /**
     * 借人
     * @param personId
     * @return
     * @throws TException
     */
    public Person borrowPerson(long personId) throws TException {
        if (personId > 2 || personId < 1) return null;
        return persons.get(personId);
    }
}

 

 
测试服务端结构如下:
 
package littlehow.thrift.demo.call.optional;

import littlehow.thrift.demo.AppendService;
import littlehow.thrift.demo.call.AppendServiceImpl;
import littlehow.thrift.demo.optional.BorrowPerson;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;

/**
 * Created by littlehow on 2016/6/27 0024.
 */
public class Server {
    public final static int port = 7456;


    public void start() {
        try {
            /** BorrowPerson */
            TProcessor processor = new BorrowPerson.Processor(new BorrowPersonImpl());
            /** 设置监听端口 */
            TServerTransport transport = new TServerSocket(port);
            /** 采用TCompactProtocol传输协议,服务端和客户端协议使用必须一致
             * 可选的协议有:TBinaryProtocol/TJSONProtocol/TSimpleJSONProtocol/TTupleProtocol
             * 其中TTupleProtocol是TCompactProtocol的子类,可以根据自己的业务选择对应的协议
             */
            TProtocolFactory pf = new TCompactProtocol.Factory();
            TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(transport).protocolFactory(pf).processor(processor));
            System.out.println("server started ,port is " + port);
            server.serve();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Server().start();
    }
}

 

 
测试客户端:
 
package littlehow.thrift.demo.call.optional;

import littlehow.thrift.demo.AppendService;
import littlehow.thrift.demo.call.Server;
import littlehow.thrift.demo.optional.BorrowPerson;
import littlehow.thrift.demo.optional.Person;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

/**
 * Created by littlehow on 2016/6/27 0024.
 */
public class Client {
    public final String address = "localhost";

    public void run() {
        try {
            TTransport transport = new TSocket(address, Server.port);
            transport.open();
            TProtocol protocol = new TCompactProtocol(transport);
            BorrowPerson.Client client = new BorrowPerson.Client(protocol);
            System.out.println(System.currentTimeMillis());
            //信息齐全
            Person person1 = client.borrowPerson(1);
            //Person(id:1, name:littlehow, age:18, height:140, work:Work(workid:1, workage:8, salary:500.00))
            System.out.println(person1);
            //信息不全
            Person person2 = client.borrowPerson(2);
            //Person(id:2, name:不全, age:0, work:Work(workid:2, salary:2500.00))
            System.out.println(person2);
            System.out.println("height的设置情况:"+person2.isSetHeight());//false
            System.out.println("age的设置情况:"+person2.isSetAge());//true
            System.out.println("work.workage的设置情况:" + person2.getWork().isSetWorkage());//false
            System.out.println(System.currentTimeMillis());
            transport.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Client().run();
    }
}

 

 
测试结果分析:
person1的信息都设置,所以信息都是齐全的。
对person2的输出进行一些讲解:
Person(id:2, name:不全, age:0, work:Work(workid:2, salary:2500.00))

 

 
为什么age:0会被输出,被输出就表明被反序列化回来了,可是我在客户端就没有设置age值啊;
因为:age在定义idl文件的时候用的是默认的修饰(required),所以age会被传输,就是这么简单,
那么后面的height,age,workage的isset输出就知道为什么了,
因为height和workage的修饰变量是optional,所以isset=false,age是required,所以isset=true。
还有一个就是work中salary:2500.00,这个值在服务端没有设置,传输到客户端为什么是2500.00呢,
因为idl文件中有定义default的值为2500.00。
 
想了解thrift设置的详细信息,可以查看链接:
http://thrift.apache.org/docs/idl
 

 

 

 

你可能感兴趣的:(java)