Loading

老项目维护之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的子容器;

posted @ 2022-03-25 15:45  topfrank0  阅读(157)  评论(0编辑  收藏  举报