如何在spring boot standalone app

时间:2018-01-28 13:08:51

标签: spring spring-boot constructor null autowired

我最近学到了很多关于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注释,但我得到的只是null服务。

任何帮助都将不胜感激。

谢谢!

2 个答案:

答案 0 :(得分:0)

我弄清楚了我的问题,这是一个非常愚蠢的问题。首先,我没有使用@Component注释我的主类,所以Spring从不打算在其中注入依赖项。其次,我没有意识到使用@PostContruct注释的方法会在构造函数运行后自行运行而不需要明确地调用它!

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

答案 1 :(得分:-1)

你通常不需要使用构造函数+ @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方法的参数。但即使在这种情况下,您也可以从主代码中完成。这实际上是你用主服务调用各种setter所做的,而不是搞乱构造函数来设置这些值。