【问题标题】:Spring @Autowired field is null inside an overrided methodSpring @Autowired 字段在被覆盖的方法中为空
【发布时间】:2016-05-27 09:30:16
【问题描述】:

我有一个实现 MessageListener 的类,用于 Spring Data Redis。它适用于 Redis,但我有一个奇怪的行为。我有一个 test() 方法来测试 messageService 实例是否为空。它需要调用 Jpa Repository 来实现 MySql DB 中的持久性。奇怪的行为是,如果在 getNewMessage() 和 printWelcome() 方法中调用它,它就不是 null (然后我可以使用 CRUD 方法进行持久性),但它在 onMessage 中是 null () 方法被 org.springframework.data.redis.connection.MessageListener 类覆盖。这是我的 Controller 类:

@Controller
public class StatoController implements MessageListener{


  @Autowired
  private MessageService messageService;

  public static final List<DeferredResult<Message>> messageDeferredResultList = new ArrayList<>();

  @RequestMapping(value = "sec/redis", method = RequestMethod.GET, produces = "application/json")
  @ResponseBody
  public DeferredResult<Message> getNewMessage() throws Exception {
    Long deferredResultTimeout = 0L;

    final DeferredResult<Message> deferredResult = new DeferredResult<>(deferredResultTimeout);

    deferredResult.onCompletion(() -> {
        messageDeferredResultList.remove(deferredResult);
    });

    deferredResult.onTimeout(() -> {
        messageDeferredResultList.remove(deferredResult);
    });

    messageDeferredResultList.add(deferredResult);

    try{
        //not null
        List<Message> list=messageService.findAll();
    }
    catch(Exception ex){ex.printStackTrace();}

    return deferredResult;
  }

  @RequestMapping(value = {"sec/stato.html"}, method = RequestMethod.GET)
  public ModelAndView printWelcome(ModelMap model) {

    try{
        //not null
        List<Message> list=messageService.findAll();
    }
    catch(Exception ex){ex.printStackTrace();}

    ModelAndView mav = new ModelAndView("secured/stato");
    return mav;
  }


  @Override
  public void onMessage(Message msg, byte[] bytes) {

    try{
        //NullPointerException
        List<Message> list=messageService.findAll();
    }
    catch(Exception ex){ex.printStackTrace();}
    // set the deferred results for the user
    messageDeferredResultList.stream().forEach((deferredResult) -> {
        deferredResult.setResult(msg);
    });

  }

这是消息到达并调用 onMessage 方法时的堆栈跟踪:

java.lang.NullPointerException 在 infn.lns.acceleratori.controller.StatoController.onMessage(StatoController.java:95) 在 org.springframework.data.redis.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:299) 在 org.springframework.data.redis.listener.RedisMessageListenerContainer.executeListener(RedisMessageListenerContainer.java:245) 在 org.springframework.data.redis.listener.RedisMessageListenerContainer.processMessage(RedisMessageListenerContainer.java:235) 在 org.springframework.data.redis.listener.RedisMessageListenerContainer$1.run(RedisMessageListenerContainer.java:960) 在 java.lang.Thread.run(Thread.java:745)

当有来自 Redis 的消息时调用 onMessage() 方法。我在我的 context-config.xml 中正确添加了这个:

<context:annotation-config/>
<context:component-scan base-package="org.springframework.data.redis, infn.lns.acceleratori"/>

这是包含数据redis的bean声明的配置类:

@Configuration
public class AppConfig {

  @Bean
  JedisConnectionFactory jedisConnectionFactory() {
    return new JedisConnectionFactory();
  }

  @Bean
  RedisTemplate< String, Object > redisTemplate() {
    final RedisTemplate< String, Object > template =  new RedisTemplate<  >();
    template.setConnectionFactory( jedisConnectionFactory() );
    template.setKeySerializer( new StringRedisSerializer() );
    template.setHashValueSerializer( new GenericToStringSerializer<  >( Object.class ) );
    template.setValueSerializer( new GenericToStringSerializer<  >( Object.class ) );
    return template;
  }

  @Bean
  MessageListenerAdapter messageListener() {
    return new MessageListenerAdapter( new RedisMessageListener() );
  }

  @Bean
  RedisMessageListenerContainer redisContainer() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();

    container.setConnectionFactory( jedisConnectionFactory() );
    container.addMessageListener( messageListener(), new ChannelTopic( "queue" ) );

    return container;
  }

}

这是作为 Bean 创建的 MessageServiceImpl:

@Service
public class MessageServiceImpl implements MessageService {

  @Resource
  private MessageRepository messageRepository;

  @Override
  @Transactional
  public Message create(Message event) {
    Message createdMessage = event;
    return messageRepository.save(createdMessage);
  }

我想知道为什么 messageRepository 的实例在 getNewMessage() 和 printWelcome() 方法中正确自动装配,但在覆盖的 onMessage() 方法中却没有。

编辑:

现在我将监听器和控制器分成两个不同的类。我有这个新课程:

public class RedisMessageListener implements MessageListener {

  @Autowired
  private MessageService messageService;

  @Override
  public void onMessage(Message message, byte[] paramArrayOfByte) {
    System.out.println(messageService==null);

    messageDeferredResultList.stream().forEach((deferredResult) -> {
        deferredResult.setResult(message);
    });
  }
}

但 messageService 始终为空。它只是一颗豆子!

【问题讨论】:

  • 你能添加堆栈跟踪吗? 我想知道为什么实例在这些方法中正确自动装配,但在覆盖方法中却没有?你自动连接messageRepository,它没有在覆盖方法中使用....
  • 对不起,我修改了我的问题。我添加了stacktrace:在onMessageMethod中messageRepository的实例为null,而在其他两个方法中它不是null,我不知道为什么。
  • 因为您自己创建了一个实例,所以该实例不是 bean。另外为什么你的控制器(与网络相关)也是一个监听器?恕我直言,这些应该是两件不同的事情。
  • 我不明白为什么在控制器内部 messageService 是正确自动装配的,但不是在侦听器类中。它只是公共类 MessageServiceImpl 实现 MessageService 之上的 Service 标记的 bean
  • 你现在在哪里创建 RedisMessageListener bean?

标签: java spring autowired


【解决方案1】:

好的,感谢@dunni,我找到了解决方案。我仍在自己创建 RedisMessageListener 的实例。允许 Spring 创建它(通过添加 @Component 注释)并将其注入到我创建 MessageListenerAdapter 的方法中,使用 @Autowired,我解决了这个问题。

【讨论】:

  • 你能解释一下吗
【解决方案2】:

@Vipul

这意味着您的 MessageListenerAdapter 配置由您自己而不是由 spring 创建一个 TaskEventSubscriber bean。

错误:

    @Bean
    MessageListenerAdapter taskEventListener() {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(new TaskEventSubscriber());
        return messageListenerAdapter;
    }

正确:


@Autowired
private TaskEventSubscriber taskEventSubscriber;


@Bean
    MessageListenerAdapter taskEventListener() {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(taskEventSubscriber);
        RedisSerializer stringSerializer = new StringRedisSerializer();
        messageListenerAdapter.setSerializer(stringSerializer);
        return messageListenerAdapter;
    }

(对不起,我不能评论)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    相关资源
    最近更新 更多