spring,hibernate事務(wù)無效問題(由use-default-filters導(dǎo)致的事故)

來張圖


圖片發(fā)自簡書App

前置

最近在開發(fā)一個web項(xiàng)目,集成hibernate,且使用了OpenSessionInViewFilter,發(fā)現(xiàn)spring的事務(wù)無效了。進(jìn)行了如下配置:

spring上下文的applicationContext.xml

<context:component-scan base-package="com.github.mypost">   
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   
    <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

<!-- 事務(wù)管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- 事務(wù)特性  -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
    <tx:attributes>
        <tx:method name="save*" propagation="REQUIRED"/>
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="insert*" propagation="REQUIRED"/>
        <tx:method name="create*" propagation="REQUIRED"/>
        <tx:method name="delete*" propagation="REQUIRED"/>
        <tx:method name="remove*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="modify*" propagation="REQUIRED"/>
        <tx:method name="edit*" propagation="REQUIRED"/>
        <tx:method name="*" read-only="true" />
    </tx:attributes>
</tx:advice>

<aop:config proxy-target-class="true">
    <aop:pointcut id="serviceMethod" expression="execution(* com.github.mypost.*.service..*+.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
</aop:config>

<aop:aspectj-autoproxy proxy-target-class="true"/>

<!-- annotation trasaction -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

springmvc的上下文配置webApplicationContext.xml

<context:component-scan base-package="com.github.mypost">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

<!--默認(rèn)的注解映射的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>

<!-- 攔截器 -->
<mvc:interceptors>
    <bean class="com.github.mypost.commons.web.interceptor.BaseInterceptor"></bean>
</mvc:interceptors>

<!--視圖解釋器,根據(jù)不同的請求展示不同的View -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="viewResolvers">
        <list>
            <!--視圖解釋類 -->
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
                <property name="prefix" value="/WEB-INF/view/" />
                <property name="suffix" value=".jsp" />
            </bean>
        </list>
    </property>
</bean>

<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />

<!-- 配置文件上傳解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8" />
</bean>

<mvc:view-controller path="/" view-name="index"/>

一直以為是使用了OpenSessionInViewFilter這個類庫的原因?qū)е碌氖?,最后才發(fā)現(xiàn)是由于context:component-scan的use-default-filters導(dǎo)致的問題。

分析

  1. <context:component-scan>會交給org.springframework.context.config.ContextNamespaceHandler處理;
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
  1. <context:component-scan>的use-default-filters默認(rèn)true,會交給ClassPathScanningCandidateComponentProvider進(jìn)行掃描,看代碼:
protected void registerDefaultFilters() {
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
        logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
        // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
    }
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
        logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
        // JSR-330 API not available - simply skip.
    }
}

可以看到默認(rèn)ClassPathBeanDefinitionScanner會自動注冊對@Component、@ManagedBean、@Named注解的Bean進(jìn)行掃描。如果細(xì)心,到此就找到問題根源了。

  1. 對exclude-filter,include-filter進(jìn)行過濾
    首先通過exclude-filter 進(jìn)行黑名單過濾;
    然后通過include-filter 進(jìn)行白名單過濾;
    否則默認(rèn)排除。

結(jié)論

<context:component-scan base-package="com.github.mypost" use-default-filters="false"> 
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
     <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

那么這段代碼不僅僅對@Controller的注解Bean進(jìn)行了掃描,而且對@Compoent注解也掃描了,子注解@Service,@Repository也進(jìn)行了掃描,所以原來mvc的上下文的Bean被后面的bean替換了。所以如下解決方法:

  1. 如果不需要默認(rèn)的,則use-default-filters=“false”禁用掉。
  2. 直接寫明具體Controller包名稱。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容