0%

Spring 多线程下自动注入

在编写多线程代码时,往往是通过自己调用 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);