日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring源码分析——资源访问利器Resource之接口和抽象类分析

發布時間:2023/12/31 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring源码分析——资源访问利器Resource之接口和抽象类分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  從今天開始,一步步走上源碼分析的路。剛開始肯定要從簡單著手。我們先從Java發展史上最強大的框架——Spring、、、旗下的資源抽象接口Resource開始吧。

  我看了好多分析Spring源碼的,每每一開始就是Spring IOC、AOP、BeanFactory這樣的Spring典型模塊,實在看厭了,這些暫且留到以后。我的想法是,分析就分析別人沒分析過的,或者以不同的角度來分析別人分析過的。

  可能很多用了Spring多年的程序員對Resource都了解有限,畢竟訪問資源一般是搭建web工程框架的時候的事情。不過了解它也是非常有好處的。

  這個接口的作用是可以讓我們更方便操縱底層資源。因為JDK操縱底層資源基本就是 java.net.URL 、java.io.File 、java.util.Properties這些。取資源基本是根據絕對路徑或當前類的相對路徑來取。從類路徑或Web容器上下文中獲取資源的時候也不方便。Resource接口提供了更強大的訪問底層資源的能力。

  廢話不多說,看源碼之前先來看一下Resource的類結構。

一、類結構

一、Resource接口

  如圖,Resouce接口并不是一個根接口,它繼承了一個簡單的父接口 InputStreamSource,這個接口只有一個方法,用以返回一個輸入流:

InputStream getInputStream() throws IOException;

  來,直接上Resource接口的源碼,中文是我根據英文注釋自己翻譯的,如下:

public interface Resource extends InputStreamSource {boolean exists(); // 資源是否存在boolean isReadable(); // 資源是否可讀boolean isOpen(); // 資源所代表的句柄是否被一個stream打開了 URL getURL() throws IOException; // 返回資源的URL的句柄 URI getURI() throws IOException; // 返回資源的URI的句柄 File getFile() throws IOException; // 返回資源的File的句柄long contentLength() throws IOException; // 資源內容的長度long lastModified() throws IOException; // 資源最后的修改時間 Resource createRelative(String relativePath) throws IOException; //根據資源的相對路徑創建新資源 String getFilename(); // 資源的文件名 String getDescription(); //資源的描述 }

?  這個沒什么好說的,繼續!

?

二、抽象類AbstractResource

  對于任何的接口而言,這個直接抽象類是重中之重,里面濃縮了接口的大部分公共實現。翻譯后如下:

public abstract class AbstractResource implements Resource {public boolean exists() { //判斷文件是否存在,若判斷過程產生異常(因為會調用SecurityManager來判斷),就關閉對應的流try {return getFile().exists();}catch (IOException ex) {try {InputStream is = getInputStream(); //getInputStream()方法會被子類重寫, is.close();return true;}catch (Throwable isEx) {return false; }}}public boolean isReadable() { // 直接返回true,可讀return true;}public boolean isOpen() { // 直接返回false,未被打開return false;}public URL getURL() throws IOException { // 留給子類重寫throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");}public URI getURI() throws IOException { //返回urlURL url = getURL();try {return ResourceUtils.toURI(url); //將url格式化后返回 }catch (URISyntaxException ex) {throw new NestedIOException("Invalid URI [" + url + "]", ex);}}public File getFile() throws IOException { // 留給子類重寫throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");}// 這個資源內容長度實際就是資源的字節長度,通過全部讀取一遍來判斷。這個方法調用起來很占資源啊!public long contentLength() throws IOException { InputStream is = this.getInputStream();Assert.state(is != null, "resource input stream must not be null"); //斷言try {long size = 0;byte[] buf = new byte[255];int read;while((read = is.read(buf)) != -1) {size += read;}return size;}finally {try {is.close();}catch (IOException ex) {}}}public long lastModified() throws IOException { // 返回資源的最后修改時間long lastModified = getFileForLastModifiedCheck().lastModified();if (lastModified == 0L) {throw new FileNotFoundException(getDescription() +" cannot be resolved in the file system for resolving its last-modified timestamp");}return lastModified;}// 這是Resource接口所沒有的方法,注釋的意思是“返回文件,給時間戳檢查”,要求子類重寫...protected File getFileForLastModifiedCheck() throws IOException {return getFile();}public Resource createRelative(String relativePath) throws IOException { // 留給子類重寫throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());}public String getFilename() { // 默認返回空(假設資源沒有文件名),除非子類重寫return null;}@Overridepublic String toString() { // toString返回文件描述return getDescription();}@Overridepublic boolean equals(Object obj) { // equals比較的就是2個資源描述是否一樣return (obj == this ||(obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));}@Overridepublic int hashCode() { // 返回資源描述的HashCodereturn getDescription().hashCode(); }}

?

結論:

  1、增加了一個方法,protected File getFileForLastModifiedCheck() throws IOException,要求子類實現,如果子類未實現,那么直接返回資源文件。這個方法的具體作用,后面再看實現類。

  2、方法 contentLength() ,是一個很比較重量級的方法,它通過將資源全部讀取一遍來判斷資源的字節數。255字節的緩沖數組來讀取。子類一般會重寫。(調整一下緩沖數組的大小?)

  3、getDescription() 是這個抽象類唯一沒有實現的接口方法,留給子類去實現,資源文件默認的equals()、hashCode() 都通過這個來判斷。

  4、InputStreamSource這個祖先接口的唯一方法 getInputStream()也沒有被實現,留給子類。

?

三、Resource的子接口ContextResource和WritableResource

  這兩個接口繼承于Resource,擁有Resource的全部方法。其中,ContextResource接口增加了一個方法:

String getPathWithinContext(); // 返回上下文內的路徑

  這個方法使得它的實現類有了返回當前上下文路徑的能力。

?

  WritableResource接口增加了2個方法:

boolean isWritable(); // 是否可寫 OutputStream getOutputStream() throws IOException; //返回資源的寫入流

  這個方法使得它的實現類擁有了寫資源的能力。

?

四、重要的抽象類AbstractFileResolvingResource

  這個抽象類繼承自AbstractResource,重寫了AbstractResource的大部分方法。

/** Copyright 2002-2011 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.core.io;import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.net.URLConnection;import org.springframework.util.ResourceUtils;/*** Abstract base class for resources which resolve URLs into File references,* such as {@link UrlResource} or {@link ClassPathResource}.** <p>Detects the "file" protocol as well as the JBoss "vfs" protocol in URLs,* resolving file system references accordingly.** @author Juergen Hoeller* @since 3.0*/ public abstract class AbstractFileResolvingResource extends AbstractResource {@Overridepublic File getFile() throws IOException { // 通過資源的URL得到資源本身,是文件就返回文件,否則返回描述URL url = getURL();if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {return VfsResourceDelegate.getResource(url).getFile();}return ResourceUtils.getFile(url, getDescription());}@Overrideprotected File getFileForLastModifiedCheck() throws IOException { //從<壓縮文件地址>中獲取文件URL url = getURL();if (ResourceUtils.isJarURL(url)) {URL actualUrl = ResourceUtils.extractJarFileURL(url);if (actualUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {return VfsResourceDelegate.getResource(actualUrl).getFile();}return ResourceUtils.getFile(actualUrl, "Jar URL");}else {return getFile();}}protected File getFile(URI uri) throws IOException { // 通過資源uri獲取文件if (uri.getScheme().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {return VfsResourceDelegate.getResource(uri).getFile();}return ResourceUtils.getFile(uri, getDescription());}@Overridepublic boolean exists() { //判斷資源是否存在,如果是文件Url,直接獲取文件判斷,否則,建立連接來判斷。try {URL url = getURL();if (ResourceUtils.isFileURL(url)) {// Proceed with file system resolution...return getFile().exists();}else {// Try a URL connection content-length header...URLConnection con = url.openConnection();ResourceUtils.useCachesIfNecessary(con);HttpURLConnection httpCon =(con instanceof HttpURLConnection ? (HttpURLConnection) con : null);if (httpCon != null) {httpCon.setRequestMethod("HEAD");int code = httpCon.getResponseCode();if (code == HttpURLConnection.HTTP_OK) {return true;}else if (code == HttpURLConnection.HTTP_NOT_FOUND) {return false;}}if (con.getContentLength() >= 0) {return true;}if (httpCon != null) {// no HTTP OK status, and no content-length header: give up httpCon.disconnect();return false;}else {// Fall back to stream existence: can we open the stream?InputStream is = getInputStream();is.close();return true;}}}catch (IOException ex) {return false;}}@Overridepublic boolean isReadable() { // 是否可讀try {URL url = getURL();if (ResourceUtils.isFileURL(url)) {// Proceed with file system resolution...File file = getFile();return (file.canRead() && !file.isDirectory());}else {return true;}}catch (IOException ex) {return false;}}@Overridepublic long contentLength() throws IOException {URL url = getURL();if (ResourceUtils.isFileURL(url)) {// Proceed with file system resolution...return getFile().length();}else {// Try a URL connection content-length header...URLConnection con = url.openConnection();ResourceUtils.useCachesIfNecessary(con);if (con instanceof HttpURLConnection) {((HttpURLConnection) con).setRequestMethod("HEAD");}return con.getContentLength();}}@Overridepublic long lastModified() throws IOException {URL url = getURL();if (ResourceUtils.isFileURL(url) || ResourceUtils.isJarURL(url)) {// Proceed with file system resolution...return super.lastModified();}else {// Try a URL connection last-modified header...URLConnection con = url.openConnection();ResourceUtils.useCachesIfNecessary(con);if (con instanceof HttpURLConnection) {((HttpURLConnection) con).setRequestMethod("HEAD");}return con.getLastModified();}}/*** Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.*/private static class VfsResourceDelegate {public static Resource getResource(URL url) throws IOException {return new VfsResource(VfsUtils.getRoot(url));}public static Resource getResource(URI uri) throws IOException {return new VfsResource(VfsUtils.getRoot(uri));}}} View Code

?

  這個抽象類的子類都需要重寫繼承自AbstractResource的getURL()方法。因為絕大多數方法都依賴這個方法,進行資源在url上的操作。

  所以在查看資源情況的時候,需要根據url建立連接來查看。

?

?

?  PS:框架感覺大都是這樣,不難,設計模式也運用的不多。卻有一種大巧不工、重劍無鋒的感覺,因為代碼運用真的非常簡練。

    分析源碼,很大程度上也鍛煉了自己的英文文檔閱讀能力。共勉。

?

?

轉載于:https://www.cnblogs.com/zrtqsk/p/4015323.html

總結

以上是生活随笔為你收集整理的Spring源码分析——资源访问利器Resource之接口和抽象类分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。