文件資源的操做是應用程序中常見的功能,如當上傳一個文件後將其保存在特定目錄下,從指定地址加載一個配置文件等等。咱們通常使用 JDK 的 I/O 處理類完成這些操做,但對於通常的應用程序來講,JDK 的這些操做類所提供的方法過於底層,直接使用它們進行文件操做不但程序編寫複雜並且容易產生錯誤。相比於 JDK 的 File,Spring 的 Resource 接口(資源概念的描述接口)抽象層面更高且涵蓋面更廣,Spring 提供了許多方便易用的資源操做工具類,它們大大下降資源操做的複雜度,同時具備更強的普適性。這些工具類不依賴於 Spring 容器,這意味着您能夠在程序中象通常普通類同樣使用它們。html
Spring 定義了一個 org.springframework.core.io.Resource 接口,Resource 接口是爲了統一各類類型不一樣的資源而定義的,Spring 提供了若干 Resource 接口的實現類,這些實現類能夠輕鬆地加載不一樣類型的底層資源,並提供了獲取文件名、URL 地址以及資源內容的操做方法。java
訪問文件資源web
假設有一個文件地位於 Web 應用的類路徑下,您能夠經過如下方式對這個文件資源進行訪問:spring
經過 FileSystemResource 以文件系統絕對路徑的方式進行訪問;apache
經過 ClassPathResource 以類路徑的方式進行訪問;緩存
經過 ServletContextResource 以相對於 Web 應用根目錄的方式進行訪問。服務器
相比於經過 JDK 的 File 類訪問文件資源的方式,Spring 的 Resource 實現類無疑提供了更加靈活的操做方式,您能夠根據狀況選擇適合的 Resource 實現類訪問資源。下面,咱們分別經過 FileSystemResource 和 ClassPathResource 訪問同一個文件資源:app
package com.baobaotao.io; import java.io.IOException; import java.io.InputStream; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; public class FileSourceExample { public static void main(String[] args) { try { String filePath = "D:/masterSpring/chapter23/webapp/WEB-INF/classes/conf/file1.txt"; // ① 使用系統文件路徑方式加載文件 Resource res1 = new FileSystemResource(filePath); // ② 使用類路徑方式加載文件 Resource res2 = new ClassPathResource("conf/file1.txt"); InputStream ins1 = res1.getInputStream(); InputStream ins2 = res2.getInputStream(); System.out.println("res1:"+res1.getFilename()); System.out.println("res2:"+res2.getFilename()); } catch (IOException e) { e.printStackTrace(); } } }
在獲取資源後,您就能夠經過 Resource 接口定義的多個方法訪問文件的數據和其它的信息:如您能夠經過 getFileName() 獲取文件名,經過 getFile() 獲取資源對應的 File 對象,經過 getInputStream() 直接獲取文件的輸入流。此外,您還能夠經過 createRelative(String relativePath) 在資源相對地址上建立新的資源。框架
在 Web 應用中,您還能夠經過 ServletContextResource 以相對於 Web 應用根目錄的方式訪問文件資源,以下所示:webapp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <jsp:directive.page import=" org.springframework.web.context.support.ServletContextResource"/> <jsp:directive.page import="org.springframework.core.io.Resource"/> <% // ① 注意文件資源地址以相對於 Web 應用根路徑的方式表示 Resource res3 = new ServletContextResource(application, "/WEB-INF/classes/conf/file1.txt"); out.print(res3.getFilename()); %>
對於位於遠程服務器(Web 服務器或 FTP 服務器)的文件資源,您則能夠方便地經過 UrlResource 進行訪問。
爲了方便訪問不一樣類型的資源,您必須使用相應的 Resource 實現類,是否能夠在不顯式使用 Resource 實現類的狀況下,僅根據帶特殊前綴的資源地址直接加載文件資源呢? Spring 提供了一個 ResourceUtils 工具類,它支持「classpath:」和「file:」的地址前綴,它可以從指定的地址加載文件資源,請看下面的例子:
package com.baobaotao.io; import java.io.File; import org.springframework.util.ResourceUtils; public class ResourceUtilsExample { public static void main(String[] args) throws Throwable{ File clsFile = ResourceUtils.getFile("classpath:conf/file1.txt"); System.out.println(clsFile.isFile()); String httpFilePath = "file:D:/masterSpring/chapter23/src/conf/file1.txt"; File httpFile = ResourceUtils.getFile(httpFilePath); System.out.println(httpFile.isFile()); } }
ResourceUtils 的 getFile(String resourceLocation) 方法支持帶特殊前綴的資源地址,這樣,咱們就能夠在不和 Resource 實現類打交道的狀況下使用 Spring 文件資源加載的功能了。
本地化文件資源
本地化文件資源是一組經過本地化標識名進行特殊命名的文件,Spring 提供的 LocalizedResourceHelper 容許經過文件資源基名和本地化實體獲取匹配的本地化文件資源並以 Resource 對象返回。假設在類路徑的 i18n 目錄下,擁有一組基名爲 message 的本地化文件資源,咱們經過如下實例演示獲取對應中國大陸和美國的本地化文件資源:
package com.baobaotao.io; import java.util.Locale; import org.springframework.core.io.Resource; import org.springframework.core.io.support.LocalizedResourceHelper; public class LocaleResourceTest { public static void main(String[] args) { LocalizedResourceHelper lrHalper = new LocalizedResourceHelper(); // ① 獲取對應美國的本地化文件資源 Resource msg_us = lrHalper.findLocalizedResource("i18n/message", ".properties", Locale.US); // ② 獲取對應中國大陸的本地化文件資源 Resource msg_cn = lrHalper.findLocalizedResource("i18n/message", ".properties", Locale.CHINA); System.out.println("fileName(us):"+msg_us.getFilename()); System.out.println("fileName(cn):"+msg_cn.getFilename()); } }
雖然 JDK 的 java.util.ResourceBundle 類也能夠經過類似的方式獲取本地化文件資源,可是其返回的是 ResourceBundle 類型的對象。若是您決定統一使用 Spring 的 Resource 接表徵文件資源,那麼 LocalizedResourceHelper 就是獲取文件資源的很是適合的幫助類了。
在使用各類 Resource 接口的實現類加載文件資源後,常常須要對文件資源進行讀取、拷貝、轉存等不一樣類型的操做。您能夠經過 Resource 接口所提供了方法完成這些功能,不過在大多數狀況下,經過 Spring 爲 Resource 所配備的工具類完成文件資源的操做將更加方便。
文件內容拷貝
第一個咱們要認識的是 FileCopyUtils,它提供了許多一步式的靜態操做方法,可以將文件內容拷貝到一個目標 byte[]、String 甚至一個輸出流或輸出文件中。下面的實例展現了 FileCopyUtils 具體使用方法:
package com.baobaotao.io; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileReader; import java.io.OutputStream; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.util.FileCopyUtils; public class FileCopyUtilsExample { public static void main(String[] args) throws Throwable { Resource res = new ClassPathResource("conf/file1.txt"); // ① 將文件內容拷貝到一個 byte[] 中 byte[] fileData = FileCopyUtils.copyToByteArray(res.getFile()); // ② 將文件內容拷貝到一個 String 中 String fileStr = FileCopyUtils.copyToString(new FileReader(res.getFile())); // ③ 將文件內容拷貝到另外一個目標文件 FileCopyUtils.copy(res.getFile(), new File(res.getFile().getParent()+ "/file2.txt")); // ④ 將文件內容拷貝到一個輸出流中 OutputStream os = new ByteArrayOutputStream(); FileCopyUtils.copy(res.getInputStream(), os); } }
每每咱們都經過直接操做 InputStream 讀取文件的內容,可是流操做的代碼是比較底層的,代碼的面向對象性並不強。經過 FileCopyUtils 讀取和拷貝文件內容易於操做且至關直觀。如在 ① 處,咱們經過 FileCopyUtils 的 copyToByteArray(File in) 方法就能夠直接將文件內容讀到一個 byte[] 中;另外一個可用的方法是 copyToByteArray(InputStream in),它將輸入流讀取到一個 byte[] 中。
若是是文本文件,您可能但願將文件內容讀取到 String 中,此時您可使用 copyToString(Reader in) 方法,如 ② 所示。使用 FileReader 對 File 進行封裝,或使用 InputStreamReader 對 InputStream 進行封裝就能夠了。
FileCopyUtils 還提供了多個將文件內容拷貝到各類目標對象中的方法,這些方法包括:
方法 | 說明 |
---|---|
static void copy(byte[] in, File out) |
將 byte[] 拷貝到一個文件中 |
static void copy(byte[] in, OutputStream out) |
將 byte[] 拷貝到一個輸出流中 |
static int copy(File in, File out) |
將文件拷貝到另外一個文件中 |
static int copy(InputStream in, OutputStream out) |
將輸入流拷貝到輸出流中 |
static int copy(Reader in, Writer out) |
將 Reader 讀取的內容拷貝到 Writer 指向目標輸出中 |
static void copy(String in, Writer out) |
將字符串拷貝到一個 Writer 指向的目標中 |
在實例中,咱們雖然使用 Resource 加載文件資源,但 FileCopyUtils 自己和 Resource 沒有任何關係,您徹底能夠在基於 JDK I/O API 的程序中使用這個工具類。
屬性文件操做
咱們知道能夠經過 java.util.Properties 的 load(InputStream inStream) 方法從一個輸入流中加載屬性資源。Spring 提供的 PropertiesLoaderUtils 容許您直接經過基於類路徑的文件地址加載屬性資源,請看下面的例子:
package com.baobaotao.io; import java.util.Properties; import org.springframework.core.io.support.PropertiesLoaderUtils; public class PropertiesLoaderUtilsExample { public static void main(String[] args) throws Throwable { // ① jdbc.properties 是位於類路徑下的文件 Properties props = PropertiesLoaderUtils.loadAllProperties("jdbc.properties"); System.out.println(props.getProperty("jdbc.driverClassName")); } }
通常狀況下,應用程序的屬性文件都放置在類路徑下,因此 PropertiesLoaderUtils 比之於 Properties#load(InputStream inStream) 方法顯然具備更強的實用性。此外,PropertiesLoaderUtils 還能夠直接從 Resource 對象中加載屬性資源:
方法 | 說明 |
---|---|
static Properties loadProperties(Resource resource) |
從 Resource 中加載屬性 |
static void fillProperties(Properties props, Resource resource) |
將 Resource 中的屬性數據添加到一個已經存在的 Properties 對象中 |
特殊編碼的資源
當您使用 Resource 實現類加載文件資源時,它默認採用操做系統的編碼格式。若是文件資源採用了特殊的編碼格式(如 UTF-8),則在讀取資源內容時必須事先經過 EncodedResource 指定編碼格式,不然將會產生中文亂碼的問題。
package com.baobaotao.io; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.EncodedResource; import org.springframework.util.FileCopyUtils; public class EncodedResourceExample { public static void main(String[] args) throws Throwable { Resource res = new ClassPathResource("conf/file1.txt"); // ① 指定文件資源對應的編碼格式(UTF-8) EncodedResource encRes = new EncodedResource(res,"UTF-8"); // ② 這樣才能正確讀取文件的內容,而不會出現亂碼 String content = FileCopyUtils.copyToString(encRes.getReader()); System.out.println(content); } }
EncodedResource 擁有一個 getResource() 方法獲取 Resource,但該方法返回的是經過構造函數傳入的原 Resource 對象,因此必須經過 EncodedResource#getReader() 獲取應用編碼後的 Reader 對象,而後再經過該 Reader 讀取文件的內容。
您幾乎老是使用 Spring 框架開發 Web 的應用,Spring 爲 Web 應用提供了不少有用的工具類,這些工具類能夠給您的程序開發帶來不少便利。在這節裏,咱們將逐一介紹這些工具類的使用方法。
當您在控制器、JSP 頁面中想直接訪問 Spring 容器時,您必須事先獲取 WebApplicationContext 對象。Spring 容器在啓動時將 WebApplicationContext 保存在 ServletContext 的屬性列表中,經過 WebApplicationContextUtils 工具類能夠方便地獲取 WebApplicationContext 對象。
WebApplicationContextUtils
當 Web 應用集成 Spring 容器後,表明 Spring 容器的 WebApplicationContext 對象將以 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 爲鍵存放在 ServletContext 屬性列表中。您固然能夠直接經過如下語句獲取 WebApplicationContext:
WebApplicationContext wac = (WebApplicationContext)servletContext. getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
但經過位於 org.springframework.web.context.support 包中的 WebApplicationContextUtils 工具類獲取 WebApplicationContext 更方便:
WebApplicationContext wac =WebApplicationContextUtils. getWebApplicationContext(servletContext);
當 ServletContext 屬性列表中不存在 WebApplicationContext 時,getWebApplicationContext() 方法不會拋出異常,它簡單地返回 null。若是後續代碼直接訪問返回的結果將引起一個 NullPointerException 異常,而 WebApplicationContextUtils 另外一個 getRequiredWebApplicationContext(ServletContext sc) 方法要求 ServletContext 屬性列表中必定要包含一個有效的 WebApplicationContext 對象,不然立刻拋出一個 IllegalStateException 異常。咱們推薦使用後者,由於它能提早發現錯誤的時間,強制開發者搭建好必備的基礎設施。
WebUtils
位於 org.springframework.web.util 包中的 WebUtils 是一個很是好用的工具類,它對不少 Servlet API 提供了易用的代理方法,下降了訪問 Servlet API 的複雜度,能夠將其當作是經常使用 Servlet API 方法的門面類。
下面這些方法爲訪問 HttpServletRequest 和 HttpSession 中的對象和屬性帶來了方便:
方法 | 說明 |
---|---|
Cookie getCookie(HttpServletRequest request, String name) |
獲取 HttpServletRequest 中特定名字的 Cookie 對象。若是您須要建立 Cookie, Spring 也提供了一個方便的 CookieGenerator 工具類; |
Object getSessionAttribute(HttpServletRequest request, String name) |
獲取 HttpSession 特定屬性名的對象,不然您必須經過 request.getHttpSession.getAttribute(name) 完成相同的操做; |
Object getRequiredSessionAttribute(HttpServletRequest request, String name) |
和上一個方法相似,只不過強制要求 HttpSession 中擁有指定的屬性,不然拋出異常; |
String getSessionId(HttpServletRequest request) |
獲取 Session ID 的值; |
void exposeRequestAttributes(ServletRequest request, Map attributes) |
將 Map 元素添加到 ServletRequest 的屬性列表中,當請求被導向(forward)到下一個處理程序時,這些請求屬性就能夠被訪問到了; |
此外,WebUtils 還提供了一些和 ServletContext 相關的方便方法:
方法 | 說明 |
---|---|
String getRealPath(ServletContext servletContext, String path) |
獲取相對路徑對應文件系統的真實文件路徑; |
File getTempDir(ServletContext servletContext) |
獲取 ServletContex 對應的臨時文件地址,它以 File 對象的形式返回。 |
下面的片段演示了使用 WebUtils 從 HttpSession 中獲取屬性對象的操做:
protected Object formBackingObject(HttpServletRequest request) throws Exception { UserSession userSession = (UserSession) WebUtils.getSessionAttribute(request, "userSession"); if (userSession != null) { return new AccountForm(this.petStore.getAccount( userSession.getAccount().getUsername())); } else { return new AccountForm(); } }
Spring 爲 Web 應用提供了幾個過濾器和監聽器,在適合的時間使用它們,能夠解決一些常見的 Web 應用問題。
延遲加載過濾器
Hibernate 容許對關聯對象、屬性進行延遲加載,可是必須保證延遲加載的操做限於同一個 Hibernate Session 範圍以內進行。若是 Service 層返回一個啓用了延遲加載功能的領域對象給 Web 層,當 Web 層訪問到那些須要延遲加載的數據時,因爲加載領域對象的 Hibernate Session 已經關閉,這些致使延遲加載數據的訪問異常。
Spring 爲此專門提供了一個 OpenSessionInViewFilter 過濾器,它的主要功能是使每一個請求過程綁定一個 Hibernate Session,即便最初的事務已經完成了,也能夠在 Web 層進行延遲加載的操做。
OpenSessionInViewFilter 過濾器將 Hibernate Session 綁定到請求線程中,它將自動被 Spring 的事務管理器探測到。因此 OpenSessionInViewFilter 適用於 Service 層使用 HibernateTransactionManager 或 JtaTransactionManager 進行事務管理的環境,也能夠用於非事務只讀的數據操做中。
要啓用這個過濾器,必須在 web.xml 中對此進行配置:
… <filter> <filter-name>hibernateFilter</filter-name> <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>*.html</url-pattern> </filter-mapping> …
上面的配置,咱們假設使用 .html 的後綴做爲 Web 框架的 URL 匹配模式,若是您使用 Struts 等 Web 框架,能夠將其改成對應的「*.do」模型。
中文亂碼過濾器
在您經過表單向服務器提交數據時,一個經典的問題就是中文亂碼問題。雖然咱們全部的 JSP 文件和頁面編碼格式都採用 UTF-8,但這個問題仍是會出現。解決的辦法很簡單,咱們只須要在 web.xml 中配置一個 Spring 的編碼轉換過濾器就能夠了:
<web-app> <!---listener 的配置 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class> org.springframework.web.filter.CharacterEncodingFilter ① Spring 編輯過濾器 </filter-class> <init-param> ② 編碼方式 <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> ③ 強制進行編碼轉換 <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> ② 過濾器的匹配 URL <filter-name>encodingFilter</filter-name> <url-pattern>*.html</url-pattern> </filter-mapping> <!---servlet 的配置 --> </web-app>
這樣全部以 .html 爲後綴的 URL 請求的數據都會被轉碼爲 UTF-8 編碼格式,表單中文亂碼的問題就能夠解決了。
請求跟蹤日誌過濾器
除了以上兩個經常使用的過濾器外,還有兩個在程序調試時可能會用到的請求日誌跟蹤過濾器,它們會將請求的一些重要信息記錄到日誌中,方便程序的調試。這兩個日誌過濾器只有在日誌級別爲 DEBUG 時纔會起做用:
方法 | 說明 |
---|---|
org.springframework.web.filter.ServletContextRequestLoggingFilter |
該過濾器將請求的 URI 記錄到 Common 日誌中(如經過 Log4J 指定的日誌文件); |
org.springframework.web.filter.ServletContextRequestLoggingFilter |
該過濾器將請求的 URI 記錄到 ServletContext 日誌中。 |
如下是日誌過濾器記錄的請求跟蹤日誌的片段:
(JspServlet.java:224) - JspEngine --> /htmlTest.jsp (JspServlet.java:225) - ServletPath: /htmlTest.jsp (JspServlet.java:226) - PathInfo: null (JspServlet.java:227) - RealPath: D:\masterSpring\chapter23\webapp\htmlTest.jsp (JspServlet.java:228) - RequestURI: /baobaotao/htmlTest.jsp …
經過這個請求跟蹤日誌,程度調試者能夠詳細地查看到有哪些請求被調用,請求的參數是什麼,請求是否正確返回等信息。雖然這兩個請求跟蹤日誌過濾器通常在程序調試時使用,可是即便程序部署不將其從 web.xml 中移除也不會有大礙,由於只要將日誌級別設置爲 DEBUG 以上級別,它們就不會輸出請求跟蹤日誌信息了。
轉存 Web 應用根目錄監聽器和 Log4J 監聽器
Spring 在 org.springframework.web.util 包中提供了幾個特殊用途的 Servlet 監聽器,正確地使用它們能夠完成一些特定需求的功能。好比某些第三方工具支持經過 ${key} 的方式引用系統參數(便可以經過 System.getProperty() 獲取的屬性),WebAppRootListener 能夠將 Web 應用根目錄添加到系統參數中,對應的屬性名能夠經過名爲「webAppRootKey」的 Servlet 上下文參數指定,默認爲「webapp.root」。下面是該監聽器的具體的配置:
… <context-param> <param-name>webAppRootKey</param-name> <param-value>baobaotao.root</param-value> ① Web 應用根目錄以該屬性名添加到系統參數中 </context-param> … ② 負責將 Web 應用根目錄以 webAppRootKey 上下文參數指定的屬性名添加到系統參數中 <listener> <listener-class> org.springframework.web.util.WebAppRootListener </listener-class> </listener> …
這樣,您就能夠在程序中經過 System.getProperty("baobaotao.root") 獲取 Web 應用的根目錄了。不過更常見的使用場景是在第三方工具的配置文件中經過 ${baobaotao.root} 引用 Web 應用的根目錄。好比如下的 log4j.properties 配置文件就經過 ${baobaotao.root} 設置了日誌文件的地址:
log4j.rootLogger=INFO,R log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=${baobaotao.root}/WEB-INF/logs/log4j.log ① 指定日誌文件的地址 log4j.appender.R.MaxFileSize=100KB log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n
另外一個專門用於 Log4J 的監聽器是 Log4jConfigListener。通常狀況下,您必須將 Log4J 日誌配置文件以 log4j.properties 爲文件名並保存在類路徑下。Log4jConfigListener 容許您經過 log4jConfigLocation Servlet 上下文參數顯式指定 Log4J 配置文件的地址,以下所示:
① 指定 Log4J 配置文件的地址 <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/log4j.properties</param-value> </context-param> … ② 使用該監聽器初始化 Log4J 日誌引擎 <listener> <listener-class> org.springframework.web.util.Log4jConfigListener </listener-class> </listener> …
一些 Web 應用服務器(如 Tomcat)不會爲不一樣的 Web 應用使用獨立的系統參數,也就是說,應用服務器上全部的 Web 應用都共享同一個系統參數對象。這時,您必須經過 webAppRootKey 上下文參數爲不一樣 Web 應用指定不一樣的屬性名:如第一個 Web 應用使用 webapp1.root 而第二個 Web 應用使用 webapp2.root 等,這樣纔不會發生後者覆蓋前者的問題。此外,WebAppRootListener 和 Log4jConfigListener 都只能應用在 Web 應用部署後 WAR 文件會解包的 Web 應用服務器上。一些 Web 應用服務器不會將 Web 應用的 WAR 文件解包,整個 Web 應用以一個 WAR 包的方式存在(如 Weblogic),此時由於沒法指定對應文件系統的 Web 應用根目錄,使用這兩個監聽器將會發生問題。
Log4jConfigListener 監聽器包括了 WebAppRootListener 的功能,也就是說,Log4jConfigListener 會自動完成將 Web 應用根目錄以 webAppRootKey 上下文參數指定的屬性名添加到系統參數中,因此當您使用 Log4jConfigListener 後,就沒有必須再使用 WebAppRootListener 了。
Introspector 緩存清除監聽器
Spring 還提供了一個名爲 org.springframework.web.util.IntrospectorCleanupListener 的監聽器。它主要負責處理由 JavaBean Introspector 功能而引發的緩存泄露。IntrospectorCleanupListener 監聽器在 Web 應用關閉的時會負責清除 JavaBean Introspector 的緩存,在 web.xml 中註冊這個監聽器能夠保證在 Web 應用關閉的時候釋放與其相關的 ClassLoader 的緩存和類引用。若是您使用了 JavaBean Introspector 分析應用中的類,Introspector 緩存會保留這些類的引用,結果在應用關閉的時候,這些類以及 Web 應用相關的 ClassLoader 不能被垃圾回收。不幸的是,清除 Introspector 的惟一方式是刷新整個緩存,這是由於無法準確判斷哪些是屬於本 Web 應用的引用對象,哪些是屬於其它 Web 應用的引用對象。因此刪除被緩存的 Introspection 會致使將整個 JVM 全部應用的 Introspection 都刪掉。須要注意的是,Spring 託管的 Bean 不須要使用這個監聽器,由於 Spring 的 Introspection 所使用的緩存在分析完一個類以後會立刻從 javaBean Introspector 緩存中清除掉,並將緩存保存在應用程序特定的 ClassLoader 中,因此它們通常不會致使內存資源泄露。可是一些類庫和框架每每會產生這個問題。例如 Struts 和 Quartz 的 Introspector 的內存泄漏會致使整個的 Web 應用的 ClassLoader 不能進行垃圾回收。在 Web 應用關閉以後,您還會看到此應用的全部靜態類引用,這個錯誤固然不是由這個類自身引發的。解決這個問題的方法很簡單,您僅需在 web.xml 中配置 IntrospectorCleanupListener 監聽器就能夠了:
<listener> <listener-class> org.springframework.web.util.IntrospectorCleanupListener </listener-class> </listener>
本文介紹了一些經常使用的 Spring 工具類,其中大部分 Spring 工具類不但能夠在基於 Spring 的應用中使用,還能夠在其它的應用中使用。使用 JDK 的文件操做類在訪問類路徑相關、Web 上下文相關的文件資源時,每每顯得拖泥帶水、拐彎抹角,Spring 的 Resource 實現類使這些工做變得輕鬆了許多。
在 Web 應用中,有時你但願直接訪問 Spring 容器,獲取容器中的 Bean,這時使用 WebApplicationContextUtils 工具類從 ServletContext 中獲取 WebApplicationContext 是很是方便的。WebUtils 爲訪問 Servlet API 提供了一套便捷的代理方法,您能夠經過 WebUtils 更好的訪問 HttpSession 或 ServletContext 的信息。
Spring 提供了幾個 Servlet 過濾器和監聽器,其中 ServletContextRequestLoggingFilter 和 ServletContextRequestLoggingFilter 能夠記錄請求訪問的跟蹤日誌,你能夠在程序調試時使用它們獲取請求調用的詳細信息。WebAppRootListener 能夠將 Web 應用的根目錄以特定屬性名添加到系統參數中,以便第三方工具類經過 ${key} 的方式進行訪問。Log4jConfigListener 容許你指定 Log4J 日誌配置文件的地址,且能夠在配置文件中經過 ${key} 的方式引用 Web 應用根目錄,若是你須要在 Web 應用相關的目錄建立日誌文件,使用 Log4jConfigListener 能夠很容易地達到這一目標。
Web 應用的內存泄漏是最讓開發者頭疼的問題,雖然不正確的程序編寫多是這一問題的根源,也有多是一些第三方框架的 JavaBean Introspector 緩存得不到清除而致使的,Spring 專門爲解決這一問題配備了 IntrospectorCleanupListener 監聽器,它只要簡單在 web.xml 中聲明該監聽器就能夠了。