首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring 整合 MyBatis 實戰(二):Web 容器啟動 Spring、獲取上下文與聲明式事務完整指南

     編輯:Java 綜合教學

Spring 整合 MyBatis 實戰(二):Web 容器啟動 Spring、獲取上下文與聲明式事務完整指南

承接上篇 Maven 環境搭建,本文聚焦 Web 環境下 Spring 容器的啟動方式、ApplicationContext 獲取策略,以及基於註解與 AOP 的聲明式事務管理配置,構建企業級應用的堅實基礎。

一、 Web 專案中啟動 Spring 容器的三種方式

1.1 監聽器啟動(推薦,最早啟動)

使用 org.springframework.web.context.ContextLoaderListener,需引入 spring-web 依賴:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>${spring.version}</version>
</dependency>

web.xml 基礎配置:

<listener>
  <description>Spring 容器啟動監聽器</description>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

預設掃描 /WEB-INF/applicationContext.xml,多配置檔指定方式:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath*:applicationContext.xml</param-value>
</context-param>

常見啟動失敗排查:

  • 配置檔路徑錯誤
  • 找不到 ContextLoaderListener 類 → Maven 依賴未發布到伺服器(專案屬性 → Deployment Assembly 添加 Maven Dependencies)

1.2 Servlet 啟動(Spring 3.0 後棄用)

使用 ContextLoaderServlet 需設定 <load-on-startup>1</load-on-startup>,但 Spring 3.0 已移除,建議統一使用監聽器。

1.3 MVC 框架擴展點啟動

如 Spring MVC 的 DispatcherServlet 自帶 contextConfigLocation 參數,屬於特定框架用法,不做通用介紹。

二、 獲取 ApplicationContext 實例的兩大模式

2.1 工具類模式:WebApplicationContextUtils

適用於 Servlet、Filter 等非 Spring 管理物件:

@Override
public void init() throws ServletException {
    WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    bookTypeService = ctx.getBean(BookTypeService.class);
}

注意:重寫帶參 init(ServletConfig) 時必須呼叫 super.init(config),否則無法獲取 ServletContext。

2.2 接口回調模式:ApplicationContextAware(推薦)

實現 ApplicationContextAware 並交由 Spring 管理(@Component 或 XML <bean>),容器啟動時自動回調 setApplicationContext():

@Component
public class CtxUtil implements ApplicationContextAware {
    public static ApplicationContext springCtx;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        springCtx = applicationContext;
    }

    public static Object getBean(String name) { return springCtx.getBean(name); }
    public static <T> T getBean(Class<T> clazz) { return springCtx.getBean(clazz); }
}

後續任何處直接呼叫 CtxUtil.getBean(BookTypeService.class) 即可,無需傳遞 ServletContext。

三、 基於註解的聲明式事務管理配置

3.1 核心依賴與命名空間

需引入 spring-tx,並在 applicationContext.xml 引入 tx 命名空間:

xmlns:tx="https://www.springframework.org/schema/tx"
xsi:schemaLocation="...
  https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd"

3.2 事務管理器與註解驅動

<!-- 數據源事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="jdbcDataSource"/>
</bean>

<!-- 開啟 @Transactional 註解支援 -->
<tx:annotation-driven transaction-manager="txManager"/>

3.3 業務層使用 @Transactional

@Service
public class BookTypeService {
    @Resource BookTypeDAO bookTypeDAO;

    @Transactional
    public int addDouble(BookType entity1, BookType entity2) {
        int rows = 0;
        rows += bookTypeDAO.add(entity1);
        rows += bookTypeDAO.add(entity2); // 若此處拋異常,前一條自動回滾
        return rows;
    }
}

驗證:entity2 缺少必填字段導致異常時,資料庫兩條記錄均不會插入,保證原子性。

3.4 AOP 攔截器式事務配置(替代方案)

適合統一按方法名規則套用事務:

<tx:advice id="transactionAdvice" transaction-manager="txManager">
  <tx:attributes>
    <tx:method name="add*" propagation="REQUIRED"/>
    <tx:method name="save*" propagation="REQUIRED"/>
    <tx:method name="update*" propagation="REQUIRED"/>
    <tx:method name="delete*" propagation="REQUIRED"/>
    <tx:method name="get*" propagation="SUPPORTS"/>
    <tx:method name="find*" propagation="SUPPORTS"/>
    <tx:method name="*" propagation="SUPPORTS"/>
  </tx:attributes>
</tx:advice>

<aop:config>
  <aop:pointcut id="transactionPointcut" expression="execution(* com.service..*Impl.*(..))"/>
  <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>
</aop:config>

對比:註解式靈活精準,AOP 式統一規約;查詢方法建議 SUPPORTS(不需要事務),寫操作用 REQUIRED。

完整 applicationContext.xml 關鍵片段

<beans ... xmlns:tx="...">
  <context:property-placeholder location="classpath:db.properties"/>
  
  <bean id="jdbcDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="${jdbc.driver}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.uid}"/>
    <property name="password" value="${jdbc.pwd}"/>
    <property name="acquireIncrement" value="5"/>
    <property name="initialPoolSize" value="10"/>
    <property name="minPoolSize" value="5"/>
    <property name="maxPoolSize" value="20"/>
  </bean>

  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="jdbcDataSource"/>
    <property name="typeAliasesPackage" value="com.example.entities"/>
    <property name="mapperLocations" value="classpath:com/example/mapping/*Mapper.xml"/>
  </bean>

  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    <property name="basePackage" value="com.example.mapping"/>
  </bean>

  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="jdbcDataSource"/>
  </bean>
  <tx:annotation-driven transaction-manager="txManager"/>

  <context:component-scan base-package="com.example">
    <context:exclude-filter type="aspectj" expression="com.example.dao.*"/>
  </context:component-scan>
  <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

關鍵點總結

  • 監聽器啟動 Spring 容器最早、最通用
  • ApplicationContextAware 提供靜態獲取 Bean 能力,適合非 Spring 管理物件
  • 聲明式事務核心:DataSourceTransactionManager + <tx:annotation-driven/> + @Transactional
  • MyBatis-Spring 透明管理 SqlSession 生命週期,DAO 層無需手動提交/回滾
  • AOP 事務攔截適合大量統一規則場景,減少註解重複
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved