零、先拋結論
該異常拋出只是連鎖反應的一環,是表象結果而不是根本原因,追着日志向上查spring是否之前就拋出了其他異常。而正是這些更早的異常導致spring不能符合預期的工作。
一、現象
服務可以正常啟動,在調用某些服務的時候必拋出如下異常。google查找若干,多數情況下是啟動時報錯,而不是運行時,所有未找到契合的先例。測試等了半天問啥時候可以解決,只能硬着頭皮說,先繞過觀察下其他用例是否正常,正是其他用例暴露出了bug的尾巴。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBean'
defined in com.org.my.BeanContainer: BeanPostProcessor before instantiation of bean failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.cache.annotation.ProxyCachingConfiguration':
Initialization of bean failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available
二、bug的尾巴
這個狐狸的尾巴正是下面這個異常,說明springContext有問題啊,異常說沒有refresh,那是不是applicationContext.refresh()拋異常了呢。
java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@149e0f5d has not been refreshed yet at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1068) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1092) at com.my.Engine.execute(Engine.java:84)
三、按圖索驥
果然在日志里向上翻到了,AbstractApplicationContext.refresh()方法的異常日志。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // ...... refresh stuff blabla } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
四、揪出真凶
這行日志Exception encountered during context initialization...... 會打印出具體哪個業務Bean發生了初始化錯誤。最后發現原因是被@PostConstruct注解的一個方法拋出了異常,進而影響了整個SpringContext的初始化。
@Component public class ReportTask { @Autowired private MyService myService; @PostConstruct public void afterPropertiesSet() throws Exception { // throw exception here UNEXPECTED !!!!!! } }
以上。