`

NPE联想到的spring bean的生命周期

 
阅读更多

 

    场景:

      怎么会想到这个题目的呢,最近开发中遇到了一个NPE问题,后来查下去觉得挺有意思,所以就拿出来分享下。code 如下。

 

public class Service{
    
    @Resource(name = "xxx")
    private ConfigService disconf;

    private loginEventThreadPool = new ThreadPoolExecutor(
	2, disconf.getMaxThread(), ThreadPool.THREAD_POOL_WAIT_SECONDS, TimeUnit.SECONDS, 
        new ArrayBlockingQueue<Runnable>(2000), new ThreadPoolExecutor.AbortPolicy()
    );
}

 

    探索一,看这个问题肯定是disconf没有初始化进去了,试试在构造函数里面看看能不能初始化吧,尼玛还是NPE。

   

public class Service{
    
    @Resource(name = "xxx")
    private ConfigService disconf;

    private loginEventThreadPool = null;

    public Service() {
      loginEventThreadPool = new ThreadPoolExecutor(
	 2, 10, ThreadPool.THREAD_POOL_WAIT_SECONDS, TimeUnit.SECONDS, 
         new ArrayBlockingQueue<Runnable>(2000), new ThreadPoolExecutor.AbortPolicy()
      );
    }
}

 

    探索二,好像有个叫init的方法,但是尼玛要在xml中配置,太麻烦了,我是注解控啊,不喜欢配置。

 

    探索三, 依赖spring的生命周期InitializingBean 在spring bean设置完后才执行方法,搞定。

    

public class Service{
    
    @Resource(name = "xxx")
    private ConfigService disconf;

    private loginEventThreadPool = null;

    @OverRide
    public void afterPropertiesSet() throws Exception {
      loginEventThreadPool = new ThreadPoolExecutor(
	 2, 10, ThreadPool.THREAD_POOL_WAIT_SECONDS, TimeUnit.SECONDS, 
         new ArrayBlockingQueue<Runnable>(2000), new ThreadPoolExecutor.AbortPolicy()
      );
    }
}

 

    问题:通过这个问题我可以去了解哪些东西

      1. 属性和构造器的执行顺序

      2. spring的生命周期

      3. 记得以前来面试的时候高老师问过我循环依赖的问题,也是该主题的啊,顺便一起研究下。

 

   结论:

     1. 类先设置属性,然后执行构造器的方法 。

 

     对象new 出来后再查询field 为2 ,即使field字段放在构造函数之后也是一样。

public class MyObject {

    private int fileld = 1;

    public MyObject() {
        fileld = 2;
    }
    
    public int getFileld() {
        return fileld;
    }
}

 

    2.   spring的生命周期 参照http://www.cnblogs.com/caoyc/p/5624417.html

 

    从文档中可以看出spring bean属性设置是在构造器执行之后,但是一般属性是在构造器之前。所以执行顺序是一般属性(loginEventThreadPool) --> 构造器 --> spring bean属性。所以也就验证了为啥前两个场景报NPE的错误。

 

    3. 循环依赖,如果构造器不依赖则正常初始化,构造器依赖则初始化失败。

 

      从第二个结论的链接可以看出初始化和设置spring bean是分开的。如果A 构造器不依赖于B,则A B都能实例化,实例化之后也就可以做下面的spring bean属性设置了。

    

@Component("beanA")
public class BeanA{

    @Autowired
    private BeanB beanB;

    public BeanA(BeanB beanB) {

    }
}

@Component
public class BeanB {

    @Autowired
    private BeanA beanA;

}

// 报错如下,这图太形象了,NB
┌─────┐
|  beanA defined in file [/xxx/classes/com/spring/model/BeanA.class]
↑     ↓
|  beanB (field private com.spring.model.BeanA com.spring.model.BeanB.beanA)
└─────┘

 

 

 

 

 

0
0
分享到:
评论
2 楼 labreeze 2017-02-14  
szq80140 写道
@PostConstruct 也可以

试了下果然可以,也能获取到注入的bean,学习了。
1 楼 szq80140 2017-02-14  
@PostConstruct 也可以

相关推荐

Global site tag (gtag.js) - Google Analytics