弹簧自动接线给NPE。不能手动创建bean

时间:2019-07-01 22:48:08

标签: java spring spring-boot

在运行该应用程序时,我的spring MVC程序中的服务类仍然为空。这两个类都是@Service,并且在控制器类中具有@Autowired,但仍为null。我浏览了几天,发现的原因只有两个,我认为这都不是我的情况。

Spring Boot应用试图创建Discord机器人,自动装配无法在控制器或Junit测试中运行(执行时为NPE,调试时变量显示为空)。

驱动程序类:

package com.deth;

//imports
@SpringBootApplication
public class DethBotApplication {


    private static Logger logger = Logger.getLogger(DethBotApplication.class);

    @Autowired
    private static BotCommandListener botListener;

    public static void main(String[] args)  {
        SpringApplication.run(DethBotApplication.class, args);


        try {
            JDA jda = new JDABuilder(AccountType.BOT)
                .setToken(TOKEN)
                //.addEventListener(command controller)
                .addEventListener(botListener)
                .build(); //starts listening in discord server.

相关控制器代码:

package com.deth.controller;
//imports
@Component  
public class BotCommandListener extends ListenerAdapter {


        private static Logger logger = Logger.getLogger(BotCommandListener.class);

        @Autowired
        @Qualifier("raidAdminService")
        private RaidAdminService raidAdminService; 

        @Autowired
        private RaidRosterServiceImpl raidRosterService;

        @Autowired
        private RaidAttendanceService raidAttendanceService;

        @Override
        public void onMessageReceived(MessageReceivedEvent event) {
            JDA jda = event.getJDA();

            String msg = event.getMessage().getContentDisplay();
            if(msg.startsWith("!")) {
                String command = "";
                if(!msg.contains(" ")) {
                    command = msg;
                } else {
                    command = msg.subSequence(0, msg.indexOf(" ")).toString();
                    logger.trace("possible command: " + command);
                }
                try {
                    switch (command) {
                    //raid leader commands
                    case "!open":
                        raidAdminService.createRaid(event); //NPE here
                        logger.trace("!open detected");
                        break;

raidAdminService:

package com.deth.service;
//imports
@Service("raidAdminService")
public class RaidAdminServiceImpl extends CommandInfoService implements RaidAdminService {

    String intRegex = "[0-9]+";

    @Override
    public void createRaid(MessageReceivedEvent event) {
        // TODO Auto-generated method stub

包装结构:

  • com
    • 深度
      • DethBotApplication
      • 控制器
        • DethBotCommandListner
      • 服务
        • RaidAdminService(界面)
        • RaidAdminServiceImpl(类) ....

程序启动并运行时,在不和谐服务器中发送“!open”,正确命中switch语句并尝试调用createRaid方法,但是RaidAdminService并未自动装配,因此将其调用为null。

4 个答案:

答案 0 :(得分:1)

我认为问题出在您的DethBotApplication类中。您不能在那里自动接线。主类需要首先执行。之后,该应用程序将查找@ Componet,@ Service,@ Controller ...批注。下面的代码可能会解决您的问题。

package com.deth;

//imports
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DethBotApplication extends SpringBootServletInitializer {

    private static Logger logger = Logger.getLogger(DethBotApplication.class);

    public static void main(String[] args)  {
        ConfigurableApplicationContext context = SpringApplication.run(DethBotApplication.class, args);
        BotCommandListener botListener = context.getBean(BotCommandListener.class);
        try {
            JDA jda = new JDABuilder(AccountType.BOT)
                .setToken(TOKEN)
                //.addEventListener(command controller)
                .addEventListener(botListener)
                .build(); //starts listening in discord server.

答案 1 :(得分:0)

您手动实例化了该对象,因此Spring不了解该bean。这就是为什么您的@Autowired字段为null的原因。

Spring Boot必须首先加载主类,然后再通过这些类继续注入注入的Bean。

答案 2 :(得分:0)

扩展ApplicationRunner或CommandLineRunner类

package com.deth;

//imports
@SpringBootApplication
@Component
public class DethBotApplication implements CommandLineRunner {


    private static Logger logger = Logger.getLogger(DethBotApplication.class);

    @Autowired
    private /*static*/ BotCommandListener botListener; // i remove "static" here

    public static void main(String[] args)  {
        SpringApplication.run(DethBotApplication.class, args);

    }

    @Override
    public void run(String args) {
        try {
            JDA jda = new JDABuilder(AccountType.BOT)
                .setToken(TOKEN)
                //.addEventListener(command controller)
                .addEventListener(botListener)
                .build(); //starts listening in discord server.
    ... 

这里的关键是(正如其他答案所指出的)@Autowired仅在它是@Component而不是“静态”时才起作用。

答案 3 :(得分:0)

看看:

@Autowired
private static BotCommandListener botListener;

public static void main(String[] args)  {
    SpringApplication.run(DethBotApplication.class, args);
    try {
        JDA jda = new JDABuilder(AccountType.BOT)
            .setToken(TOKEN)
            .addEventListener(botListener)
     //...
    }

您为@Autowired注释了一个静态字段,而Spring并未在静态字段中注入bean(而仅在实例字段中)。
您的问题确实非常普遍:您想在Spring Boot应用程序类的main()中执行某些依赖于某些bean的任务。
正确的方法是使用@PostConstruct批注。一旦在当前bean上执行依赖项注入,便会(自动)执行带有此方法注释的方法:此处为Spring Boot Application。
它会给出:

@Autowired
private BotCommandListener botListener;

@PostConstruct
public void init(){    
    JDA jda = new JDABuilder(AccountType.BOT)
        .setToken(TOKEN)
        .addEventListener(botListener)
        .build(); 
       // ...    
}