springのbeanはマルチスレッドに注入する問題です。
問題の説明
springでは,非同期スレッドにビーンを注入する必要があると,ビーンが空であることが分かった。なぜなら、スプリング・バーはスレッドの安全を考慮して、ベアンからスレッド類に注入してはいけないからだそうです。コードは以下の通りです
解決方法
Spring APIにはApplication ContactixtAwareというインターフェースがあり、このインターフェースの種類を実現し、容器初期化完了中に容器を獲得することができ、容器中のすべてのbeanを獲得することができます。
上記のコードには
springでは,非同期スレッドにビーンを注入する必要があると,ビーンが空であることが分かった。なぜなら、スプリング・バーはスレッドの安全を考慮して、ベアンからスレッド類に注入してはいけないからだそうです。コードは以下の通りです
public class DealThreadTask implements Runnable{
@Autowired
private DealService dealService;
@Override
public void run() {
// DealService dealService=holder.getBean("dealService");
System.out.println("dealService-->"+dealService);
dealService.deal("andy", " ", 100d);
}
}
controller層では、上記のserviceを呼び出します。
public static void main(String[] args){
ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/applicationContext-aware.xml");
DealThreadTask task=new DealThreadTask();
new Thread(task).start();
}
実行結果:dealService-->null
Exception in thread "Thread-1" java.lang.NullPointerException
at com.test.spring.tx.multi.DealThreadTask.run(DealThreadTask.java:38)
at java.lang.Thread.run(Thread.java:744)
springはDealThreadTaskにdealServiceを注入できなかったと説明します。解決方法
Spring APIにはApplication ContactixtAwareというインターフェースがあり、このインターフェースの種類を実現し、容器初期化完了中に容器を獲得することができ、容器中のすべてのbeanを獲得することができます。
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHolder.applicationContext=applicationContext;
System.out.println("applicationContext---->"+applicationContext);
}
public static T getBean(Class clazz){
return applicationContext.getBean(clazz);
}
public static T getBean(String name) {
if (applicationContext==null) {
System.out.println("applicationContext ");
}
return (T) applicationContext.getBean(name);
}
}
その後、xmlプロファイルには、このクラスを配置する必要があります。<bean id="applicationContextHolder" class="com.test.spring.tx.multi.ApplicationContextHolder">bean>
このように、非同期スレッド中のDealThreadTaskでは、マニュアルのappication Contactext HolderのgetBean方法により、必要なbeanを取得することができる。public class DealThreadTask implements Runnable{
@Autowired
private ApplicationContextHolder holder;
@Override
public void run() {
DealService dealService=holder.getBean("dealService");
System.out.println("dealService-->"+dealService);
dealService.deal("andy", " ", 100d);
}
}
ヒント上記のコードには
public static void main(String[] args){
ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/applicationContext-aware.xml");
DealThreadTask task=new DealThreadTask();
new Thread(task).start();
}
junnitのtestコメントを使ってテストを行っていないのは、junnitが非同期スレッドの実行を待って終了するのではなく、junit自身の本スレッドのコードが実行されたら終了するからです。コードの中にデータベース操作が設計されていますので、簡単にjunnitでテストすれば、テストは完了しますが、データベース操作はまだ行われていません。junnitでテストをしたいなら、他の手段でthreadのjun操作やjunnitのテスト方法でキーボード入力を待って終わってもいいです。これらはすべて非同期スレッドを実行してからjunnitテストを終了するためです。