我想知道什么是具有单线程执行程序的RESTful Web服务的最佳架构。
我的目标:
instanciated对象的生命周期非常重要(必须有只有一个线程队列)。我知道RESTful Web服务生命周期是每个请求" (类似于我认为的@RequestScoped),所以我看到了2个选项:
选项1:
public class RestService {
protected final static Executor executor;
protected final static Implementation1 impl1;
protected final static Implementation2 impl2;
static {
executor = Executors.newSingleThreadExecutor();
impl1 = new Implementation1();
impl2 = new Implementation2();
}
}
@Path("/servicename")
public class MyService extends RestService {
@POST
@Path("/compute")
public void compute(){
executor.execute(new Runnable(){
public void run(){
impl1.compute();
}
});
}
}
选项2:
@Singleton
public class RestService {
private Executor executor;
private Implementation1 impl1;
private Implementation2 impl2;
public RestService () {
executor = Executors.newSingleThreadExecutor();
impl1 = new Implementation1();
impl2 = new Implementation2();
}
public void execute(Runnable run){
executor.execute(run);
}
public Implementation1 getImplementation1(){
return impl1;
}
public Implementation2 getImplementation2(){
return impl2;
}
}
@Path("/servicename")
public class MyService {
@Inject
private RestService rs;
@POST
@Path("/compute")
public void compute(){
rs.execute(new Runnable(){
public void run(){
rs.getImplementation1().compute();
}
});
}
}
对于选项1,我不确定"生命周期"关于静态领域。我应该使用哪个选项?你会怎么做?
由于
编辑: 选项3(由EJB容器处理的线程)和"排序"并不重要:
@Singleton
public class RestService {
private final Executor executor;
private final Implementation1 impl1;
private final Implementation2 impl2;
public RestService () {
executor = Executors.newSingleThreadExecutor();
impl1 = new Implementation1();
impl2 = new Implementation2();
}
public void compute1(){
executor.execute(new Runnable(){
public void run(){
impl1.compute();
}
});
}
public void compute2(){
executor.execute(new Runnable(){
public void run(){
impl2.compute();
}
});
}
}
@Path("/servicename")
public class MyService {
@Inject
private RestService rs;
@POST
@Path("/compute1")
public void compute1(){
rs.compute1();
}
@POST
@Path("/compute2")
public void compute2(){
rs.compute2();
}
}
我认为选项3仍然优于选项1& 2。
答案 0 :(得分:6)
我认为这样做是个坏主意。线程应该由您的容器处理,而不是您的代码。
如果要在Java EE应用服务器上进行部署,则应该让它处理线程。
如果要在Netty或vert.x等非阻塞I / O服务器上进行部署,则应该让它处理线程。
在任何情况下都不应该管理线程。
加载.class时实例化静态字段。它们没有像实例那样的“生命周期”。在类加载器删除.class文件之前,它们不会被清理。
如果你必须有这种行为,我要么使用JMS队列来订购处理,要么使用生产者/消费者deque来管理它。您希望处理是异步的。让REST服务将令牌或收据返回给客户端,让他们回来查看处理完成的时间。如果线条很长,你将无法知道他们的衬衫什么时候准备就绪。收据让他们回来检查他们的结果何时可用。
答案 1 :(得分:0)
如果您使用Spring,然后将业务逻辑分离为单独的组件(bean)并将这些bean注入到服务类中,则只需更改业务的“范围”属性即可有效控制实现的线程模型逻辑豆。
这是description of Spring bean scopes。
这种方法可以让您轻松修改/试验您的解决方案,并为您的情况找到最佳选择。
就架构而言,我建议您对系统进行分层(松散耦合,高内聚,关注点分离等)。在这方面,您可能拥有服务层(REST),业务层和数据(dao)层最小值。这些层通过接口相互交互。使用Spring将事物连接在一起(注入依赖关系)。这使您可以灵活地注入不同的实现。示例是为您的业务类注入模拟DAO以进行单元测试。 REST服务所在的服务层将执行请求/响应的转换,一些验证,确定要调用的业务组件以及调用它们。