1. 程式人生 > >applicationContext.xml和dispatch-servlet.xml的區別及引發的問題和教訓

applicationContext.xml和dispatch-servlet.xml的區別及引發的問題和教訓

大家知道, 在spring mvc中, 在applicationContext.xml 和 dispatch-servlet.xml中都可以進行spring 的配置, 那麼他們有什麼區別呢:

我們先看一下Spring 官方文件:

	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中的例項。

在Spring 裡配置Mybatis 事務時出現的問題:

                 按照網上的說明, 我在applicationContext.xml檔案中增加了如下的配置:

  1.       applicationContext.xml

<!--這是原先的sqlSession和dao的配置, 增加事務時候配置保持不變-->
<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>        
 
    <!--增加的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 註解宣告事務
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;
		
		
	}

	
}
其中的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配置如下:

<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配置:
<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。


相關推薦

applicationContext.xmldispatch-servlet.xml區別引發的問題教訓

大家知道, 在spring mvc中, 在applicationContext.xml 和 dispatch-servlet.xml中都可以進行spring 的配置, 那麼他們有什麼區別呢: 我們先看一下Spring 官方文件: Spring lets you defin

applicationContext-XXX.xmlXXX-servlet.xml區別

IT xxx bottom pat 官網 轉發 ota sca AC 1.ApplicationContext.xml 是spring 全局配置文件,用來控制spring 特性的 2.dispatcher-servlet.xml 是spring mvc裏面的,控制器、攔

dispatch-servlet.xmlapplicationContext.xml

spring的配置檔案:applicationContext.xml定義的是“root webapp context”,直譯過來就是根應用上下文。(一般配置bean、資料庫連線、事務、shiro、開啟任務task配置等等) springmvc的配置檔案:dispatcher-servlet.xm

web.xml 中spring-servlet.xml application.xml 配置位置含義

在我們進行 Spring-servlet 進行開發的時候,經常會遇到配置檔案配置的問題,要徹底的解決這個問題,我們需要了解 springMVC 設計的基本架構 1.SpringMVC 的配置分為兩部分 application.xml 和 spring-servl

2.SpringMVC+Spring+Mybatis整合(2) 配置web.xml,spring-servlet.xmlapplicationContext.xml

web spring-servlet 在 webapp WEB-INF下 applicationContext 在resource資料夾下 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:

springMVC(二)web.xmlspringmvc-servlet.xml配置

首先是配置web.xml將請求交給spring的DispatcherServlet處理 程式碼如下<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/200

述 SQL 中的 distinct row_number() over() 的區別用法

表示 第一個 字段值 格式 這樣的 操作數 col 例如 from   1 前言    在咱們編寫 SQL 語句操作數據庫中的數據的時候,有可能會遇到一些不太爽的問題,例如對於同一字段擁有相同名稱的記錄,我們只需要顯示一條,但實際上數據庫中可能含有多條擁有相同名稱的記錄,從

JAVA中string.replace()string.replaceAll()的區別用法

mod btn dsm ont match cep 產生 生成 語法 乍一看,字面上理解好像replace只替換第一個出現的字符(受javascript的影響),replaceall替換所有的字符,其實大不然,只是替換的用途不一樣。 public Strin

JDBC中PreparedStatement接口提供的execute、executeQueryexecuteUpdate之間的區別用法

ica cat nvi 一個 execute ear let ace 刪除 JDBC中PreparedStatement接口提供的execute、executeQuery和executeUpdate之間的區別及用法 (2012-08-27 09:36:18) 轉載▼

Linux下ps -efps aux的區別格式詳解

占用內存 style star wid 內存交換 現在 linu pts tar Linux下顯示系統進程的命令ps,最常用的有ps -ef 和ps aux。這兩個到底有什麽區別呢?兩者沒太大差別,討論這個問題,要追溯到Unix系統中的兩種風格,System V風格和BSD

(轉)Http狀態碼301302概念簡單區別企業應用案例

ash BE light div www oldboy dex -i 地址 Http狀態碼301和302的區別及企業應用案例 原文:http://blog.51cto.com/oldboy/1774260 1、什麽是301重定向?   301重定向/跳轉一般,表示本網頁永

Linux下ps -efps aux的區別格式詳解-轉

進程組 inux 詳解 少見 CP 被鎖 中斷 https www. 原文:https://www.linuxidc.com/Linux/2016-07/133515.htm Linux下顯示系統進程的命令ps,最常用的有ps -ef 和ps aux。這兩個到底有什麽區別呢

python 2Python3的常見區別修改辦法

常見報錯如下: SyntaxError: Missing parentheses in call to 'print'. Did you mean print(x)?   NameError: name 'collections' is not defined   M

bowtiebowtie2使用條件區別用法

一、轉錄組還是基因組? map常用的工具有bowtie/bowtie2, BWA,SOAP1/SOAP2等。這個問題又會被分成兩個問題,是基因組測序(DNA-seq)還是轉錄組測序(mRNA-seq)。其中的區別是對於真核生物而言,mRNA序列與DNA序列並不完全相同,在經歷了後剪下之後,成熟的

JAVA基礎(44)---區域性變數成員變數的區別封裝

成員變數和區域性變數的區別                       

vue3.02.0的區別專案的搭建

  3.0 新加入了 TypeScript 以及 PWA 的支援 部分命令發生了變化: 下載安裝  npm install -g [email protected] 刪除了vue list 建立專案&n

全形半形的區別使用方法

一.什麼是全形什麼是半形? 一、什麼是全形和半形?  1. 全形:是一種電腦字元,是指一個全形字元佔用兩個標準字元(或兩個半形字元)的位置。全形佔兩個位元組。  漢字字元和規定了全形的英文字元及國標GB2312-80中的圖形符號和特殊字元都是全形字元。在全形中,字母和數字等與漢字

docker虛擬機器的區別docker安裝

docker和虛擬機器的區別: 如下圖: Docker守護程序可以直接與主作業系統進行通訊,為各個Docker容器分配資源;它還可以將容器與主作業系統隔離,並將各個容器互相隔離。虛擬機器啟動需要數分鐘,而Docker容器可以在數毫秒內啟動。由於沒有臃腫的從作業系統,Docker可以節省大量

日誌採集系統flumekafka有什麼區別聯絡?

日誌採集系統flume和kafka有什麼區別及聯絡,它們分別在什麼時候使用,什麼時候又可以結合? 觀點一: 簡言之:這兩個差別很大,使用場景區別也很大。 先說flume: 日誌採集。線上資料一般主要是落地檔案或者通過socket傳輸給另外一個系統。這種情況下,你很難推動線上應用或服務去修改介

32位64位系統區別int位元組數

一、64位系統和32位有什麼區別? 1、64bit CPU擁有更大的定址能力,最大支援到16GB記憶體,而32bit只支援4G記憶體 2、64位CPU一次可提取64位資料,比32位提高了一倍,理論上效能會提升1倍。但這是建立在64bit作業系統,64bit軟體的基礎上的。 什麼是64位處理器? 之所以叫