Spring的ApplicationContext未正确注入
背景:
现在做的一个项目分为三个子工程。一个是控制层,主要有Action和JSP,另外一个为服务层,主要有Service, DAO和MyBatis Mapping File。为了解耦这2个工程,抽取这2个工程里共用的类放到另外一个工程。其中控制层部署在tomcat上,服务层部署在weblogic平台,两层之间通过RMI来调用。每次新加功能,都要很麻烦地加RMI层,还要改配置文件,更要命的是,RMI的性能可能比JVM直接调用要差一些。在性能调优期间,我们尝试合并3个工程,消除RMI层,将所有的程序部署在weblogic平台。
另外,我们项目用到的技术框架有:Struts2.0, Spring3.0, Mybatis, JAX-WS,Quartz等。
问题描述:
合并3层完毕,在本地(Tomcat)测试无误后,上传应用到服务器(Weblogic平台),Quartz job在运行的时候报如下的错误:
1 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'taskSchedulerJob' defined in ServletContext resource [/WEB-INF/classes/spring/quartz/quartz.xml]: Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError
2 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:946)
3 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:892)
4 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
5 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
6 at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
7 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
8 ..................................................................................
9 at com.oracle.weblogic.wsee.wrapper.org.springframework.web.context.ContextLoaderListener.contextInitialized(Unknown Source)
10 ..................................................................................
11 Caused by: java.lang.NullPointerException
12 at com.SpringUtil.getBean(SpringUtil.java:11)
13 at com.TaskScheduler.<clinit>(TaskScheduler.java:29)
报错的类的源代码如下:
1 public class SpringUtil implements ApplicationContextAware {
2
3 private static ApplicationContext applicationContext;
4
5 @Override
6 public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
7 this.applicationContext = applicationContext;
8 }
9
10 public static Object getBean(String beanName) {
11 return applicationContext.getBean(beanName);
12 }
13
14 }
其中 SpringUtil这个类作为一个Spring Bean在business.xml里定义。Quartz job在quartz.xml里定义。
问题分析:
从错误日志来看,应该是 applicationContext 未注入导致的。奇怪了,在tomcat下运行好好的,到weblogic下又有问题,难道又是weblogic的bug(本人前段时间遇到了一个weblogic的bug,真是杯弓蛇影啊。。。)。经分析,怀疑是由于加载spring配置文件顺序引起的。立马开始验证。对比tomcat启动时加载spring配置文件的顺序和weblogic下的加载顺序,发现的确有所差别。在tomcat下,加载顺序为business.xml,然后是quartz.xml。weblogic下则相反。
如果bean之间有依赖关系,spring应该会自动管理bean配置文件的加载顺序,但由于Quartz job调用的是SpringUtil的静态方法,所以在business.xml没有加载的情况下,applicationContext没能注入。
解决办法:
解决办法是在web.xml里指定spring配置文件的加载顺序。
另外,在消除RMI层后,系统在500个并发下,频繁调用RMI层的业务场景的性能提高了30%左右。