如何在 spring 引导独立应用程序中正确使用@Autowired

How to use @Autowired correctly in spring boot standalone app

我最近学到了很多关于 Spring 的知识,我认为我可能误解的一件事是 @Autowired 注释,尤其是在构造函数中使用它时。你看,我正在开发的应用程序是一项服务,所以基本上一切都在构造函数中初始化。唯一实际发生的用户驱动事件是重启某些服务模块的按钮。这是我的主要方法:

ConfigurableApplicationContext ctx = new SpringApplicationBuilder(MDHIS_Service.class)
        .headless(false).web(false).run(args);
    java.awt.EventQueue.invokeLater(() -> 
    {
        MDHIS_Service frame = ctx.getBean(MDHIS_Service.class);
        frame.setSize(1024, 768);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    });

这是我的 main class 的构造函数,基本上一切都在这里发生。我省略了对初始化每个模块的方法的调用以缩短它:

@Autowired
public MDHIS_Service(GlobalParamService globalParamService, LogEntryService logentryService, InterfaceService interfaceService, 
        ConnectionService connectionService, OutboundMessageService outboundMessageService, OutboundMessageHistoryService outboundMessageHistoryService, 
        InboundMessageService inboundMessageService, FacilityService facilityService, ModuleStatusService moduleStatusService,
        SequenceService sequenceService) 
{
    this.globalParamService = globalParamService;
    this.logEntryService = logentryService;
    this.interfaceService = interfaceService;
    this.connectionService = connectionService;
    this.outboundMessageService = outboundMessageService;
    this.outboundMessageHistoryService = outboundMessageHistoryService;
    this.inboundMessageService = inboundMessageService;
    this.facilityService = facilityService;
    this.moduleStatusService = moduleStatusService;
    this.sequenceService = sequenceService;
}

我的 main class 每个服务都有一个 private final 全局变量。每个模块都是一个单独的线程,我发现自己必须将这些变量传递给每个模块的构造函数,后者将它们存储到自己的私有最终变量中。我现在做事的方式@Autowired 几乎没用,因为我必须传递实例。有没有办法更好地使用@Autowired?该服务用作大型网络应用程序的后端,我发现自己可以更好地利用其中的注释。我对这个主题做了很多研究,我确实尝试了@PostContruct 注释,但我得到的只是空服务。

如有任何帮助,我们将不胜感激。

谢谢!

您通常不必使用构造函数 + @Autorwired,您可以直接在字段上使用自动装配,spring 会为您填充依赖项:

@Component
public class MDHIS_Service {

@Autowired
private GlobalParamService globalParamService;

}

要理解的重要一点是,要使 spring 正常工作,您必须让它为您创建对象,而不是显式调用构造函数。然后它将根据需要填充依赖项。这是通过将服务声明为组件(例如使用 @Component 注释)来完成的,并且从不自己创建服务而是从依赖注入中获取它们。

您开始的第一个对象必须由 spring 创建并由应用程序上下文返回。

作为交换,您获得的好处是您不必明确转发所有内容。离应用程序根很远的子子子服务可以依赖于它可见的任何东西,而不必一路转发引用。

我建议看一下 spring 参考文档,它非常详细和完整:

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core

编辑:我会试着用一个例子来澄清一下...各种服务的初始化代码实际上做了什么?

也许它设置了依赖项。然后自动装配它们:

@Component 
MySubService {

@Autowired MySubSubService mySubSubService;

}

也许它比设置字段做更多的事情,所以你可以在上面添加一个 init 方法来完成它,这个 init 方法最终可以调用其他服务。

@Component 
MySubService {

@Autowired MySubSubService mySubSubService;

@PostConstruct
public void init() {
//Init code that may use mySubSubService.
}
}

您不必自己声明构造函数和转发依赖项,sprint 会为您完成。

您遇到问题的唯一情况是您最终需要一些不依赖于 init 方法的参数。但即使在那种情况下,您也可以从主代码中完成。这实际上就是您对调用各种设置器的主要服务所做的,而不是通过构造函数来设置这些值。

我解决了我的问题,这是一个非常愚蠢的问题。首先,我没有用 @Component 注释我的主 class 所以 Spring 从来没有费心在其中注入依赖项。其次,我没有意识到用@PostContruct 注释的方法会在构造函数 运行 之后自行 运行 而无需显式调用!

我将我所有的初始化代码都移到了一个用@PostConstruct 注释的init 方法中,并用@Component 注释了我的主要class,现在一切正常!