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

标签 java spring servlets thrift

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

我知道 Apache Thrift 在使用 TServer 及其派生产品时通过使用 TMultiplexingProcessor 支持多路复用,但是由于我使用 Spring 并且我的 Servlet、Handler 和 Processor 都是 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;
    }

}

UserServiceServlet.java

@Component
public class UserServiceServlet extends TServlet {
    private UserServiceProcessor processor;

    @Autowired
    public UserServiceServlet(UserServiceProcessor p) {
        super(p, new TBinaryProtocol.Factory());
        processor = p;
    }
}

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 等。

最佳答案

好的,明白了。可能不是最好的方法,欢迎批评指正。

这是我的粗略步骤:

  1. 保持处理程序类的原样。
  2. 创建一个扩展 TMultiplexedProcessor 的新类
  3. 创建一个扩展 TServlet 的新类
  4. 所有处理器(例如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

这一切可能对其处于我这种情况的其他人有帮助,所以享受吧!

附注确保在调整客户端时使用 TMultiplexedProtocol ,以便在与服务器通信时可以传递服务名称,例如

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);

关于java - 使用 Apache Thrift 和 TServlet 执行服务多路复用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24063686/

相关文章:

带有 JFrame 的 Java GUI

java - Apache 弗林克 : The execution environment and multiple sink

spring - 使用 Spring 的 @Value 注入(inject) Map<String, List<String>>

java - Uploadify 插件不调用 Java Servlet

java - Spark SQL 性能

java - 将 String 转换为 Integer 时出现 NumberFormatException

java - Spring 安全 : AnonymousAuthenticationToken vs UsernamePasswordAuthenticationToken

java - Spring Boot 与 @PostConstruct 的集成测试取决于 @Before 部分

java - Spring MVC 应用程序可以是多线程的,即使它的 servlet 不是吗?

java - javax.servlet.jsp-api 的用途是什么