背景:
在实际项目中,多线程执行任务,在继承了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
本文由 SAn 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2018/04/25 18:40