在编写多线程代码时,往往是通过自己调用 new 实例化出来的线程类(Thread或Runnable)来实现。这时 Spring 无法使用 Autowired
进行自动注入。
原因是在 Spring 中,Spring 只能自动注入由它自己管理(创建)的组件。
实际和多线程并没有太多的关系,但是可以放到一起来看。
示例一
如下代码,MyService 通过手动 new 实例化,因此 MyService 中的 MyRepository 无法通过 @Autowired 直接注入,会返回 null。(当然是这样)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Controller public class Controller {
@GetMapping("/example") public String example() { MyService my = new MyService(); my.doStuff(); } }
@Service public class MyService() {
@Autowired MyRepository repo;
public void doStuff() { repo.findByName( "steve" ); } }
@Repository public interface MyRepository extends CrudRepository<My, Long> {
List<My> findByName( String name ); }
|
示例二
如下代码,SpiderUrlMapper 无法直接注入到 VideoJob 实例中。会返回 null。
1 2 3 4 5 6 7 8 9 10 11 12
| ExecutorService executors = Executors.newFixedThreadPool(1); executors.execute(new VideoJob());
public class VideoJob implements Runnable {
@Autowired private SpiderUrlMapper spiderUrlMapper;
@Override public void run() { } }
|
解决方案一:通过构造函数
为 VideoJob 编写构造函数,在外部 new 的时候通过构造函数进行初始化
1 2 3 4 5 6 7 8 9 10 11 12
| public class VideoJob implements Runnable {
private final SpiderUrlMapper spiderUrlMapper; public VideoJob(SpiderUrlMapper spiderUrlMapper) { this.spiderUrlMapper = spiderUrlMapper }
@Override public void run() { } }
|
如果需要注入的对象很多,构造函数列表比较长,这样使用起来会比较麻烦。
解决方案二:通过 ApplicationContext
在对类实例化以后,手动把它注册到 Spring 容器中。
1 2 3 4 5
| @Autowired private ApplicationContext applicationContext;
VideoJob videoJob = new VideoJob(); applicationContext.getAutowireCapableBeanFactory().autowireBean(videoJob);
|