【问题标题】:How to use @Autowired correctly in spring boot standalone app如何在 Spring Boot 独立应用程序中正确使用 @Autowired
【发布时间】:2018-01-28 13:08:50
【问题描述】:

我最近学到了很多关于 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);
    });

这是我的主类的构造函数,基本上所有事情都发生在这里。我省略了对初始化每个模块的方法的调用以缩短它:

@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;
}

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

任何帮助将不胜感激。

谢谢!

【问题讨论】:

标签: spring spring-boot constructor null autowired


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    您通常不必使用构造函数 + @Autorwired,您可以直接在字段上使用 autowired,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 方法的参数。但即使在那种情况下,你也可以从你的主代码中做到这一点。这实际上是您对调用各种设置器的主服务所做的,而不是弄乱构造函数来设置这些值。

    【讨论】:

    • 因为我正在通过 ctx.getBean() 初始化我的 JFrame,所以我肯定已经涵盖了这一部分。根据我过去所做的测试,自动装配的 bean 仅在从构造函数访问时为空,正如我所说,这是该应用程序代码的 95%。我确实将@Component 注释添加到我的主类中,但似乎无论我做什么,服务在构造函数调用的任何代码中始终为空。已经有一段时间了,但我确实记得使用 PostConstruct 对构造函数调用的方法进行注释,但这也不起作用。
    • 澄清为什么你需要访问构造函数中的服务变量?如果您使用 Autowired,您甚至可能根本不需要构造函数,并且 PostConstruct 将使用标准方法,而不是构造函数。还要确保你实际上并没有用 new) 来调用自己的构造函数,而是让 spring 来做。
    • 我的服务基本上是一个 JFrame,它初始化了 4 个模块(连接、消息传递、维护和 Web 连接器)。它用作医院信息系统的后端。没有人可以直接与这个应用程序交互(除了 4 个重启按钮,它们会杀死单个模块并重新启动它们)。初始化代码都在主类的构造函数中,这就是为什么我需要从那里访问自动装配服务。
    • 从你的例子来看,构造函数中没有初始化代码,只有字段的依赖注入......你应该决定是让 spring 为你做这件事还是手动处理它。 (啊,不幸的是你删除了它)。无论如何,您不需要在该构造函数内部调用并明确给出依赖项,因为您基本上不使用 spring。您可以自动装配子组件的字段。
    • 是的,我做错的正是你所说的,非常感谢你的帮助!我对在 Web 应用程序中使用 Spring 非常熟悉,但是我缺少一些能够将依赖注入应用到 Swing 应用程序的东西。
    猜你喜欢
    • 2016-07-04
    • 2018-12-30
    • 2020-03-30
    • 2021-05-30
    • 2021-05-24
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    相关资源
    最近更新 更多