溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決SpringMVC對包的掃描范圍擴大后導(dǎo)致的事務(wù)配置不生效問題

發(fā)布時間:2021-10-21 09:49:24 來源:億速云 閱讀:212 作者:柒染 欄目:大數(shù)據(jù)

今天就跟大家聊聊有關(guān)如何解決SpringMVC對包的掃描范圍擴大后導(dǎo)致的事務(wù)配置不生效問題,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

在整合新的ssh框架的時候,spring+springmvc+hibernate的時候發(fā)現(xiàn)一個問題,就是持久層在使用hibernateTemplate的時候,并不會自動實現(xiàn)事務(wù)的提交,SpringMVC對包的掃描范圍擴大后,導(dǎo)致的事務(wù)配置不生效問題

首先配置的是Spring容器的初始化加載的application文件,然后是SpringMVC的前端控制器(DispatchServlet),當(dāng)配置完DispatchServlet后會在Spring容器中創(chuàng)建一個新的容器

其實這是兩個容器,Spring作為父容器,SpringMVC作為子容器

web.xml中對Spring的配置

<!-- 把 Spring 容器集成到 Web 應(yīng)用里面 -->
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>

  <!-- spring配置文件 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/applicationContext.xml</param-value>
  </context-param>

  <!--DispatcherServlet是前端控制器設(shè)計模式的實現(xiàn),提供Spring Web MVC的集中訪問點,而且負責(zé)職責(zé)的分派,
  而且與Spring IoC容器無縫集成,從而可以獲得Spring的所有好處。-->
  <!--DispatcherServlet會默認加載[servlet-name]-servlet.xml文件-->
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

applicationContext.xml使用AOP聲明式事務(wù)配置

<!--  聲明式容器事務(wù)管理 ,transaction-manager指定事務(wù)管理器為transactionManager -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="query*" read-only="true"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="save*" rollback-for="Exception" propagation="REQUIRED"/>
            <tx:method name="update*" rollback-for="Exception" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <!--只對業(yè)務(wù)邏輯層實施事務(wù) -->
        <aop:pointcut expression="execution(* com.zhimajp.auction.service.impl..*.*(..))" id="busiLogicService"/>
        <aop:advisor advice-ref="transactionAdvice" pointcut-ref="busiLogicService"/>
    </aop:config>

遇到的問題是:通過Hibernate執(zhí)行save方法后,數(shù)據(jù)未能插入到DB中并且控制臺也沒有打印出SQL(控制臺沒有輸出)

通過仔細排查,閱讀網(wǎng)絡(luò)文章后,發(fā)現(xiàn)問題出現(xiàn)在spring-servlet.xml中:<context:component-scan base-package="com.zhimajp.auction" /> 

上述配置的結(jié)果是:SpringMVC對Service和Dao的所有package進行了掃描裝載

問題分析:

1、Spring與SpringMVC屬于父子容器關(guān)系??蚣軉訒r先啟動Spring容器,而后啟動SpringMVC容器。子容器可以訪問父容器中的Bean,而父容器不能訪問子容器中的Bean

2、由于SpringMVC在掃描時擴大了掃描范圍,裝載了@Service標(biāo)識的類的實例,從而導(dǎo)致Controller層在注入Service時,實際注入的是子容器中的Service實例

3、事務(wù)被配置在父容器中,Spring父容器在裝載Service時會同時應(yīng)用事務(wù)配置,而SpringMVC只是單純加載Service的實例

解決的辦法如下

applicationContext.xml掃包排除掉Controller

<context:component-scan base-package="com.bdqn.cc">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

springmvc.xml掃包只掃描controller

<context:component-scan base-package="com.bdqn.cc" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

springmvc配置文件 use-default-filters="false",因為use-default-filters的值默認是true,也就是掃描全部的帶有@Controller、@Service等注解的包了,加上之后則只掃描controller

進一步證明
打印容器管理的bean名稱

我們使SpringMVC掃描Controller和Service,Spring掃描Service和DAO。

使用以下代碼打印父子窗口管理的bean名稱:

WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
        String[] definationBeanNames = webApplicationContext.getBeanNamesForAnnotation(Service.class);
        List<String> names = new ArrayList<String>(Arrays.asList(definationBeanNames));
        Collections.addAll(names, webApplicationContext.getBeanNamesForAnnotation(Controller.class));
        Collections.addAll(names, webApplicationContext.getBeanNamesForAnnotation(Repository.class));
        System.out.println("Spring 父容器管理的Bean:");
        for(String beanName : names){
            System.out.println(beanName);
        }

        webApplicationContext = RequestContextUtils.getWebApplicationContext(request);
        definationBeanNames = webApplicationContext.getBeanNamesForAnnotation(Service.class);
        names = new ArrayList<String>(Arrays.asList(definationBeanNames));
        Collections.addAll(names, webApplicationContext.getBeanNamesForAnnotation(Controller.class));
        Collections.addAll(names, webApplicationContext.getBeanNamesForAnnotation(Repository.class));

        System.out.println("SpringMVC 子容器管理的Bean:");
        for(String beanName : names){
            System.out.println(beanName);
        }

如何解決SpringMVC對包的掃描范圍擴大后導(dǎo)致的事務(wù)配置不生效問題

我們發(fā)現(xiàn)父子容器同時維護了Service層的類的實例,并且應(yīng)該是兩個獨立的實例。

只使用子容器,而完全不使用父容器

現(xiàn)在我們測試另外一個場景

將web.xml中,注釋掉ContextLoaderListener,修改配置為:

<!--DispatcherServlet是前端控制器設(shè)計模式的實現(xiàn),提供Spring Web MVC的集中訪問點,而且負責(zé)職責(zé)的分派,
  而且與Spring IoC容器無縫集成,從而可以獲得Spring的所有好處。-->
  <!--DispatcherServlet會默認加載[servlet-name]-servlet.xml文件-->
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:/applicationContext.xml;/WEB-INF/spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

移除了父容器,所有配置文件全部交由SpringMVC加載 。

打印結(jié)果如下:

如何解決SpringMVC對包的掃描范圍擴大后導(dǎo)致的事務(wù)配置不生效問題

1、當(dāng)事務(wù)交由Spring管理時,Spring負責(zé)管理session中事務(wù)的開啟、關(guān)閉、flush等步驟,開發(fā)者只需調(diào)用例如save、update方法即可

2、當(dāng)web項目框架中存在父子容器,且事務(wù)由父容器管理時,就應(yīng)當(dāng)注意SpringMVC對包的掃描范圍并且只需掃描Controller組件。官方推薦:父子容器應(yīng)當(dāng)各執(zhí)其責(zé)

3、如果子容器加載了Service的話,則在該實例上事務(wù)并不會生效。也就是Spring不會在service的方法被調(diào)用時自動開啟事務(wù)

4、基于2中的前提:SpringMVC應(yīng)只加載web相關(guān)配置(視圖配置、Controller注解掃描),由Spring加載數(shù)據(jù)源、事務(wù)配置、Service和Dao注解掃描

看完上述內(nèi)容,你們對如何解決SpringMVC對包的掃描范圍擴大后導(dǎo)致的事務(wù)配置不生效問題有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI