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.xml和dispatch-servlet.xml的區別及引發的問題和教訓
大家知道, 在spring mvc中, 在applicationContext.xml 和 dispatch-servlet.xml中都可以進行spring 的配置, 那麼他們有什麼區別呢: 我們先看一下Spring 官方文件: Spring lets you defin
applicationContext-XXX.xml和XXX-servlet.xml的區別
IT xxx bottom pat 官網 轉發 ota sca AC 1.ApplicationContext.xml 是spring 全局配置文件,用來控制spring 特性的 2.dispatcher-servlet.xml 是spring mvc裏面的,控制器、攔
dispatch-servlet.xml與applicationContext.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.xml,applicationContext.xml
web spring-servlet 在 webapp WEB-INF下 applicationContext 在resource資料夾下 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:
springMVC(二)web.xml和springmvc-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、executeQuery和executeUpdate之間的區別及用法
ica cat nvi 一個 execute ear let ace 刪除 JDBC中PreparedStatement接口提供的execute、executeQuery和executeUpdate之間的區別及用法 (2012-08-27 09:36:18) 轉載▼
Linux下ps -ef和ps aux的區別及格式詳解
占用內存 style star wid 內存交換 現在 linu pts tar Linux下顯示系統進程的命令ps,最常用的有ps -ef 和ps aux。這兩個到底有什麽區別呢?兩者沒太大差別,討論這個問題,要追溯到Unix系統中的兩種風格,System V風格和BSD
(轉)Http狀態碼301和302概念簡單區別及企業應用案例
ash BE light div www oldboy dex -i 地址 Http狀態碼301和302的區別及企業應用案例 原文:http://blog.51cto.com/oldboy/1774260 1、什麽是301重定向? 301重定向/跳轉一般,表示本網頁永
Linux下ps -ef和ps aux的區別及格式詳解-轉
進程組 inux 詳解 少見 CP 被鎖 中斷 https www. 原文:https://www.linuxidc.com/Linux/2016-07/133515.htm Linux下顯示系統進程的命令ps,最常用的有ps -ef 和ps aux。這兩個到底有什麽區別呢
python 2和Python3的常見區別及修改辦法
常見報錯如下: SyntaxError: Missing parentheses in call to 'print'. Did you mean print(x)? NameError: name 'collections' is not defined M
bowtie和bowtie2使用條件區別及用法
一、轉錄組還是基因組? map常用的工具有bowtie/bowtie2, BWA,SOAP1/SOAP2等。這個問題又會被分成兩個問題,是基因組測序(DNA-seq)還是轉錄組測序(mRNA-seq)。其中的區別是對於真核生物而言,mRNA序列與DNA序列並不完全相同,在經歷了後剪下之後,成熟的
JAVA基礎(44)---區域性變數和成員變數的區別及封裝
成員變數和區域性變數的區別
vue3.0和2.0的區別及專案的搭建
3.0 新加入了 TypeScript 以及 PWA 的支援 部分命令發生了變化: 下載安裝 npm install -g [email protected] 刪除了vue list 建立專案&n
全形和半形的區別及使用方法
一.什麼是全形什麼是半形? 一、什麼是全形和半形? 1. 全形:是一種電腦字元,是指一個全形字元佔用兩個標準字元(或兩個半形字元)的位置。全形佔兩個位元組。 漢字字元和規定了全形的英文字元及國標GB2312-80中的圖形符號和特殊字元都是全形字元。在全形中,字母和數字等與漢字
docker和虛擬機器的區別及docker安裝
docker和虛擬機器的區別: 如下圖: Docker守護程序可以直接與主作業系統進行通訊,為各個Docker容器分配資源;它還可以將容器與主作業系統隔離,並將各個容器互相隔離。虛擬機器啟動需要數分鐘,而Docker容器可以在數毫秒內啟動。由於沒有臃腫的從作業系統,Docker可以節省大量
日誌採集系統flume和kafka有什麼區別及聯絡?
日誌採集系統flume和kafka有什麼區別及聯絡,它們分別在什麼時候使用,什麼時候又可以結合? 觀點一: 簡言之:這兩個差別很大,使用場景區別也很大。 先說flume: 日誌採集。線上資料一般主要是落地檔案或者通過socket傳輸給另外一個系統。這種情況下,你很難推動線上應用或服務去修改介
32位和64位系統區別及int位元組數
一、64位系統和32位有什麼區別? 1、64bit CPU擁有更大的定址能力,最大支援到16GB記憶體,而32bit只支援4G記憶體 2、64位CPU一次可提取64位資料,比32位提高了一倍,理論上效能會提升1倍。但這是建立在64bit作業系統,64bit軟體的基礎上的。 什麼是64位處理器? 之所以叫