【问题标题】:Spring Autowiring giving NPE. not manually creating beansSpring Autowireing 提供 NPE。不手动创建 bean
【发布时间】:2019-07-02 13:29:23
【问题描述】:

我的 Spring MVC 程序中的服务类在运行应用程序时仍然为空。这两个类都是@Service 并且在控制器类中有@Autowired 但仍然为空。我已经浏览了几天,发现只有两个原因,(我相信)都不适用于我的情况。

Spring boot 应用程序试图创建一个不和谐的机器人,自动装配在控制器或 Junit 测试中不起作用(执行时 NPE,调试时变量显示为 null)。

驱动类:

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
    • deth
      • DethBot 应用程序
      • 控制器
        • DethBotCommandListner
      • 服务
        • RaidAdminService(接口)
        • RaidAdminServiceImpl(类) ....

当程序启动并运行时,在 discord 服务器中发送“!open”,正确地点击 switch 语句并尝试调用 createRaid 方法,但 RaidAdminService 没有自动装配,因此它在 null 上调用该方法。

【问题讨论】:

  • new BotCommandListener() 的哪一部分不是手动创建 bean?
  • 即使从 BotCommandListener 类中删除 @Component(以阻止它变成 bean?)仍然将其他设置为 null,所以我认为这不是问题。
  • 但这与您想要的相反。您需要 BotCommandListener 成为一个 bean。现在您自己创建它,这就是它不起作用的原因。
  • 更新了驱动程序类中显示的代码,现在应用程序无法启动,因为 BotCommandListener 为空而不是自动装配
  • 现在它是空的,因为它是静态的,它不会工作。使其成为实例变量或将其提取到另一个类。

标签: java spring spring-boot


【解决方案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.

【讨论】:

    【解决方案2】:

    看那个:

    @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 应用程序。
    它会给:

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

    【讨论】:

      【解决方案3】:

      您手动实例化了该对象,因此 Spring 不知道该 bean。这就是您的 @Autowired 字段为空的原因。

      Spring boot要先加载primary类,然后通过这些类继续注入bean。

      【讨论】:

        【解决方案4】:

        扩展 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 而不是“静态”时才有效。

        【讨论】:

          猜你喜欢
          • 2011-06-18
          • 2012-11-03
          • 1970-01-01
          • 2012-06-04
          • 1970-01-01
          • 1970-01-01
          • 2014-05-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多