背景:剛開始作平臺的工做,接觸的就是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>