Spring注解【非单例】

花了至少一整天的时间解决了这个问题,必须记录这个纠结的过程,问题不可怕,思路很绕弯。

为了能说清楚自己的问题,我都用例子来模拟。

我有一个类MyThread是这样的:

1 @Service
2 public class MyThread extends Thread {
3 @Autowired
4 MyService myService;
5 ......
6 }

在主线程中有这样一个调用:

1 @Autowired
2 MyThread myThread;
3 ......
4 public void invoke{
5   if(condition){
6     myThread.start();
7   }  
8 }
9 ......

我的invoke存在一个循环调用,此时遇到了第一个问题!

问题一:抛出java.lang.IllegalThreadStateException。

问题一的解决:

1 //@Autowired
2 //MyThread myThread;
3 ......
4 public void invoke {
5   if(condition){
6 //myThread.start();
6 MyThread myThread = new MyThread(); 7 myThread.start(); 8 } 9 }

引发的新的问题!

问题二:我用了Spring注解,用new的话无法用注解实现注入,所以myThread中的myService对象抛出空指针。

问题二的解决:放弃了MyThread类,新写了一个类,开始绕弯。

1 @Service
2 public class MyRunable implements Runnable {
3   @Autowired
4   MyService myService;
5   ......
6 }

相应的,修改主线程中的调用。

 1  //@Autowired
 2  //MyThread myThread;
 3  @Autowired
 4  MyRunnable myRunnable;
 5  ......
 6  public void invoke{
 7    if(condition){
 8      //MyThread myThread = new MyThread();
 9      //myThread.start();
10      Thread t = new Thread(myRunnable);
11      t.start();
12    }  
13  }
14  ......

又遇到了新的问题!

我需要对myRunnable线程命名。即在invoke方法中增加这么一行:

1 ......
2 myRunnable.setName(name);//增加的一行
3 Thread t = new Thread(myRunnable);
4 ......

问题三:后面命名的myRunnable线程名称竟然覆盖前面的命名。

打印myRunnable对象,很容易判断出来这个对象是单例模式,所以每次改动都会影响以前的调用。

查了Spring的相关资料,得到结论,Spring默认管理类的模式就是“单例模式”,我需要改成非单例的。

尝试改动一:

1 //增加了对象使用创建模式的注解
2 @Service
3 @Scope("prototype")
4 public class MyRunable implements Runnable {
5   @Autowired
6   MyService myService;
7   ......
8 }

运行,问题依旧。然后就卡住了,甚至评估放弃Spring?一路new下去得了……

直到某一刻灵光闪现,发现虽然现在MyRunnble是非单例模式,但是在invoke的那个类中,Spring只在加载这个类时初始化了一个MyRunnable对象啊……

问题三的解决:

 1    //@Autowired
 2    //MyThread myThread;
 3    //@Autowired
 4    //MyRunnable myRunnable;
 5    ......
 6    public void invoke{
 7      if(condition){
 8        //MyThread myThread = new MyThread();
 9        //myThread.start();
10        MyRunnable myRunnable = SpringContextUtil.getApplicationContext().getBean("myRunnable",MyRunnable.class);
11        Thread t = new Thread(myRunnable);
12        t.start();
13     }  
14   }
15   ......

这一步需要声明的是SpringContextUtil类有时间需要单独写一篇,先理解原理,就是每次从Spring容器中生成一个全新[scope("prototype")]的对象。

到这里,问题全部解决了……等等!

感觉MyThread类被抛弃好无辜啊!最终改成了这个样子的:

1 MyThread myThread = SpringContextUtil.getApplicationContext().getBean("myThread", MyThread.class);
posted @ 2016-03-10 14:54  一沙世界  阅读(12435)  评论(0编辑  收藏  举报