场景:
怎么会想到这个题目的呢,最近开发中遇到了一个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) └─────┘