如何在 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,现在一切正常!
我最近学到了很多关于 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,现在一切正常!