Java 使用Apache Thrift和TServlet执行服务多路复用

Java 使用Apache Thrift和TServlet执行服务多路复用,java,spring,servlets,thrift,Java,Spring,Servlets,Thrift,我有一个系统(Java with Spring Framework),它使用TServlet类通过HTTP公开了7个不同的Apache Thrift servlet。目前,它们都需要自己的servlet、servlet映射、处理器、处理程序等。因此,实现客户端还必须保留不同服务的所有不同URL的内部列表 我知道Apache Thrift在使用TServer及其衍生产品时支持多路复用,使用TMultiplexingProcessor,但是由于我使用的是Spring和我的Servlet,处理程序和处

我有一个系统(Java with Spring Framework),它使用TServlet类通过HTTP公开了7个不同的Apache Thrift servlet。目前,它们都需要自己的servlet、servlet映射、处理器、处理程序等。因此,实现客户端还必须保留不同服务的所有不同URL的内部列表

我知道Apache Thrift在使用
TServer
及其衍生产品时支持多路复用,使用
TMultiplexingProcessor
,但是由于我使用的是Spring和我的Servlet,处理程序和处理器都是Spring bean,它们可以自动连接在一起,我不确定如何继续

以下是其中一项服务如何连接的示例:

UserServiceHandler.java

@Component
public class UserServiceHandler implements UserService.Iface {
    @Override
    public User getUser(String userId) throws TException {
        // implementation logic goes here
    }
}
UserServiceProcessor.java

@Component
public class UserServiceProcessor extends UserService.Processor<UserServiceHandler> {

    private UserServiceHandler handler;

    @Autowired
    public UserServiceProcessor(UserServiceHandler iface) {
        super(iface);
        handler = iface;
    }

    public UserServiceHandler getHandler() {
        return handler;
    }

    public void setHandler(UserServiceHandler handler) {
        this.handler = handler;
    }

}
Servlet注册

ServletRegistration.Dynamic userService = servletContext.addServlet("UserServiceServlet", (UserServiceServlet) ctx.getBean("userServiceServlet"));
userService.setLoadOnStartup(1);
userService.addMapping("/api/UserService/*");
// This same block repeated 7 times for each *ServiceServlet with different mappings

我希望所有7个服务处理程序都映射到一个URL,如
/api/*
。这可能吗?我想我必须创建一个servlet和处理器,但我不确定它们应该是什么样子。我的处理器扩展了
UserService.Processor
等等。

好的,算出了。这可能不是最好的方法,所以我欢迎批评

以下是我的艰难步骤:

  • 保持处理程序类的原样
  • 创建扩展
    TMultiplexedProcessor
  • 创建扩展TServlet的新类
  • 所有处理器(例如
    UserServiceProcessor
    都有
    handler
    属性和相应的getter和setter
  • 这是我的
    ApiMultiplexingProcessor

    @Component
    public class ApiMultiplexingProcessor extends TMultiplexedProcessor {
    
        UserServiceHandler userServiceHandler;
        ReportServiceHandler reportServiceHandler;
        // ... more service handlers can go here
    
        @Autowired
        public ApiMultiplexingProcessor(UserServiceProcessor userServiceProcessor, ReportServiceProcessor reportServiceProcessor) {
            this.registerProcessor("UserService", userServiceProcessor);
            this.registerProcessor("ReportService", reportServiceProcessor);
            // add more registerProcessor lines here for additional services
    
            userServiceHandler = userServiceProcessor.getHandler();
            reportServiceHandler = reportServiceProcessor.getHandler();
            // set any additional service handlers here
        }
    
        // getters and setters for the handlers
    
        public UserServiceHandler getUserServiceHandler() {
            return userServiceHandler;
        }
    
        public void setUserServiceHandler(UserServiceHandler userServiceHandler) {
            this.userServiceHandler = userServiceHandler;
        }
    
        public ReportServiceHandler getReportServiceHandler() {
            return reportServiceHandler;
        }
    
        public void setReportServiceHandler(ReportServiceHandler reportServiceHandler) {
            this.reportServiceHandler = reportServiceHandler;
        }
    }
    
    因此,为了稍微解释一下上面的内容,如果您添加了任何其他服务,您需要将*ServiceHandler类作为字段添加到此类中,并创建getter和setter等

    现在我们有了它,我们可以创建一个新的servlet,它将被添加到servlet上下文中

    这是我的
    ApiServlet

    @Component
    public class ApiServlet extends TServlet {
        private ApiMultiplexingProcessor processor;
    
        @Autowired
        public ApiServlet(ApiMultiplexingProcessor p) {
            super(p, new TBinaryProtocol.Factory());
            processor = p;
        }
    }
    
    然后您只需像前面一样将这个servlet添加到servlet上下文(来自bean):

    ServletRegistration.Dynamic api = servletContext.addServlet("ApiServlet", (ApiServlet) ctx.getBean("apiServlet"));
    api.setLoadOnStartup(1);
    api.addMapping("/api/*");
    // yay now we have a single URL and a single servlet
    
    在我的情况下,这一切都可能对其他人有所帮助,所以请享受

    注意:在调整客户端时,请确保使用
    t多路协议
    ,以便在与服务器通话时传递服务名称,例如:

    TTransport transport = new THttpClient(new Uri("https://myapp.com/api/"));
    TProtocol protocol = new TBinaryProtocol(transport);
    TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "UserService");
    UserService.Client userServiceClient = new UserService.Client(mp);
    
    TTransport transport = new THttpClient(new Uri("https://myapp.com/api/"));
    TProtocol protocol = new TBinaryProtocol(transport);
    TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "UserService");
    UserService.Client userServiceClient = new UserService.Client(mp);