Spring的applicationContext.xml和dispatcher-servlet.xml的区别

大家知道, 在spring mvc中, 在applicationContext.xml 和 dispatch-servlet.xml中都可以进行spring 的配置, 那么他们有什么区别呢:

我们先看一下Spring 官方文档:

[html]  view plain  copy
  1. Spring lets you define multiple contexts in a parent-child hierarchy.  
  2. The applicationContext.xml defines the beans for the "root webapp context", i.e. the context associated with the webapp.  
  3. The spring-servlet.xml (or whatever else you call it) defines the beans for one servlet's app context. There can be many of these in a webapp, one per Spring servlet (e.g. spring1-servlet.xml for servlet spring1, spring2-servlet.xml for servlet spring2).  
  4. Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.  
  5. All Spring MVC controllers must go in the spring-servlet.xml context.  
  6. In most simple cases, the applicationContext.xml context is unnecessary. It is generally used to contain beans that are shared between all servlets in a webapp. If you only have one servlet, then there's not really much point, unless you have a specific use for it.   

可见, applicationContext.xml 和 dispatch-servlet.xml形成了两个父子关系的上下文,经过测试, 发现:

1) 一个bean如果在两个文件中都被定义了(比如两个文件中都定义了component scan扫描相同的package), spring会在application context和 servlet context中都生成一个实例,他们处于不同的上下文空间中,他们的行为方式是有可能不一样的(见下面描述的问题)。

 2)  如果在application context和 servlet context中都存在同一个 @Service 的实例, controller(在servlet context中) 通过 @Resource引用时, 会优先选择servlet context中的实例。

PS:

ApplicationContext.xml  是spring 全局配置文件,用来控制spring 特性的

dispatcher-servlet.xml 是spring mvc里面的,控制器、拦截uri转发view

使用applicationContext.xml文件时是需要在web.xml中添加listener的:

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

其实如果直接使用SpringMVC是可以不添加applicationContext.xml文件的。

使用applicationContext.xml文件时是需要在 web.xml 中添加listener的:

org.springframework.web.context.ContextLoaderListener

而这个一般是采用非spring mvc架构,如使用struts之类而又想引入spring才添加的,这个是用来加载Application Context。
如果直接采用SpringMVC,只需要把所有相关配置放到xxx-servlet.xml中就OK了。

在Spring 里配置Mybatis 事务时出现的问题:

                 按照网上的说明, 我在applicationContext.xml文件中增加了如下的配置:

  1.       applicationContext.xml

[html]  view plain  copy
  1. <!--这是原先的sqlSession和dao的配置, 增加事务时候配置保持不变-->  
[html]  view plain  copy
  1. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  2.         <property name="dataSource" ref="dataSource"></property>  
  3.         <property name="configLocation" value="classpath:mybatis.xml"></property>  
  4.         <property name="mapperLocations" value="classpath:com/sjl/dao/*-mapper.xml"></property>  
  5.     </bean>  
  6.       
  7.     <bean id="idao" class="com.sjl.dao.IdaoImpl">  
  8.         <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>  
  9.     </bean>          
 

 

[html]  view plain  copy
  1.    <!--增加的mybatis 事务控制 -->  
  2.    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
  3.          <property name="dataSource" ref="dataSource"></property>      
  4.    </bean>   
  5. <tx:annotation-driven transaction-manager="transactionManager"/>  
   2.     然后在dao中使用 @Transactional 注解声明事务

[java]  view plain  copy
  1. package com.sjl.base;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6.   
  7. import javax.annotation.Resource;  
  8.   
  9. import org.springframework.transaction.annotation.Transactional;  
  10.   
  11. import com.sjl.common.EntityClassUtil;  
  12. import com.sjl.common.Pager;  
  13. import com.sjl.dao.Idao;  
  14.   
  15. public class AbstractBaseDao<T, PK extends Serializable> implements BaseDao <T, PK> {  
  16.     @Resource  
  17.     private Idao<T, PK> idao;  
  18.       
  19.     private Class entityClass = EntityClassUtil.getEntityClass(getClass());  
  20.     <strong><span style="color:#ff0000;">@Transactional</span></strong>  
  21.     public void save(T entity) {  
  22.           
  23.         idao.save(entity);  
  24.         throw new RuntimeException();//抛出异常, 事务回滚  
  25.   
  26.     }  
  27.     public void delete(PK pk) {  
  28.         idao.delete(entityClass, pk);  
  29.           
  30.     }  
  31.     public Pager<T> findByPage(int pageOffset, int pageSize) {  
  32.           
  33.         HashMap<String, Integer> map = new HashMap();  
  34.         map.put("pageOffset", pageOffset);  
  35.         map.put("pageSize", pageSize);  
  36.         Pager<T> pager = idao.findByPage(entityClass, map);  
  37.         return pager;  
  38.           
  39.           
  40.     }  
  41.   
  42.       
  43. }  
[java]  view plain  copy
  1. 其中的idao定义如下:  
  2. <pre name="code" class="java">package com.sjl.dao;  
  3.   
  4. import java.io.Serializable;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import org.mybatis.spring.support.SqlSessionDaoSupport;  
  9. import org.springframework.stereotype.Repository;  
  10.   
  11. import com.sjl.common.Pager;  
  12.   
  13. @Repository("idao")  
  14. public class IdaoImpl<T, PK extends Serializable> extends SqlSessionDaoSupport implements Idao<T, PK>  {  
  15.   
  16.     public void save(T entity) {  
  17.           
  18.         this.getSqlSession().insert(entity.getClass().getName()+".add", entity);  
  19.     }  
  20.   
  21.     public void delete(Class<T> entityClass, PK pk) {  
  22.         this.getSqlSession().insert(entityClass.getName()+".delete", pk);  
  23.           
  24.     }  
  25.   
  26.     public Pager<T> findByPage(Class<T> entityClass, Map param){  
  27.           
  28.         Pager<T> pager = new Pager();  
  29.           
  30.         List<T> pageContent = this.getSqlSession().selectList(entityClass.getName()+".findPageContent", param);  
  31.         pager.setPageContent(pageContent);  
  32.           
  33.         int count = this.getSqlSession().selectOne(entityClass.getName()+".findTotal");  
  34.         pager.setTotalCount(count);  
  35.           
  36.         return pager;  
  37.           
  38.     }  
  39. }  

 

经过以上配置,按照道理应该没有问题了, 但是程序运行后发现事务始终没有启动,连transaction-manager都没有进入, 找了很久没有发现问题出在哪里。后来看到网上同样的配置能运行成功, 比较后发现他是在普通Java Application方式下运行成功的,我把自己的程序也在普通的Java Application方式下运行, 发现transaction起作用了,由此感觉应该是Spring MVC环境下出现的问题,而且应该是transaction 的配置没有起作用, 偶然记起在自己的配置中,dispatch-servlet.xml和applicationContext.xml中 配置的component-scan都扫描了相同的包,这样的话, 虽然在application Context中定义了transaction-manager, 但是这个transaction-manager的配置却是作用在application context中定义的bean上面的。根据前面讲到的application context和dispatcher-servlet context的关系, dispatcher-servlet context 和application context中都存在着相同类型的service bean 实例, 那么controller将优先调用dispatcher-servlet context 中的service bean,而dispatcher-servlet context 中由于没有配置transaction manager, 所以生成的service bean实例没有事务的植入(aop), 当然就无法启动事务了。

解决办法:

1. 在applicationContext.xml 中修改component-scan配置如下:

[html]  view plain  copy
  1. <context:component-scan base-package="com.sjl">  
  2. <span style="white-space:pre">    </span><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />  //不扫描标记@Controller的类  
  3. </context:component-scan>  
2. 在dispatcher-servlet.xml中修改component-scan配置:

[html]  view plain  copy
  1. <context:component-scan base-package="com.sjl.controller"></context:component-scan> .//只扫描controller package  


经过上面的配置, Service bean实例就只会在application Context中生成,就可以使用transaction-manager管理的声明式事务了。


教训:

在application context和dispatcher-servlet定义的bean最好不要重复, dispatcher-servlet最好只是定义controller类型的bean。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值