论坛首页 Java企业应用论坛

Hibernate/Spring/Struts架构使用OpenSessionInView的问题

浏览 83289 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-08-03  
今天有一个朋友问了我一个问题,他使用的是Hibernate/Spring/Struts架构,配置使用Spring的OpenSessionInView Filter,但是发现不生效,lazy的集合属性在页面访问的时候仍然报session已经关闭的错误。我和他一起检查了所有的配置和相关的代码,但是没有发现任何问题。经过调试发现,应用程序使用的Session和OpenSessionInView Filter打开的Session不是同一个,所以OpenSessionInView模式没有生效,但是为什么他们不使用同一个Session呢?

检查了一遍Spring的相关源代码,发现了问题的根源:

通常在Web应用中初始化Spring的配置,我们会在web.xml里面配置一个Listener,即:

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>


如果使用Struts,那么需要在Struts的配置文件struts-config.xml里面配置一个Spring的plugin:ContextLoaderPlugIn。

实际上ContextLoaderListener和ContextLoaderPlugIn的功能是重叠的,他们都是进行Spring配置的初始化工作的。因此,如果你不打算使用OpenSessionInView,那么你并不需要在web.xml里面配置ContextLoaderListener。

好了,但是你现在既需要Struts集成Spring,又需要OpenSessionInView模式,问题就来了!

由于ContextLoaderListener和ContextLoaderPlugIn功能重叠,都是初始化Spring,你不应该进行两次初始化,所以你不应该同时使用这两者,只能选择一个,因为你现在需要集成Struts,所以你只能使用ContextLoaderPlugIn。

但是令人困惑的是,ContextLoaderListener和ContextLoaderPlugIn有一个非常矛盾的地方!

ContextLoaderListener初始化spring配置,然后把它放在ServletContext对象里面保存:

servletContext.setAttribute(
					WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);;


请注意,保存的对象的key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE!

但是ContextLoaderPlugIn初始化spring配置,然后把它放在ServletContext对象里面保存:

String attrName = getServletContextAttributeName();;
getServletContext();.setAttribute(attrName, wac);;


这个attrName和WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE名字是不一样的!

如果仅仅是名字不一样,问题还不大,你仍然可以放心使用ContextLoaderPlugIn,但是当你使用OpenSessionInView的时候,OpenSessionInViewFilter是使用哪个key取得spring配置的呢?

WebApplicationContext wac =
				WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext(););;


显然,OpenSessionInViewFilter是按照WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE这个key去拿spring配置的!

我们整理一下思路:

ContextLoaderPlugIn保存spring配置的名字叫做attrName;
,ContextLoaderListener保存spring配置的名字叫做WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
而OpenSessionInView是按照WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE这个名字去取得spring配置的!
而你的应用程序却是按照attrName去取得spring的配置的!

所以,OpenSessionInView模式失效!

解决办法:
修改ContextLoaderPlugIn代码,在getServletContext().setAttribute(attrName, wac);这个地方加上一行代码:
getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);

或者修改OpenSessionInViewFilter,让它按照attrName去取得spring配置。
   发表时间:2005-08-04  
我原来用struts/spring/hibernate的时候同样使用OpenSessionInView,但是似乎没有robbin所说的问题啊。而且我在使用的时候,是ContextLoaderListener和ContextLoaderPlugIn一起用的。整个配置如下:
1.首先是web.xml
	<filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

......


2. 然后是struts-config.xml:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
	<set-property property="contextConfigLocation" 
				  value="/WEB-INF/action-servlet.xml" 
	/>
</plug-in>


其余部分省略。

在上述配置下,使用OpenSessionInView似乎没有问题。

不知道robbin所说的ContextLoaderListener和ContextLoaderPlugIn不应该同时使用是不是做得是如下的配置:(struts-config.xml)

<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml,
/WEB-INF/action-servlet.xml"/>
</plug-in>


我尝试了一下,用这种配置时,OpenSessionInView的确失效了。

我猜想,原因大概是这样:struts的这个plugIn,可能只是为了整合一个action-servlet.xml,将action-servlet.xml中的定义当作Spring的bean来使用,因此,在保存时,只要有action-servlet.xml的配置,就被保存到robbin所提到的那个attrName中,而不是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE中,所以,OpenSessionInView是取不到这个配置的。

那么这个配置什么时候被取到呢?直觉告诉我,可能是和Action的Proxy有关。于是,查看了org.springframework.web.struts.DelegatingActionProxy的源码,果然:
/**
	 * Return the delegate Action for the given mapping.
	 * <p>The default implementation determines a bean name from the
	 * given ActionMapping and looks up the corresponding bean in the
	 * WebApplicationContext.
	 * @param mapping the Struts ActionMapping
	 * @return the delegate Action
	 * @throws BeansException if thrown by WebApplicationContext methods
	 * @see #determineActionBeanName
	 */
	protected Action getDelegateAction(ActionMapping mapping); throws BeansException {
		WebApplicationContext wac = getWebApplicationContext(getServlet();, mapping.getModuleConfig(););;
		String beanName = determineActionBeanName(mapping);;
		return (Action); wac.getBean(beanName, Action.class);;
	}

	/**
	 * Fetch ContextLoaderPlugIn's WebApplicationContext from the
	 * ServletContext, containing the Struts Action beans to delegate to.
	 * @param actionServlet the associated ActionServlet
	 * @param moduleConfig the associated ModuleConfig
	 * @return the WebApplicationContext
	 * @throws IllegalStateException if no WebApplicationContext could be found
	 * @see DelegatingActionUtils#getRequiredWebApplicationContext
	 * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
	 */
	protected WebApplicationContext getWebApplicationContext(
			ActionServlet actionServlet, ModuleConfig moduleConfig); throws IllegalStateException {
		return DelegatingActionUtils.getRequiredWebApplicationContext(actionServlet, moduleConfig);;
	}


仔细看其中的取wac的代码,它并不是从WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE取的wac。

由此,我相信,除了robbin讲的修改源码以外,同时使用ContextLoaderListener和ContextLoaderPlugIn,但是不要在ContextLoaderPlugIn里面加入applicationContext.xml,只要加入你的action-servlet.xml,我相信,同样也可以非常流畅的使用OpenSessionInView
15 请登录后投票
   发表时间:2005-08-04  
有道理,应该是这样的。
0 请登录后投票
   发表时间:2005-12-16  
我也遇到了上面说的openSessionInView不起作用的问题(web.xml既定义了listener,也定义了struts plugin),我想问一下,上面提到的action-servlet.xml到底是什么内容?
在我的应用里spring的配置文件是application-context.xml,它本身是空的,引用spring-data.xml,sping-security.xml等等和存放对应struts action的spring 配置文件spring-struts-action.xml。
struts的配置文件是struts-config.xml,里面定义了所有的action,它们的class都是org.springframework.web.struts.DelegatingActionProxy。最后的plug-in是
<plug-in 
className="org.springframework.web.struts.ContextLoaderPlugIn"> 
<set-property property="contextConfigLocation" 
value="/WEB-INF/applicationContext.xml"/> 
</plug-in>


结果也遇到了openSessionInView不起作用的问题
在我的应用里都没有出现过action-servlet.xml,我想问下它到底是什么?是对应于我的spring-struts-action.xml还是struts-config.xml引用的一部分?

通俗的说,这个action-servlet.xml到底是spring配置文件还是struts的配置文件?
0 请登录后投票
   发表时间:2005-12-16  
我仔细想了一下,那个action-servlet.xml应该是spring配置的一部分,也就是说对应我的spring-struts-action.xml(明确的说,这个里面的xml语法是spring配置文件的),应该是这样的吧?不过按照这个理解下去,我又产生了问题。
我的理解时这样的,spring里面的listener会在web.xml里加载spring的容器,struts ActionServlet初始化时又会根据struts-config.xml里的spring plugin配置再初始化一个spring容器,所以原则上说只要一个就可以了,如果2处都配了,会初始化2个spring容器,在和struts结合的用法里,实际有效的是stuts配置里面那个plugin初始化的容器,因为用户操作的入口都是struts的action。那么二楼提供的方法其实就是所有的bean都由那个listener初始化的,存在于第一个spring容器中,然后stuts只初始化那些和struts action关联的action bean,存在第二个容器里(这两个容器的区分就在于robbin提到的他们的名字不同)但是问题就是:
为什么在二楼的的方法中,用户通过action访问spring bean,那么应该只是访问的第二个容器里的action bean,而service bean在第一个容器里,那第二个容器里的action bean是怎么会可以访问到第一个容器里的service bean和其他所有spring bean的呢?实在是费解
0 请登录后投票
   发表时间:2006-05-10  
我觉得这个根本就是大家对Spring的理解的问题。

如果这真是一个严重的问题,以至于需要修改源码来修正,Spring的team不会到现在没有发现,到现在还没有修正。为什么Spring的context分成了多个文件?为什么用applicationContext.xml了,还有xxx-servlet.xml?


如果大家监听ContextRefreshedEvent的话,会发现一个web app至少会有两个这样的event,下面是我的现在的应用打印出的context及其所包含的beans:
org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date
[Wed May 10 17:30:13 CST 2006]; child of [org.springframework.context.support.ClassPathXmlApplicationContext: display name  [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=3736840]; startup date [Wed May 10 17:30:09 CST
2006]; root of context hierarchy]; config locations
[/WEB-INF/webApplicationContext.xml,/WEB-INF/webApplicationContext-*.xml,/WEB-INF/standardJspApplicationContext.xml,classpath
*:config/spring/app-context-base.xml,classpath*:config/spring/app-context-hibernate.xml,classpath*:config/spring/app-context-
ibatis.xml,classpath*:config/spring/app-context-integration.xml,classpath*:config/spring/app-context-biz.xml]

[messageSource, localeResolver, exposeSpringBeanDefinition, dataListOfTerminalInfoForm, dataListOfPointsSpecialOfferForm,
dataListOfSearchTerminalForm, pointsSpecialOfferForm1, terminalInfoForm1, searchTerminalForm1,
dataListOfSearchCardAccountDetailForm, dataListOfSearchPhysicalCardInfoForm, dataListOfSearchCardApplicationInfoForm,
dataListOfSearchTransactionForm, searchCardAccountDetailForm1, searchCardAccountDetailForm2, searchCardAccountDetailForm3,
searchPhysicalCardInfoForm1, searchPhysicalCardInfoForm2, searchPhysicalCardInfoForm3, searchTransactionForm1, searchTransactionForm2, searchTransactionForm3, displayTransactionFormForTest, dataListOfReplaceCardForm, dataListOfSearchCardInfoForm, cardInfoFormForTest, cardAccountForm1, cardAccountForm2, cardAccountForm3, searchCardInfoForm1, searchCardInfoForm2, searchCardInfoForm3, replaceCardForm1, replaceCardForm2, replaceCardForm3,
searchCardApplicationInfoForm1, searchCardApplicationInfoForm2, searchCardApplicationInfoForm3,
displayCardApplicationInfoFormForTest, displayCardApplicationInfoFormForTest1, csvDisplayProvider, excelDisplayProvider,
classicLook, simpleLook, microsoftLook, dacHandler, integer0, integer1, integer2, integer3, integer4, integer5, integer6, integer7, integer8, integer9, sessionFactory, transactionManager, hibernateTemplate, abstractHibernateDao, abstractDacHolderHibernateDao, ageLevelDefinitionDao, auditLogDao, bankDao, bankBranchDao, binRangeDao, cardDao,
cardAccountDao, cardAccountDetailDao, cardApplicationDao, cardSalesAgentDao, cardTypeDefinitionDao, centerDao,
centerAccountDao, centerAccountDetailDao, corporationDao, corporationTypeDefinitionDao, csaAccountDao, csaAccountDetailDao, csaBillsDao, csaTypeDefinitionDao, educationLevelDefinitionDao, generalLedgerDao, generalLedgerDetailDao, generalLedgerTypeDefinitionDao, identificationTypeDefinitionDao, incomeLevelDefinitionDao, industryDao, journalDao, journalBackupDao, maritalStatusDefinitionDao, merchantDao, merchantAccountDao, merchantAccountDetailDao, merchantApplicationDao, merchantBillsDao, merchantTypeDefinitionDao, occupationTypeDefinitionDao, outboundEmailDao, permissionDao, physicalCardDao, pointsSpecialOfferDao, residentialTypeDefinitionDao, roleDefinitionDao, rolePermissionDao,
systemConfigDao, terminalDao, terminalConfigurationDao, terminalModelDefinitionDao, transactionSummaryDao,
transactionTypeDefinitionDao, userDao, userCreditRatingDao, userLevelDefinitionDao, userRoleDao, sqlMapClient,
abstractIbatisValueListAdapter, valueListHandler, propertyConfigurer, dataSource, voidTransactionTemplate,
inquiryBalanceTransactionTemplate, definitionBizFacade, facadeHolder, pointsTransactionTemplate, emailBizObject,
clsSpringEventListener, balanceBizFacadeTarget, kernelBizObject, printBizFacadeTarget, pointsSpecialOfferBizFacadeTarget,
settlementBizObject, addPointsTransactionTemplate, inquiryMerchantAccountInfoTransactionTemplate,
addMerchantPointsTransactionTemplate, emailBizFacadeTarget, centerBizFacadeTarget, monitorBizFacadeTarget,
endOfDayReportTransactionTemplate, cardBizFacadeTarget, pointsCalculator, balanceBizObject, pointsSpecialOfferBizObject,
auditLogBizFacadeTarget, terminalBizFacadeTarget, terminalBizObject, templateHolder, settlementBizFacadeTarget,
merchantBizObject, userBizObject, changePinTransactionTemplate, centerPurchasePointsBackTransactionTemplate,
definitionBizObject, monitorBizObject, auditLogBizObject, merchantBizFacadeTarget, userBizFacadeTarget,
responseMessageDataFactoryBean, tradingBizObject, printBizObject, csaBizObject, csaBizFacadeTarget, kernelBizFacadeTarget,
cardBizObject, centerBizObject, tradingBizFacadeTarget, downloadParametersTransactionTemplate, baseTransactionProxy,
abstractDataFacade, balanceBizFacade, printBizFacade, settlementBizFacade, emailBizFacade, kernelBizFacade,
auditLogBizFacade, pointsSpecialOfferBizFacade, terminalBizFacade, userBizFacade, merchantBizFacade, csaBizFacade,
monitorBizFacade, cardBizFacade, centerBizFacade, tradingBizFacade, pointsConverter, transactionTypeHelperBean, integer100, integer106, integer110, integer111, integer120, integer180, integer181, integer182, integer200, integer220, integer221]



---------------------------------------------------------------context2
org.springframework.web.context.support.XmlWebApplicationContext: display name [WebApplicationContext for namespace
'action-servlet']; startup date [Wed May 10 17:31:01 CST 2006]; child of
[org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date
[Wed May 10 17:30:13 CST 2006]; child of [org.springframework.context.support.ClassPathXmlApplicationContext: display name
[org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=3736840]; startup date [Wed May 10 17:30:09 CST
2006]; root of context hierarchy]; config locations
[/WEB-INF/webApplicationContext.xml,/WEB-INF/webApplicationContext-*.xml,/WEB-INF/standardJspApplicationContext.xml,classpath
*:config/spring/app-context-base.xml,classpath*:config/spring/app-context-hibernate.xml,classpath*:config/spring/app-context-
ibatis.xml,classpath*:config/spring/app-context-integration.xml,classpath*:config/spring/app-context-biz.xml]]; config
locations [/WEB-INF/action-servlet.xml]

[/EditCurrentUserInfoAction, /FakeLoginAction, /SaveCardInfoAction, /LoginAction, /EditOperatorPswAction,
/SavePointsSpecialOfferAction, /DisplayCurrentUserInfoAction, /DisplayOperatorApplicationAction, /EditEmailAction,
/RegisterCardAction, /IssueCardsAction, /SearchEmailAction, /RegisterCsaAction, /EditTerminalInfoAction,
/ReleaseTerminalAction, /ReleaseCsaAction, /SaveTerminalInfoAction, /SearchTransactionAction, /SearchOperatorInfoAction,
/ProcessCardApplicationAction, /EditTerminalConfigurationAction, /EditGenericUserByIdAction, /SearchMerchantInfoAction,
/SearchTerminalAction, /SaveCsaPswAction, /SaveCsaInfoAction, /SaveCardTypeAction, /RegisterPointsSpecialOfferAction,
/SearchCardInfoAction, /EditMerchantInfoAction, /SearchCardAccountDetailAction, /SearchCardApplicationInfoAction,
/DisplayTransactionStatisticsAction, /DisplayRegisterCardInfoAction, /SaveEmailAction, /EditCardInfoByIdAction,
/MoniterSystemLogAction, /ReleasePointsSpecialOfferAction, /SearchMerchantAccountDetailAction, /EditMerchantPswAction,
/ReleaseMerchantAction, /ListCardTypeAction, /StockCardsAction, /ProcessOperatorApplicationAction,
/SearchPhysicalCardInfoAction, /SearchCsaInfoAction, /SearchOperatorApplicationAction, /ReleaseOperatorAction,
/DisplayCardApplicationInfoAction, searchEmailValueListBuilder, /SearchCsaApplicationAction, /RegisterCardTypeAction,
/MonitorTerminalStatusAction, /SearchCsaAccountDetailAction, /SearchUserAction, /ReleaseCardTypeAction, /ReleaseUserAction,
/ReleaseEmailAction, /CreateBlankCardsAction, /RegisterBulkCardsAction, /SaveMerchantPswAction,
/SearchPointsSpecialOfferAction, /EditPswAction, /SearchMerchantApplicationAction, /DisplayCsaApplicationAction,
/EndOfDayAction, /EditPointsSpecialOfferAction, /DisplayMerchantApplicationAction, /RegisterEmailAction, /EditCsaPswAction,
/ProcessMerchantApplicationAction, /EditCardTypeDefinitionAction, /SaveOperatorInfoAction, /SaveMerchantInfoAction,
/SaveOperatorPswAction, /EditOperatorInfoAction, /RegisterMerchantAction, /EditCsaInfoAction, /ChangeSystemStatusAction,
/ProcessSystemLogAction, /RegisterOperatorAction, /RegisterTerminalAction, /DisplayTransanctionAction,
/ProcessCsaApplicationAction, /MerchantPointsRedeemTransactionReportAction, /SaveTerminalConfigurationAction,
autoProxyCreator, profilingAdvice, profilingAdvisor, strutsActionAdvice, baseSearchAction, userTypeBasedSelector,
valueListBuilder]



------------------------------------------------------------------------context3
org.springframework.web.context.support.XmlWebApplicationContext: display name [WebApplicationContext for namespace
'trading-servlet']; startup date [Wed May 10 17:31:08 CST 2006]; child of
[org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date
[Wed May 10 17:30:13 CST 2006]; child of [org.springframework.context.support.ClassPathXmlApplicationContext: display name
[org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=3736840]; startup date [Wed May 10 17:30:09 CST
2006]; root of context hierarchy]; config locations
[/WEB-INF/webApplicationContext.xml,/WEB-INF/webApplicationContext-*.xml,/WEB-INF/standardJspApplicationContext.xml,classpath
*:config/spring/app-context-base.xml,classpath*:config/spring/app-context-hibernate.xml,classpath*:config/spring/app-context-
ibatis.xml,classpath*:config/spring/app-context-integration.xml,classpath*:config/spring/app-context-biz.xml]]; config locations [/WEB-INF/trading-servlet.xml]
[clsRawTagElementParser, transactionProcessor, clsTradingServlet, rawTagElementParser]



如果照大家所说的方法去改源代码,那么后启动的servlet的context会覆盖前面一个启动的servlet的context,对于我的应用来说,那种方式会导致action-servlet丢失。开始robbin提出的错误,是因为你在strutsPlugin里多配置了appContext,导致实际上有2分appContext的beans存在,child在自己的context里就可以找到所需要的bean,也就不会去parent里找了。StrutsPlugin里的attrName是正确合理的。

当然你可以把所有所有的bean全部放到root context里,这也行的通,不过本人极力反对这种方式,bean的组织太乱。

Spring的context是分层次的:不要把在写contextConfigLocation的时候,把你的xxx-servlet.xml路径也加进去;不要在写xxx-servlet.xml的context的时候把applicationContext的路径也配进去;不要在parent的context里引用children里的bean,不要在你的appContext里引用xxx-servlet的bean。

总之,就是要求你合理的、有层次的组织你的bena,而不是一陀摆出来。
1 请登录后投票
   发表时间:2006-05-30  
applicationContext.xml如果不引用action-servlet.xml路径的话,那么action如何来引用bo;
<bean name="/test" class="com.xy.action.TestAction">
  <property name="testBo"><ref bean="testBoProxy"/></property>
</bean>


如果bo在applicationContext.xml中的话;
服务器会报错,找不到bo
0 请登录后投票
   发表时间:2006-05-30  
okokok 写道
applicationContext.xml如果不引用action-servlet.xml路径的话,那么action如何来引用bo;
<bean name="/test" class="com.xy.action.TestAction">
  <property name="testBo"><ref bean="testBoProxy"/></property>
</bean>


如果bo在applicationContext.xml中的话;
服务器会报错,找不到bo


我不太清楚你的bean的组织,在我的系统里,BO是在applicationContext之类的基础context里定义,而且工作很正常。

另外你需要搞清楚的是:对于Spring的BeanFactory(ApplicationContext),如果它在自己的context里找不到bean,会去parent里找。

// Check if bean definition exists in this factory.
			if (getParentBeanFactory(); != null && !containsBeanDefinition(beanName);); {
				// Not found -> check parent.
				if (getParentBeanFactory(); instanceof AbstractBeanFactory); {
					// Delegation to parent with args only possible for AbstractBeanFactory.
					return ((AbstractBeanFactory); getParentBeanFactory(););.getBean(name, requiredType, args);;
				}
				else if (args == null); {
					// No args -> delegate to standard getBean method.
					return getParentBeanFactory();.getBean(name, requiredType);;
				}
				else {
					throw new NoSuchBeanDefinitionException(beanName,
							"Cannot delegate to parent BeanFactory because it does not supported passed-in arguments");;
				}
			}


所以无论如何,只要你在applicationContext里定义了BO,那么webApp的context一定找得到这个bean,因为applicationContext是webApp的context的parent。
0 请登录后投票
   发表时间:2006-05-31  
奇了怪了,昨天一直报找不到bo的错,今天居然没报错;服务器有问题?
还有个问题,既然web.xml里可以用listener来加载applicationContext.xml,为什么还要在struts-config.xml里再用plug-in?我觉得在applicationContext.xml里按模块放置每个模块的action,bo,dao的xml文件的路径是个不错方法,比如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<import resource="SpringConfig/module1.xml" />
                <import resource="SpringConfig/module2.xml" />
                <import resource="SpringConfig/module3.xml" />

 	<bean id="dataSource"
		class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName">
			<value>org.gjt.mm.mysql.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://localhost/airline</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password">
			<value>123456</value>
		</property>
	</bean>
         ...
</beans>

而module1.xml的内容是:

&#65279;<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 数据访问层 -->
<bean id="testDao" class="com.xy.dao.TestDao">
  <property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<!-- 业务罗基层 -->
<bean id="testBo" class="com.xy.bo.TestBo">
  <property name="testDao"><ref bean="testDao"/></property>
  <!-- <property name="transactionManager"><ref bean="transactionManager"/></property> -->
</bean>
<!-- Action层 -->
<bean name="/test" class="com.xy.action.TestAction">
  <property name="testBo"><ref bean="testBoProxy"/></property>
</bean>
</beans>

这样的话不用在struts-config.xml里配置plug-in了吧
0 请登录后投票
   发表时间:2006-05-31  
struts-config.xml里配置plug-in是要配的,关键在于你Spring的配置文件的合理分层,如果像你那样什么东西都放在一个applictionContext里,那么就有可能出现象这样OpenSessioInView失效的这样“意想不到”的问题。而且会导致你错误地理解Spring,比如Spring的ApplicationEvent,本身web层的context里的Listener是听不到root层的Event的,但是你这样的配置(也是这个topic的配置)会导致Event混淆,也违背了Spring本身的设计意图。

PS:关于Event的问题可以看我blog,http://spaces.msn.com/sweetriver/blog/cns!367370EB9A9B2807!129.entry

在我的配置里,各个层次都有属于自己的配置文件,messageSource同样应该有分层,为了图方便而简单吧所有bean罗列在一个配置里是不可取的,而且会导致某些设计与实现上的问题(开始我的messageSource是没有分层的,但是后来这样导致了一些非常痛苦的问题与抉择,结果还是改回分层的messageSource)。
1 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics