零、先抛结论
该异常抛出只是连锁反应的一环,是表象结果而不是根本原因,追着日志向上查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 !!!!!! } }
以上。