如何中止 Spring-Boot 启动?
How can I abort Spring-Boot startup?
我正在编写一个 Spring-Boot 应用程序来监视目录并处理添加到其中的文件。我在配置 class:
中用 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;
}
}
如果注册目录失败,我想中止 Spring 正常启动。有人知道我该怎么做吗?
Each SpringApplication will register a shutdown hook with the JVM to
ensure that the ApplicationContext is closed gracefully on exit. All
the standard Spring lifecycle callbacks (such as the DisposableBean
interface, or the @PreDestroy annotation) can be used.
In addition, beans may implement the
org.springframework.boot.ExitCodeGenerator interface if they wish to
return a specific exit code when the application ends.
您应该实现释放资源/文件的@PreDestroy 方法。然后在启动期间,当您检测到一些错误时,您可以抛出一些 RuntimeException
- 它开始关闭应用程序上下文。
获取应用上下文,例如:
@Autowired
private ConfigurableApplicationContext ctx;
找不到目录就调用close
方法:
ctx.close();
这会正常关闭应用程序上下文,从而关闭 Spring 引导应用程序本身。
更新:
基于问题中提供的代码的更详细示例。
主要Class
@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();
}
}
}
WatchService 配置
@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();
}
}
根据目录是否存在创建 WatchService Bean @Conditional
。然后在您的 Main Class 中,检查 WatchService Bean 是否存在,如果不存在,则通过调用 close()
.
关闭 Application Context
接受的答案是正确的,但不必要地复杂。不需要一个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);
}
}
我正在编写一个 Spring-Boot 应用程序来监视目录并处理添加到其中的文件。我在配置 class:
中用 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;
}
}
如果注册目录失败,我想中止 Spring 正常启动。有人知道我该怎么做吗?
Each SpringApplication will register a shutdown hook with the JVM to ensure that the ApplicationContext is closed gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface, or the @PreDestroy annotation) can be used.
In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when the application ends.
您应该实现释放资源/文件的@PreDestroy 方法。然后在启动期间,当您检测到一些错误时,您可以抛出一些 RuntimeException
- 它开始关闭应用程序上下文。
获取应用上下文,例如:
@Autowired
private ConfigurableApplicationContext ctx;
找不到目录就调用close
方法:
ctx.close();
这会正常关闭应用程序上下文,从而关闭 Spring 引导应用程序本身。
更新:
基于问题中提供的代码的更详细示例。
主要Class
@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();
}
}
}
WatchService 配置
@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();
}
}
根据目录是否存在创建 WatchService Bean @Conditional
。然后在您的 Main Class 中,检查 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);
}
}