诡异的SPRING IOC容器
SPRING已经几乎成为我们日常开发必不可少的框架了,它对IOC以及AOP思想的实现得到了广泛的认可和推崇。
IOC作为一个容器,管控了大部分运行期的JAVA对象,由于IOC的高可配置性,使得传统的JAVA工厂模式,单例模式几乎不再出现于代码中。
然而本文的标题何故冠以诡异二字,这还得从一次项目组遇到的问题说起。
这个项目不无例外地使用了SPRING框架。然而在应用启动一段时间后,原本运行中没问题的一些对象,会忽然“无故”地报错找不到,出现Spring容器getBean失败。而这些对象在应用重启以后又是可以找到的!这使得项目组的同事百思不得其解。而且出现这些对象不见的时机也很蹊跷,时而隔天出现,时而隔一小时就报错。
此时,传说中的神器SPRING仿佛成了一个难以捉摸的幽灵,IOC容器则成了一个黑洞,时不时地把对象给吞了,不得不说诡异二字。真的是这样么,我们展开了一番排摸。
我们发现,当出现对象找不到的情况时,去获取这些对象用的是一个ApplicationContextUtil工具类,这个工具类继承实现了Spring的ApplicationContextAware,并且注册到IOC的配置XML里,按照SPRING的加载机制,会自动把ApplicationContext交到ApplicationContextUtil手里。而这次,这个工具好像出问题了。
同时我们又发现,在这种情况下,使用WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)来获取ApplicationContext的时候,这些丢失的类都还在里面!
至此,问题是不是变得更为扑朔迷离?还是渐渐有了头绪?
这种情况下,感觉可能是运行期存在了多个IOC容器。经过代码排查,果然发现在这个项目引用JAR包的一个工具类里,存在这样的写法:
private static final String CONTEXT_FILE_NAME = "/applicationContext-service.xml";private static ApplicationContext fac=null;public AdapterServiceFactory(String str) {fac = new ClassPathXmlApplicationContext(CONTEXT_FILE_NAME);((AbstractApplicationContext) fac).registerShutdownHook();this.serviseName=str;}也就是说,一旦利用这个工具获取对象,就会产生一个额外的IOC容器。