spring mvc框架 类初始化2次 解决过程

二次信任 提交于 2019-12-06 12:27:55

背景:刚开始做平台的工作,接触的就是spring mvc框架,struts没碰过,没有任何java web的理论基础,项目组的这个项目框架是spring mvc + ibatis组合的。

做了一个项目觉得挺顺手,都是小项目,第一个项目还有人稍微指导,第二个项目之后都靠自己做了。有空的时候会稍微改一下这个框架的基础东西,比如说,去掉一堆没用的jar包,冗余太多,部署上传费时。去掉struts相关的包,最后在没有提示错误时,通过报的异常导入包,去掉了几十个无用的,方法很土。

事情起因:因为要用到消息队列,另一个同事调试时,发现本来应该是3个消息队列,却可以看到6个,怀疑类初始化2次,写了个简单的方法,测试,可以看到2次初始化。我自己也写了个,确实看到输出2次。

@Service("Test")
public class Test {

	private static int cnt = 0;

	public Test() {
		super();
		System.out.println("cnt = " + cnt);
		cnt++;
	}
	
}

 


解决过程:经过调查,发现spring的配置文件中有2处component-scan,配置文件(web.xml,applicationContext.xml,spring-servlet.xml)大概如下:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<!--定义日志配置文件-->
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/classes/log4j.properties</param-value>
	</context-param>

	<!-- 配置spring配置文件路径 ,webservice配置文件路径 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/classes/applicationContext.xml;
		</param-value>
	</context-param>

	<!-- Spring Listener Config -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- url配置为/,不带文件后缀,会造成其它静态文件(js,css等)不能访问。如配为*.do(*.html),则不影响静态文件的访问。-->
	<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>namespace</param-name>
			<param-value>/classes/spring-servlet</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	
	<!-- 编码(UTF-8)转换过滤器 -->
	<filter>
		<filter-name>Set Character Encoding</filter-name>
		<filter-class>
			com.test.xxx.filter.SetCharacterEncodingFilter
		</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>Set Character Encoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- filter.listener,servlet,and servlet-mapping等元素要在session-config之前,这里设置的时间单位是分钟 -->
	<session-config>
		<session-timeout>25</session-timeout>
	</session-config>

</web-app>

 

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation=" 
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd 
		http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<!-- ORACLE数据源配置 -->
	<bean id="DataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!-- 数据库配置省略 -->
	</bean>

	<!-- 整合ibatis -->
	<bean id="sqlMapClient"
		class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="dataSource">
			<ref local="DataSource" />
		</property>
		<property name="configLocations">
			<value>classpath:SqlMapConfig.xml</value>
		</property>
	</bean>

	<!-- 自动注入实现类装填 -->
	<context:component-scan base-package="com.test" />
	<context:annotation-config />

	<!-- 配置事务管理 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref local="DataSource" />
		</property>
	</bean>
	
	<!-- 定义SERVICE事务通知 -->  
	<tx:advice id="txAdvice_service" transaction-manager="transactionManager">  
	    <!-- 定义方法的过滤规则 -->  
	    <tx:attributes>  
	        <!-- 所有方法都使用事务 -->  
	        <tx:method name="*" propagation="REQUIRED"/>  
	        <!-- 定义所有get开头的方法都是只读的 -->  
	        <tx:method name="get*" read-only="true"/>
	    </tx:attributes>  
	</tx:advice> 
	
	<!-- 定义AOP配置 -->
	<aop:config proxy-target-class="true">
		<!-- 适配切入点(service)和事务的通知 -->
		<aop:advisor pointcut="execution(* *..service..impl..*.*(..))"
			advice-ref="txAdvice_service" />
	</aop:config>
	
	<import resource="classpath:app-scheduling.xml"/>
</beans>

 


spring-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
           http://www.springframework.org/schema/context   
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/mvc       
           http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

	<!-- 把标记了@Controller注解的类转换为bean -->
	<context:component-scan base-package="com.test" />

	<!-- 在SpringMVC中使用JSON必须配置 -->
	<mvc:annotation-driven />

	<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

	<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver"
		p:prefix="/view/" p:suffix=".jsp" />
	
</beans>

 


当我删掉applicationContext.xml里的<context:component-scan base-package="com.test" />时,发现程序正常运行,将配置修改到另外一个项目里,出问题了,提示大概是找不到定时器的bean。还原回来,删掉spring-servlet.xml里的<context:component-scan base-package="com.test" />,运行项目,发现所有的url-mapping都失效了。

之后因为不想让消息队列初始化2次,就把spring-servlet.xml的<context:component-scan base-package="com.test" />改为<context:component-scan base-package="com.test.xxx.*.controller" />,使初始2次的bean缩小范围。

这几天稍微看了一下spring mvc相关的资料,下午试了一下,把applicationContext.xml的<context:component-scan base-package="com.test" />去掉,并且把定时器配置相关的<import resource="classpath:app-scheduling.xml"/>移到spring-servlet.xml中,就ok了,定时器正常执行,网址映射正常。

 

事后心得:看来做项目还是要学一些基础理论的。

==============================================

2017-8-4补充

最近看到beetlsql的Spring+beetlsql例子的配置文件,发现了一个彻底解决的办法。web.xml文件都不用修改,主要改的就是applicationContext.xml和spring-servlet.xml,把所有spring-servlet.xml的配置内容都移入applicationContext.xml,spring-servlet.xml留一个空壳就可以了。

spring-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
           http://www.springframework.org/schema/context   
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/mvc       
           http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
	
</beans>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation=" 
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
		http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<!-- 把标记了@Controller注解的类转换为bean -->
	<context:component-scan base-package="com.test" />

	<!-- 在SpringMVC中使用JSON必须配置 -->
	<mvc:annotation-driven />

	<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

	<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver"
		p:prefix="/view/" p:suffix=".jsp" />

	<!-- ORACLE数据源配置 -->
	<bean id="DataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!-- 数据库配置省略 -->
	</bean>

	<!-- 整合ibatis -->
	<bean id="sqlMapClient"
		class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="dataSource">
			<ref local="DataSource" />
		</property>
		<property name="configLocations">
			<value>classpath:SqlMapConfig.xml</value>
		</property>
	</bean>

	<!-- 自动注入实现类装填 -->
	<context:component-scan base-package="com.test" />
	<context:annotation-config />

	<!-- 配置事务管理 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref local="DataSource" />
		</property>
	</bean>
	
	<!-- 定义SERVICE事务通知 -->  
	<tx:advice id="txAdvice_service" transaction-manager="transactionManager">  
	    <!-- 定义方法的过滤规则 -->  
	    <tx:attributes>  
	        <!-- 所有方法都使用事务 -->  
	        <tx:method name="*" propagation="REQUIRED"/>  
	        <!-- 定义所有get开头的方法都是只读的 -->  
	        <tx:method name="get*" read-only="true"/>
	    </tx:attributes>  
	</tx:advice> 
	
	<!-- 定义AOP配置 -->
	<aop:config proxy-target-class="true">
		<!-- 适配切入点(service)和事务的通知 -->
		<aop:advisor pointcut="execution(* *..service..impl..*.*(..))"
			advice-ref="txAdvice_service" />
	</aop:config>
	
	<import resource="classpath:app-scheduling.xml"/>
</beans>

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!