我正在编写一个Spring-Boot应用程序,以监视正在添加到其中的目录和处理文件。我在配置类中的WatchService注册目录:
@Configuration
public class WatchServiceConfig {
private static final Logger logger = LogManager.getLogger(WatchServiceConfig.class);
@Value("${dirPath}")
private String dirPath;
@Bean
public WatchService register() {
WatchService watchService = null;
try {
watchService = FileSystems.getDefault().newWatchService();
Paths.get(dirPath).register(watchService, ENTRY_CREATE);
logger.info("Started watching "{}" directory ", dlsDirPath);
} catch (IOException e) {
logger.error("Failed to create WatchService for directory "" + dirPath + """, e);
}
return watchService;
}
}
如果注册目录失败,我想优雅地中止春季启动。有人知道我该怎么做吗?
获取应用程序上下文,例如:
@Autowired
private ConfigurableApplicationContext ctx;
如果找不到目录:
,请调用close
方法 ctx.close();
优雅地关闭应用程序上下文,从而使Spring Boot应用程序本身。
更新:
基于问题中提供的代码的更详细的示例。
主类
@SpringBootApplication
public class GracefulShutdownApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(GracefulShutdownApplication.class, args);
try{
ctx.getBean("watchService");
}catch(NoSuchBeanDefinitionException e){
System.out.println("No folder to watch...Shutting Down");
ctx.close();
}
}
}
手表服务配置
@Configuration
public class WatchServiceConfig {
@Value("${dirPath}")
private String dirPath;
@Conditional(FolderCondition.class)
@Bean
public WatchService watchService() throws IOException {
WatchService watchService = null;
watchService = FileSystems.getDefault().newWatchService();
Paths.get(dirPath).register(watchService, ENTRY_CREATE);
System.out.println("Started watching directory");
return watchService;
}
文件夹条件
public class FolderCondition implements Condition{
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
String folderPath = conditionContext.getEnvironment().getProperty("dirPath");
File folder = new File(folderPath);
return folder.exists();
}
}
根据目录是否存在,制作手表服务bean @Conditional
。然后在您的主要课程中,检查WatchService Bean是否存在,如果不致电close()
。
接受的答案是正确的,但不必要地复杂。不需要Condition
,然后检查BEAN的存在,然后关闭ApplicationContext
。只需检查WatchService
创建期间目录的存在即可,而抛出例外就会因未能创建bean而流产启动。
如果您可以使用当前IOException
中的消息传递,则可以将bean投掷到中止启动:
@Bean
public WatchService watchService() throws IOException {
WatchService watchService = FileSystems.getDefault().newWatchService();
Paths.get(dirPath).register(watchService, ENTRY_CREATE);
logger.info("Started watching "{}" directory ", dlsDirPath);
}
如果您想要比默认IOException
更友好的错误消息(为了更好地帮助用户指向错误),则可以使用自定义的异常消息进行自己的异常:
@Bean
public WatchService watchService() {
try {
WatchService watchService = FileSystems.getDefault().newWatchService();
Paths.get(dirPath).register(watchService, ENTRY_CREATE);
logger.info("Started watching "{}" directory ", dlsDirPath);
return watchService;
} catch (IOException e) {
throw new IllegalStateException(
"Failed to create WatchService for directory "" + dirPath + """, e);
}
}
https://docs.spring.io/spring-boot/docs/2.1.1.release/referene/htmlsingle/htmlsingle/#boot-features-features-application-application-application-exit-exit-exit
每个SpringApplication将在JVM上注册一个关闭挂钩 确保ApplicationContext在退出时优雅地关闭。全部 标准的春季生命周期回调(例如DisposableBean 可以使用界面或@Predestroy注释)。
此外,bean可以实施 org.springframework.boot.exitcodegenerator接口 申请结束时返回特定的出口代码。
您应该实现释放资源/文件的@predestroy方法。然后在启动期间,当您检测到某些错误时,您可以投掷一些RuntimeException
- 它开始关闭应用程序上下文。