老项目维护之AOP事务不生效原因调查
AOP事务不生效原因调查
问题源起
assets需要使用rocketmq,直接加入进去的时候消费者始终初始化两次,导致系统异常:
MQClientException:The consumer group xxx has been created before, specify another name please.
为什么会重复加载?
查看web.xml配置:
<!-- SPRING监听器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- SPRING MVC -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
mvc-dispatcher-servlet.xml
<!--properties配置-->
<import resource="classpath:applicationContext.xml"/>
<!-- 访问静态资源 -->
....
可以看到,初始化springMvc时,又重新加载了一遍application-Context.xml的配置;
问题1:为什么其他bean不受二次加载的影响,rocketmq的消费者bean对二次初始化敏感?
解答:spring扫描rocketmq包时会初始化:消费者与生产者具体:ListenerContainerConfiguration/RocketMQAutoConfiguration,RocketMQ禁止启动两个相同的消费者
为了解决这个问题:我们从mvc-dispatcher-servlet.xml文件入手:
修改后的配置如下:
<!--properties配置-->
<import resource="classpath:applicationContext-with-mvc.xml"/>
<!-- 访问静态资源 -->
<mvc:resources location="/static/" mapping="/static/**" />
<mvc:annotation-driven/>
我们新增了一个applicationContext-with-mvc.xml文件用于随mvc-dispatcher-servlet.xml加载启动
<!--properties配置-->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:/configuration/*.properties">
</property>
<property name="fileEncoding" value="utf-8"/>
</bean>
<!-- component scan -->
<context:component-scan base-package="com.xiangshang" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- 导入spring http invoke 配置文件 -->
<import resource="context/applicationContext-api-server.xml" />
<import resource="context/applicationContext-api-server-task.xml" />
<import resource="context/applicationContext-api-server-notity.xml" />
<import resource="context/applicationContext-api-client.xml" />
解决思路:把spring需要加载的bean与mvc的bean分开;
问题2:为什么解决的重复加载有问题后,会导致事务失效?
其实最关键的地方在于:springMvc 自己有一个子容器,他的父容器是springContext;
子容器进行解析bean并进行依赖注入的时候,会从当前容器中找,找不到才从父容器中找;
但是由于我们子容器里面没有加入一个配置:<tx:annotation-driven transaction-manager="transactionManager" /> ,子容器中的所有bean都不会有事务支持。
ServletContext、ApplicationContext、WebApplicationContext的关系
ServletContext 包含ApplicationContext
ServletContext 包含WebApplicationContext
ApplicationContext是WebApplicationContext的子容器;
本文来自博客园,作者:topfrank0,转载请注明原文链接:https://www.cnblogs.com/topfrank/p/16055036.html