我有一个Spring应用程序,它由一个我们需要单线程的API控制,但我无法弄清楚如何实现这一点。该应用程序是对单线程应用程序进行重新分解。他们想要新版本的相同基本设计,同时使用我们的新编程方法(即Java,Spring等)并添加额外的功能。
有一个API资源可以启动应用程序:
@RequestMapping("/start")
public String startProcess(){...}
如果调用两次,则应用程序将启动另一个线程。 我们希望阻止这种情况发生。但是,我们仍然希望停止API资源起作用:
@RequestMapping("/stop")
public String stopProcess(){...}
该应用程序具有典型的Spring结构:
@SpringBootApplication
public class MyApplication{...}
@RestController
public class MyController{
@Autowired
private MyService myService;
...}
@Service
@Transactional
public class CarolService{
@Autowired
private MyDAO myDAO;
...}
@Repository
public class myDAO{...}
如何确保一次只运行此应用程序的一个实例?请帮忙!并且,提前谢谢!
答案 0 :(得分:1)
实际上有两个不同的问题:使您的API成为单线程,并确保一次只运行此应用程序的一个实例。
解决方案在概念上是相同的:您必须在某些互斥锁上进行同步。但是在第一种情况下比在第二种情况下要容易得多。
要使您的API单线程,您需要同步某些内容。如果您只有一个控制器,只需制作API方法synchronized
即可。如果您有多个控制器,则需要创建一些应用程序范围bean,将其注入每个控制器并在其上进行同步。在过去,也有类似SingleThreadModel
的东西,但我认为它已被弃用。几年没有看过它,但如果Spring有办法以某种方式设置它,我不会感到惊讶。
确保一次只运行此应用程序的一个实例要困难得多。您基本上希望阻止任何人并行启动应用程序的多个副本。实现这一目标的方法之一是拥有一些中央共享资源,如数据库。在启动时,应用程序将尝试通过在某个表中创建记录来“获取”互斥锁(这将允许最多一条记录)。如果记录创建成功,则应用程序正常启动,否则则失败。您需要一些机制来检测陈旧的互斥记录 - 可能就像在互斥记录中保存时间戳并通过计划任务(心跳)不断更新它一样简单。
我们最近在运行许多微服务的许多实例的应用程序中有类似的任务。我们只需要一个微服务来定期执行某些维护任务。我们通过中央MongoDB数据库进行同步来解决它。微服务尝试通过在数据库集合中创建文档来获取互斥锁。通过设计,该集合中最多可存在一个文档,并且创建该文档的微服务执行常规任务并在最后移除该文档。该集合配置了自动清理,因此如果微服务因任何原因无法删除文档,它将被数据库自动删除。