多线程中Spring注入为null

/ 技术 / 无站内评论 / 1285浏览

背景:

在实际项目中,多线程执行任务,在继承了extends Thread的线程类中,如果想通过spring注入bean,不管是@Resource还是@Autowired,在用多线程注入Spring的时候,注入的实例在调用时总是显示为null。

解决方案

内部类

//实现ApplicationListener<ContextRefreshedEvent>接口重写onApplicationEvent方法,在spring容器初始化的时候执行多线程任务
public class SchedulerCenter implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger logger = LoggerFactory.getLogger(TgqSchedulerCenter.class);

     //要注入的bean
    @Autowired
    private TaskInfoDao taskInfoDao;


    private List<SchedulerTask> schedulerWorks = Lists.newArrayList();

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
     // 最大核心线程
        int SchedulerMaxThread = 10;
        for (int i = 0; i < SchedulerMaxThread ; i++) {
            //继承Thread的SchedulerTask类(任务类)
            SchedulerTask schedulerTask = new SchedulerTask();
            schedulerTask.start();
            schedulerWorks.add(schedulerTask);
        }
}
class SchedulerTask extends Thread {

    @Override
    public void run() {
    //这里可以使用调用在SchedulerCenter类中注入的bean
      taskInfoDao.xxx();
      //dosomething
      }
}

将实例传入线程

将实例传入线程,实例多的时候会死人的(⊙o⊙)…

//实现ApplicationListener<ContextRefreshedEvent>接口重写onApplicationEvent方法,在spring容器初始化的时候执行多线程任务
public class SchedulerCenter implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger logger = LoggerFactory.getLogger(SchedulerCenter.class);

     //要注入的bean
    @Autowired
    private TaskInfoDao taskInfoDao;



    private List<SchedulerTask> schedulerWorks = Lists.newArrayList();

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
     // 最大核心线程
        int SchedulerMaxThread = 10;
        for (int i = 0; i < SchedulerMaxThread ; i++) {
            //这里将实例传递到SchedulerTask中
            SchedulerTask schedulerTask = new SchedulerTask(taskInfoDao);
            schedulerTask.start();
            schedulerWorks.add(schedulerTask);
        }
}

public class SchedulerTask extends Thread {
private TaskInfoDao taskInfoDao;
//通过构造传入
public SchedulerTask(TaskInfoDao taskInfoDao){
this.taskInfoDao=taskInfoDao;
}
    @Override
    public void run() {
    //这里可以使用调用在SchedulerCenter类中注入的bean
      taskInfoDao.xxx();
      //dosomething
      }
}

set注入

将多线程用到的实例进行全局化,即加static,这样就将实例提升到了进程的级别,两个线程都可以使用。

如下:
protected static TaskInfoDao taskInfoDao;
@Autowired 或 @Resource
publicvoid setTaskInfoDao (TaskInfoDao taskInfoDao) {
     SchedulerTask.taskInfoDao= taskInfoDao;
}

Tips: 1、实例加static; 2、提供set方法即可; 3、set方法去掉static; 4、如果只将实例static,而未提供非static的set方法,用Resource会报异常@Resource annotation is not supported on static fields。

其他

就是让我的service或者dao的实现类实现Runnable这个接口,然后把你的线程的逻辑写在run方法里,启动的时候,直接this.start()就行。注意除了要在service的实现类中实现Runnable接口外,还应该在service接口中继承Runnable接口。

对于我的情况,我是直接在dao里实现了Runnable,然后用的线程池启动的,如下:pool.execute(this);

还有就是直接new一个实例。

ApplicationListener

在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载、初始化缓存、特定任务的注册等等。这个时候我们就可以使用Spring提供的ApplicationListener来进行操作。

用法

本文使用为例来进行说明。需要实现ApplicationListener接口并实现onApplicationEvent方法。把需要处理的操作放在onApplicationEvent中进行处理

总结

优先推荐使用内部类方式>任务类实例化时传入>set注入

参考资料: https://yq.aliyun.com/articles/36814

https://blog.csdn.net/lihu0512/article/details/50935892

https://blog.csdn.net/wo541075754/article/details/71720984

召唤蕾姆
琼ICP备18000156号

鄂公网安备 42011502000211号