spring mvc框架 類初始化2次 解決過程

背景:剛開始作平臺的工做,接觸的就是spring mvc框架,struts沒碰過,沒有任何java web的理論基礎,項目組的這個項目框架是spring mvc + ibatis組合的。css

作了一個項目以爲挺順手,都是小項目,第一個項目還有人稍微指導,第二個項目以後都靠本身作了。有空的時候會稍微改一下這個框架的基礎東西,好比說,去掉一堆沒用的jar包,冗餘太多,部署上傳費時。去掉struts相關的包,最後在沒有提示錯誤時,經過報的異常導入包,去掉了幾十個無用的,方法很土。html

事情原由:由於要用到消息隊列,另外一個同事調試時,發現原本應該是3個消息隊列,卻能夠看到6個,懷疑類初始化2次,寫了個簡單的方法,測試,能夠看到2次初始化。我本身也寫了個,確實看到輸出2次。java

@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

web.xmlspring

<?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.xmlsql

<?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都失效了。spring-mvc

以後由於不想讓消息隊列初始化2次,就把spring-servlet.xml的<context:component-scan base-package="com.test" />改成<context:component-scan base-package="com.test.xxx.*.controller" />,使初始2次的bean縮小範圍。session

這幾天稍微看了一下spring mvc相關的資料,下午試了一下,把applicationContext.xml的<context:component-scan base-package="com.test" />去掉,而且把定時器配置相關的<import resource="classpath:app-scheduling.xml"/>移到spring-servlet.xml中,就ok了,定時器正常執行,網址映射正常。mvc

 

過後心得:看來作項目仍是要學一些基礎理論的。

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

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>
相關文章
相關標籤/搜索