有时候在spring项目中可能会遇到依赖的属性没有被注入,这个时候可能有很多原因。spring默认是单例的,通常注入的时候我们使用比较多的是@Autowired,这个注解默认按照类型注入(同时会处理依赖关系)。
当没有注入的时候,即使用的时候值为null ,会报空指针异常 ,需要查看此属性的bean 有没有被spring初始化并管理,比如bean有没有被扫描到,或者配置。
今天这这里我研究的是另一种情况,Thread中注入Bean
在Spring项目中,有时需要新开线程完成一些复杂任务,而线程中可能需要注入一些服务(例如此新开的线程需要将得到的数据写入数据库等)。而通过Spring注入来管理和使用服务是较为合理的方式。但是若直接在Thread子类中通过注解方式注入Bean是无效的。@Resource或者@Autowired注入全部为NULL,
因为Spring本身默认Bean为单例模式构建,同时是非线程安全的,因此禁止了在Thread子类中的注入行为,因此在Thread中直接注入的bean是null的,会发生空指针错误。
错误代码X------这里的ywBuildingService 是不能被注入的
@Service
public class GuanLinSyncQueue implements Runnable {
private Logger logger = Logger.getLogger(GuanLinSyncQueue.class);
private static final String qianchuanCommunityCode = Global.getConfig("qianchuanCommunityCode");
@Autowired
private YwBuildingService ywBuildingService;
@PostConstruct
public void init() {
Thread thread = new Thread(new GuanLinSyncQueue());
thread.start();
}
@Override
public void run() {
ywBuildingService.save(ywBuildingPojo)
}
}
对于此有如下两种解决方法:
- 将需要的Bean作为线程的的构造函数的参数传入
- 将线程类作为服务类的内部类,Thread或者Runnable均可
方案1:
对于第一种方法,需要将要用到的bean 全部当作线程类的属性,如果bean数量少,也比较方便。注意这个线程类中引入了 ywBuildingService 这个属性。并且在GuanLinSyncQueue 这个可以被spring 管理的bean中注入 ywBuildingService 并通过构造函数 将ywBuildingService 传给了MyThread
public class MyThread implements Runnable {
private Logger logger = Logger.getLogger(GuanLinSyncQueue.class);
private static final String qianchuanCommunityCode = Global.getConfig("qianchuanCommunityCode");
private YwBuildingService ywBuildingService;
//构造方法 传入spring 容易 中的 ywBuildingService
public MyThread(YwBuildingService ywBuildingService) {
super();
this.ywBuildingService = ywBuildingService;
}
@Override
public void run() {
ywBuildingService.save(ywBuildingPojo)
}
}
------------------------------------------分割线--------------------------------
@Service
public class GuanLinSyncQueue{
private Logger logger = Logger.getLogger(GuanLinSyncQueue.class);
private static final String qianchuanCommunityCode = Global.getConfig("qianchuanCommunityCode");
@Autowired
private YwBuildingService ywBuildingService;
@PostConstruct
public void init() {
Thread thread = new Thread(new MyThread(ywBuildingService));
thread.start();
}
}
方案2:推荐方案!!!将线程类作为服务类的内部类,可以方便直接使用外部类中注入的bean.
@Service
public class GuanLinSyncQueue{
private Logger logger = Logger.getLogger(GuanLinSyncQueue.class);
private static final String qianchuanCommunityCode = Global.getConfig("qianchuanCommunityCode");
@Autowired
private YwBuildingService ywBuildingService;
@PostConstruct
public void init() {
new worker().start();
}
private class worker extends Thread{
@Override
public void run() {
//做自己想做的事情
ywBuildingService.save(ywBuildingPojo);
}
}
}