您的位置:首页 > 移动开发

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

2017-05-25 13:52 471 查看
大家知道, 在spring mvc中, 在applicationContext.xml
和 dispatch-servlet.xml中都可以进行spring 的配置, 那么他们有什么区别呢:
我们先看一下Spring 官方文档:

[html] view
plain copy

Spring lets you define multiple contexts in a parent-child hierarchy.  

The applicationContext.xml defines the beans for the "root webapp context", i.e. the context associated with the webapp.  

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).  

Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.  

All Spring MVC controllers must go in the spring-servlet.xml context.  

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

<!--这是原先的sqlSession和dao的配置, 增加事务时候配置保持不变-->  

[html] view
plain copy

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  

        <property name="dataSource" ref="dataSource"></property>  

        <property name="configLocation" value="classpath:mybatis.xml"></property>  

        <property name="mapperLocations" value="classpath:com/sjl/dao/*-mapper.xml"></property>  

    </bean>  

      

    <bean id="idao" class="com.sjl.dao.IdaoImpl">  

        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>  

    </bean>          

 



[html] view
plain copy

   <!--增加的mybatis 事务控制 -->  

   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   

         <property name="dataSource" ref="dataSource"></property>      

   </bean>   

<tx:annotation-driven transaction-manager="transactionManager"/>  

   2.     然后在dao中使用 @Transactional 注解声明事务

[java] view
plain copy

package com.sjl.base;  

  

import java.io.Serializable;  

import java.util.HashMap;  

import java.util.List;  

  

import javax.annotation.Resource;  

  

import org.springframework.transaction.annotation.Transactional;  

  

import com.sjl.common.EntityClassUtil;  

import com.sjl.common.Pager;  

import com.sjl.dao.Idao;  

  

public class AbstractBaseDao<T, PK extends Serializable> implements BaseDao <T, PK> {  

    @Resource  

    private Idao<T, PK> idao;  

      

    private Class entityClass = EntityClassUtil.getEntityClass(getClass());  

    <strong><span style="color:#ff0000;">@Transactional</span></strong>  

    public void save(T entity) {  

          

        idao.save(entity);  

        throw new RuntimeException();//抛出异常, 事务回滚  

  

    }  

    public void delete(PK pk) {  

        idao.delete(entityClass, pk);  

          

    }  

    public Pager<T> findByPage(int pageOffset, int pageSize) {  

          

        HashMap<String, Integer> map = new HashMap();  

        map.put("pageOffset", pageOffset);  

        map.put("pageSize", pageSize);  

        Pager<T> pager = idao.findByPage(entityClass, map);  

        return pager;  

          

          

    }  

  

      

}  

[java] view
plain copy

其中的idao定义如下:  

<pre name="code" class="java">package com.sjl.dao;  

  

import java.io.Serializable;  

import java.util.List;  

import java.util.Map;  

  

import org.mybatis.spring.support.SqlSessionDaoSupport;  

import org.springframework.stereotype.Repository;  

  

import com.sjl.common.Pager;  

  

@Repository("idao")  

public class IdaoImpl<T, PK extends Serializable> extends SqlSessionDaoSupport implements Idao<T, PK>  {  

  

    public void save(T entity) {  

          

        this.getSqlSession().insert(entity.getClass().getName()+".add", entity);  

    }  

  

    public void delete(Class<T> entityClass, PK pk) {  

        this.getSqlSession().insert(entityClass.getName()+".delete", pk);  

          

    }  

  

    public Pager<T> findByPage(Class<T> entityClass, Map param){  

          

        Pager<T> pager = new Pager();  

          

        List<T> pageContent = this.getSqlSession().selectList(entityClass.getName()+".findPageContent", param);  

        pager.setPageContent(pageContent);  

          

        int count = this.getSqlSession().selectOne(entityClass.getName()+".findTotal");  

        pager.setTotalCount(count);  

          

        return pager;  

          

    }  

}  


经过以上配置,按照道理应该没有问题了, 但是程序运行后发现事务始终没有启动,连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

<context:component-scan base-package="com.sjl">  

<span style="white-space:pre">    </span><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />  //不扫描标记@Controller的类  

</context:component-scan>  

2. 在dispatcher-servlet.xml中修改component-scan配置:

[html] view
plain copy

<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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: