Spring ApplicationContext装载的问题在网上已经讨论过很多,分析也很详细了。前两天在配置Weblogic WorkManager的时候,发现了一个特别的问题,花了好半天才解决。
具体场景如下:
1。 一个package中包含了两个ejb文件(work1.ejb.jar, work2.ejb.jar)和一个war文件(work.war)。
2。 work1.ejb.jar和work.war需要用同一个workmanager。这个workmanager定义在work1.ejb.jar的weblogic-ejb-jar.xml里。
<work-manager> <name>wm/Parallel_WorkManager</name> <min-threads-constraint> <name>parallel_minthreads</name> <count>1</count> </min-threads-constraint> <max-threads-constraint> <name>parallel_maxthreads</name> <count>100</count> </max-threads-constraint> </work-manager>3。 在work1.ejb.jar对workManager的引用有如下两种方式:
【applicationContext.xml中引用】
<bean id="producerInnerImpl" class="eventnotification.producer.ProducerInnerImpl"> <constructor-arg index="0"> <ref bean="workManager" /> </constructor-arg> </bean> <bean id="workManager" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>java:comp/env/wm/EventNotifiactionWorkManager</value> </property> </bean>【程序中直接调用】
InitialContext ic = new InitialContext(); WorkManager wm = (WorkManager)ic.lookup("java:comp/env/wm/Parallel_WorkManager");
4。 在work.war中,也需要使用上述的workmanager,于是在war的applicationContext.xml中做了同样的定义:
<bean id="producerInnerImpl" class="eventnotification.producer.ProducerInnerImpl"> <constructor-arg index="0"> <ref bean="workManager" /> </constructor-arg> </bean> <bean id="workManager" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>java:comp/env/wm/EventNotifiactionWorkManager</value> </property> </bean>
因为在applicationContext里设置了default-lazy-init="true",所以安装的时候,没有任何问题,但是到了真正运行时, work.war就找不到workmanger了。
找了半天原因, 终于发现问题就在war的applicationContext.xml里,java:comp/env/wm/Parallel_WorkManager是基于上下文的引用,因此war通过java:comp/env/wm/Parallel_WorkManager的方式,访问不到ejb里的resource (workmanage)。
解决办法:让war直接访问ejb的applicationContext.xml所创建的bean。
ejb的applicationContext.xml的配置不变,beanRefFactory.xml的定义如下 (放在META-INF目录之外)
<bean id="spring.ejbContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>/applicationContext.xml</value> </list> </constructor-arg> </bean>war的applicationContext.xml里不配置workmanager,直接用work1.ejb.jar里的bean,将war的applicationContext.xml改名成webApplicationContext.xml,和beanRefFactory.xml一起放在WEB-INF/classes里(注意不放在WEB-INF),beanRefFactory.xml的定义如下
<bean id="web" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>webApplicationContext.xml</value> </list> </constructor-arg> <!-- if we want to combine with the application context in the ejb layer as the parent context.--> <constructor-arg> <ref bean="spring.ejbContext"/> </constructor-arg> </bean>
war里的spring容器访问不需要直接访问workmanager,只需要通过ejb的spring context就可以获取到workmanager的bean了。
几个需要注意的问题:
1。war的applicationContext.xml和beanRefFacotry.xml的存放地点。
2。定义beanRefFacotry.xml,让war的直接使用ejb的bean。