Spring boot如何正确使用@PostConstruct

Mas*_*Boo 5 java spring spring-boot

Spring boot 2.5.4 我第一次在我的服务类中使用@PostConstruct。如下:-

   @Slf4j
   @Service
   @AllArgsConstructor

    public class FileMonitorService {

    private final AppProperties appProperties;

    private final WatchService watchService;

    private final RestTemplate restTemplate;

   @PostConstruct
   @Async
    public void startMonitoring() {
        FileUtils.setAppProperties(appProperties);
        FileUtils.setRestTemplate(restTemplate);
        FileUtils.readFilesForDirectory();
        log.info("START_MONITORING");
        try {
            WatchKey key;
            while ((key = watchService.take()) != null) {
                for (WatchEvent<?> event : key.pollEvents()) {
                    log.info("Event kind: {}; File affected: {}", event.kind(), event.context());
                   if((event.kind() == StandardWatchEventKinds.ENTRY_CREATE ||
                      event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) &&
                      event.context().toString().contains(".xml")){
                       try {
                           restTemplateRequest(event.context().toString()+" processing");
                           FileUtils.readXml(Path.of(FileUtils.getFileAbsolutePath(appProperties.getDataIn()),
                                   event.context().toString()));
                       }catch (Exception e){
                           log.error("startMonitoring Exception: "+e.getMessage());
                       }
                   }
                }
                key.reset();
            }
        } catch (InterruptedException e) {
            log.warn("startMonitoring: interrupted exception for monitoring service: "+e.getMessage());
        }
    }
 }
Run Code Online (Sandbox Code Playgroud)

应用程序启动后立即调用此方法。这是我在应用程序启动后立即处理所有文件的要求。我的控制器如下:-

@RestController
@RequestMapping("/xml")
public class FileController {

    @Autowired
    FileMonitorService fileMonitorService;

    @SneakyThrows
    @GetMapping("/restart")
    public String restartFileMonitoring(){
        fileMonitorService.startMonitoring();
        return "File monitoring restarted started successfully";
    }
}
Run Code Online (Sandbox Code Playgroud)

我的应用程序在端口 8080 上启动,没有任何例外。但是当我接到这个终点的电话时 localhost:8080/xml/restart

这是无法到​​达的。如果我注释掉@PostConstruct然后我可以调用终点。我很困惑如何正确使用这个注释。我的代码有什么问题?

更新信息:-

    :: Spring Boot ::                (v2.5.4)

2021-09-14 18:23:21.521  INFO 71192 --- [           main] c.f.i.task.BatchProcessorApplication     : Starting BatchProcessorApplication using Java 14.0.2 on dev with PID 71192 (/home/dev/Desktop/batch-processor/batch-processor/target/classes started by dev in /home/dev/Desktop/batch-processor/batch-processor)
2021-09-14 18:23:21.523  INFO 71192 --- [           main] c.f.i.task.BatchProcessorApplication     : No active profile set, falling back to default profiles: default
2021-09-14 18:23:22.485  INFO 71192 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-09-14 18:23:22.495  INFO 71192 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-09-14 18:23:22.495  INFO 71192 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.52]
2021-09-14 18:23:22.564  INFO 71192 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-09-14 18:23:22.564  INFO 71192 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 988 ms
File to monitor: /home/dev/Desktop/batch-processor/batch-processor/data/in
2021-09-14 18:23:22.647  INFO 71192 --- [           main] c.f.i.task.config.FileMonitorConfig      : MONITORING_DIR: /home/dev/Desktop/batch-processor/batch-processor/data/in/
2021-09-14 18:23:22.667  INFO 71192 --- [           main] c.f.i.task.service.FileMonitorService    : START_MONITORING
Run Code Online (Sandbox Code Playgroud)

这是我运行应用程序时的日志。调试后,我发现while ((key = watchService.take()) != null) {调用永远不会返回,直到我复制一些 XML 文件,因为此应用程序处理 xml 文件。然后我复制监控目录中的任何 xml 文件。我期望@Async它将在异步模式下在后台线程中运行。如何在后台线程中监视这个目录?所以这个方法的调用者不会被阻塞。

tma*_*wen 10

PostContstruct语义


PostConstruct注释是JSR 330(依赖注入)的一部分,而不是Spring自定义注释。

注解规范规定,带注解的方法必须在服务注入上下文或转换为服务之前运行。

Spring支持PostConstruct生命周期钩子,允许在 bean 初始化后执行额外的初始化后操作,即注入所有依赖项。

Async语义


Async另一方面,注释是Spring特定的注释,允许将方法或类型标记为异步执行的候选者。

选择


如果您有兴趣在应用程序启动时启动后台进程,那么您应该更好地使用应用程序生命周期事件,更具体地说是ApplicationReadyEvent旋转您的监视活动:

@Slf4j
@Service
@AllArgsConstructor
public class FileMonitorService {

    private final AppProperties appProperties;

    private final WatchService watchService;

    private final RestTemplate restTemplate;

    @EventListener(ApplicationReadyEvent.class)
    @Async
    public void startMonitoring() {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

并且不要忘记@EnableAsyncSpring Boot配置类型上添加注释以激活异步处理功能。

  • 应该为 FileMonitorService 类级别添加“@EnableAsync”?或者 Spring Boot SpringApplication 主类级别? (2认同)
  • 它应该位于主应用程序“SpringApplication”或任何“@Configuration”注释类型的顶部。 (2认同)