实现一个线程继承了Thread或实现Runnable接口,想在run方法中使用spring依赖注入(操作数据库),此时报错为空指针,就是说没有注入进来。
实验了几种方式,分别说一下优缺点。
1:写了工具类,实现ApplicationContextAware接口,做一个通过name获取实例的方式,代码如下:
1 public class SpringUtil implements ApplicationContextAware { 2 3 private static ApplicationContext ctx = null; 4 5 @Override 6 public void setApplicationContext(ApplicationContext applicationContext) 7 throws BeansException { 8 9 if (SpringUtil.ctx == null) { 10 SpringUtil.ctx = applicationContext; 11 } 12 } 13 14 public static ApplicationContext getCtx() { 15 return ctx; 16 } 17 18 public static Object getBean(String name) { 19 return getCtx().getBean(name); 20 } 21 22 23 }
这种方式有个缺陷,需要web容器相应之后才有值,也就说是懒加载了,线程如果比web容器先响应的时候还是为null值。
2:内部类,这个不多说了,实际上属于绕过去了,我自己认为这样写破坏了结构,也不好维护。
3:构造注入,我认为这个方式最好,注入类依旧被spring管理,代码结构简单清晰。
在线程中提供一个构造方法,比如(注意:public RecvThread(boolean flag, DBmapper dbMapper) ):
1 @Component("RecvThread") 2 public class RecvThread extends Observable implements Runnable { 3 4 private boolean flag; 5 6 private DBmapper dbMapper; 7 8 private QueueModel model; 9 10 private static HashMap<String, String> map = new HashMap<String, String>(); 11 12 public RecvThread() { 13 super(); 14 } 15 16 public RecvThread(boolean flag, DBmapper dbMapper) { 17 this.flag = flag; 18 this.dbMapper = dbMapper; 19 } 20 21 public void ob(){ 22 if(true){ 23 super.setChanged(); 24 } 25 notifyObservers(); 26 } 27 28 @Override 29 public void run() { 30 while (flag) { 31 try {
在启动线程的地方注入:
1 @Component("SystemStartBean") 2 public class SystemStartBean extends SpringBeanAutowiringSupport implements Servlet { 3 4 @Autowired 5 private DBmapper dbMapper; 6 7 @Override 8 public void init(ServletConfig arg0) throws ServletException { 9 10 RecvThread rt = new RecvThread(true, dbMapper); 11 rt.addObserver(new RecvThreadListener()); 12 new Thread(rt).start(); 13 }