背景:
現在做的一個項目分為三個子工程。一個是控制層,主要有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%左右。
