Spring在多线程下@Resource注入为null

本文介绍了一个在使用WebMagic爬虫框架时遇到的Spring注入问题。当尝试在爬虫的process方法中通过@Autowired注解注入DAO实例时,发现该实例始终为null。经过排查,确定问题是由于WebMagic的多线程环境下与Spring容器不兼容导致。最终通过在process方法中手动通过ApplicationContext获取DAO实例解决了问题。

前情叙述

记录以下这个坑,我的情况大致是这样的,我在用webmagic写爬虫,在类中通过@Resoource(@Autowired也一样)注入dao接口实例。

然后我在process方法中引用这个实例发现这个实例在这里一直为null,然后我在测试类或者当前类的main函数中引用dao实例就没问题,一切正常(当时 黑人问号脸???)

几经波折,发现原因是spring和多线程安全的问题,不让注入。因为我也没研究过webmagic源码,不过我个人觉得跟webmagic没有与spring容器相关联可能很有关系,

解决方案

我用的是很简单暴力的方法,spring不让自动注入,那就手动注入呗,在process方法中通过ApplicationContext获取对应那个dao bean实例,然后可以了。

附上网上其它博客参考:spring 在Thread中注入@Resource失败,总为null的解决方案

<think>好的,用户想了解如何正确实现带有@Resource注解的ReceiveThread类,具体要求是@Service注解的ReceiveThread类实现Runnable接口,并使用@Resource注解的最佳实践。首先,我需要回忆一下Spring@Resource和@Service的作用。@Service用于标注服务层组件,而@Resource默认按名称注入,如果找不到再按类型注入。 接下来,用户可能希望这个ReceiveThread作为一个独立的线程运行,同时注入其他Spring管理的Bean。需要注意,实现Runnable接口的类需要被正确初始化和启动,可能需要通过@PostConstruct来启动线程,或者由其他组件管理线程的启动。 然后,考虑到线程安全的问题,特别是如果@Resource注入的Bean是否是线程安全的。例如,如果注入的是一个Service,而这个Service本身是无状态的,那么多线程中使用是安全的。如果有状态,可能需要同步机制。 另外,需要确保ReceiveThread类本身被Spring容器管理,所以必须添加@Component或@Service注解,并且要确保该类所在的包被组件扫描覆盖。同时,@Resource注解的字段是否需要setter方法?在字段注入的情况下,可能不需要,但最好还是使用构造器注入或者setter注入,不过@Resource可以直接放在字段上。 可能还需要考虑线程的生命周期管理,比如如何优雅地停止线程,避免内存泄漏。在示例代码中,可以使用一个volatile标志位来控制线程的运行状态,并在@PreDestroy方法中设置该标志位,确保应用关闭时线程能正确退出。 此外,用户可能需要知道如何测试这个类,是否需要在测试时启动Spring上下文,或者使用Mockito来模拟依赖。不过这可能超出了当前问题的范围,但作为最佳实践,可以简要提及。 最后,要提供一个完整的示例代码,展示如何正确使用@Service、@Resource,并实现Runnable接口,同时包括线程的启动和停止机制。还要注意代码中的异常处理和资源释放,确保程序的健壮性。</think>### 带@Resource注解的ReceiveThread实现步骤 #### 1. 基础类定义 使用`@Service`标注实现类,明确线程运行控制逻辑: ```java @Service public class ReceiveThread implements Runnable { @Resource // 默认按名称匹配,可指定name属性 private MessageService messageService; private volatile boolean running = true; @Override public void run() { while (running) { messageService.processMessages(); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } @PreDestroy public void shutdown() { running = false; } } ``` #### 2. 线程生命周期管理 建议通过`TaskExecutor`管理线程池: ```java @Service public class ThreadStarter { @Resource private ReceiveThread receiveThread; @PostConstruct public void init() { new Thread(receiveThread).start(); } } ``` #### 3. 最佳实践 1. **依赖注入选择**:优先使用`@Autowired`按类型注入,需要按名称时用`@Resource(name="beanName")` 2. **线程安全保证**:注入的`MessageService`应设计为无状态或使用ThreadLocal 3. **异常处理**:在run()方法中添加try-catch块捕获所有异常 4. **配置验证**:确保组件扫描包含当前类包(在`@SpringBootApplication`或XML配置中) ### 完整示例 ```java @Service public class ReceiveThread implements Runnable { @Resource(name = "jmsMessageService") private MessageService messageService; private volatile boolean running = true; @Override public void run() { while (running && !Thread.currentThread().isInterrupted()) { try { Message msg = messageService.receive(); if (msg != null) { processMessage(msg); } } catch (JMSException ex) { log.error("消息接收异常", ex); } } } private void processMessage(Message msg) { // 业务处理逻辑 } @PreDestroy public void cleanUp() { running = false; messageService.close(); } } ``` ### 关键注意事项 1. **循环依赖**:避免@Resource注入产生循环依赖(启动时抛出BeanCurrentlyInCreationException) 2. **代理机制**:AOP代理可能影响字段注入,建议使用接口编程 3. **上下文隔离**:线程内访问的Spring Bean需要是原型作用域或线程安全的[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值