<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0

    Java中,將不同來源的資源抽象成URL,通過注冊不同的handlerURLStreamHandler)來處理不同來源的資源的讀取邏輯,一般handler的類型使用不同前綴(協(xié)議,protocol)來識別,如“file:”、“http:”、“jar:”等,然而URL沒有默認定義相對classpathServletContext等資源的handler,雖然可以注冊自己的URLStreamHandler來解析特定的URL前綴(協(xié)議),比如“classpath:”,然而這需要了解URL的實現(xiàn)機制,而且URL也沒有提供一些基本的方法,如檢查當(dāng)前資源是否存在、檢查當(dāng)前資源是否可讀等方法。因而Spring對其內(nèi)部使用到的資源實現(xiàn)了自己的抽象結(jié)構(gòu):Resource接口來封裝底層資源:

    public interface InputStreamSource {

        InputStream getInputStream() throws IOException;

    }

    public interface Resource extends InputStreamSource {

        boolean exists();

        boolean isReadable();

        boolean isOpen();

        URL getURL() throws IOException;

        URI getURI() throws IOException;

        File getFile() throws IOException;

        long lastModified() throws IOException;

        Resource createRelative(String relativePath) throws IOException;

        String getFilename();

        String getDescription();

    }

    InputStreamSource封裝任何能返回InputStream的類,比如Fileclasspath下的資源、Byte Array等。它只有一個方法定義:getInputStream(),該方法返回一個新的InputStream對象。

    Resource接口抽象了所有Spring內(nèi)部使用到的底層資源:FileURLclasspath等。首先,它定義了三個判斷當(dāng)前資源狀態(tài)的方法:存在性(exists)、可讀性(isReadable)、是否處于打開狀態(tài)(isOpen)。在C語言中,當(dāng)我們拿到一個文件句柄時,我們要調(diào)用open方法打開文件才可以真正讀取該文件,但是在Java中并沒有顯示的定義open方法,一般當(dāng)我們創(chuàng)建一個InputStreamReader時,該資源(文件)就已經(jīng)處于打開狀態(tài)了,因而這里的isOpen方法并不是判斷當(dāng)前資源是否已經(jīng)處于打開的可操作狀態(tài),這里是表示Resource接口所抽象的底層資源是否可以多次調(diào)用getInputStream()方法,如果該方法返回true,則不可以多次調(diào)用getInputStream()方法。在Spring 2.5.6的實現(xiàn)中,只有InputStreamResource類的isOpen()方法返回true,其余都返回false

    另外,Resource接口還提供了不同資源到URLURIFile類型的轉(zhuǎn)換,以及獲取lastModified屬性、文件名(不帶路徑信息的文件名,getFilename())的方法。為了便于操作,Resource還提供了基于當(dāng)前資源創(chuàng)建一個相對資源的方法:createRelative();在錯誤處理中需要詳細的打印出錯的資源文件,因而Resource還提供了getDescription()方法用于在錯誤處理中的打印信息。

    Spring 2.5.6中,所有實現(xiàn)Resource的接口類繼承關(guān)系圖如下:

    即對不同來源的資源文件都有相應(yīng)的Resource實現(xiàn):文件(FileSystemResource)、classpath資源(ClassPathResource)、URL資源(UrlResource)、InputStream資源(InputStreamResource)、Byte數(shù)組(ByteArrayResource)等。

    AbstractResource

    AbstractResource是對Resource的基本實現(xiàn),所有Resource實現(xiàn)類都繼承了該類,所有繼承該類的Resource一般只需要實現(xiàn)以下方法即可:

    public File getFile() throws IOException

    public URL getURL() throws IOException

    public String getDescription()

    public InputStream getInputStream() throws IOException

    該類默認實現(xiàn)中,將toStringequalshashCode都代理給Description屬性;isReadable總是返回true,而isOpen總是返回falseexists方法實現(xiàn)中,先調(diào)用getFile返回的File對象的exists方法,如果失敗,查看是否可以獲得InputStream,如果可以,返回true,否則,返回falsegetURLgetFilecreateRelative方法拋出FileNotFoundException,而getURI則代理給getURL方法。

    ByteArrayResource

    ByteArrayResource是一個簡單的Resource實現(xiàn),它是對二進制數(shù)組的封裝,每次調(diào)用getInputStream時都會以這個二進制數(shù)組作為源創(chuàng)建一個ByteArrayInputStream。它的exists方法總是返回true,而且重寫了equalshashCode的方法,以判斷二進制數(shù)組的內(nèi)容;它的description屬性可以是用戶自定義,也可以使用默認值:resource loaded from byte array

    public final byte[] getByteArray() {

        return this.byteArray;

    }

    public boolean exists() {

        return true;

    }

    public InputStream getInputStream() throws IOException {

        return new ByteArrayInputStream(this.byteArray);

    }

    FileSystemResource

    FileSystemResource是對File的封裝,在構(gòu)建FileSystemResource時可以傳入File對象或路徑字符串(這里的路徑可以是相對路徑,相對路徑是相對于System.getProperty(“user.dir”)的值所在的路徑,也可以是絕對路徑,也可以是“file:”開頭的路徑值),在內(nèi)部會創(chuàng)建相應(yīng)的File對象,并且計算其path值,這里的path是計算完“.”和“..”影響的值(規(guī)格化)。

    getInputStream方法中,使用該File對象創(chuàng)建FileInputStream;而path值作為description屬性、equalshashCode等方法的實現(xiàn);所有其他方法(existsisReadablegetURL等)都代理給File對象;createRelative方法中使用path計算相對路徑,其算法是:找到最后一個路徑分隔符(/),將相對路徑添加到該分隔符之后,傳入的相對路徑可以是以路徑分割符(/)開頭,也可以不以分隔符(/)開頭,他們的效果是一樣的,對相對路徑存在的“.”和“..”會在創(chuàng)建FileSystemResource類時處理。最后,當(dāng)使用將一個目錄的File對象構(gòu)建FileSystemResource時,調(diào)用createRelative方法,其相對路徑的父目錄和當(dāng)前FileSystemResource的父目錄相同,比如使用”/home/Levin/dir1”目錄創(chuàng)建FileSystemResource對象,該Resource對象調(diào)用createRelative,并傳入”file”,那么出現(xiàn)的結(jié)果為”/home/Levin/file”,如果要得到”/home/Levin/dir1/file”,那么構(gòu)建FileSystemResource時,應(yīng)該傳入”/home/Levin/dir1/”字符串。

    public boolean isReadable() {

        return (this.file.canRead() && !this.file.isDirectory());

    }

    public InputStream getInputStream() throws IOException {

        return new FileInputStream(this.file);

    }

    public Resource createRelative(String relativePath) {

        String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);

        return new FileSystemResource(pathToUse);

    }

    public String getDescription() {

        return "file [" + this.file.getAbsolutePath() + "]";

    }

    UrlResource

    UrlResource是對URLURI的封裝。在構(gòu)建UrlResource時可以傳入URLURIPath字符串(帶協(xié)議字符串,如”file:”)。在UrlResource內(nèi)部還會創(chuàng)建一個cleanedUrl,它是規(guī)格化(計算“.”和“..”后的值),該URL將會用于equalshashCode方法的實現(xiàn)。

    getInputStream方法實現(xiàn)中,它使用URL.openConnection()方法獲取URLConnection,后調(diào)用該URLConnectiongetInputStream方法。對getFile()方法,只支持文件系統(tǒng)的資源,即URL字符串的協(xié)議部分為”file:”UrlResource還支持從jarzipvfszipwsjar等內(nèi)部文件,以jar為例,這些文件的字符串表達為:jar:file:/<jarpath>/jarfile.jar!/<filepath>/filename,如jar:file:/E:/Program%20Files/eclipse-juno/plugins/org.junit_4.10.0.v4_10_0_v20120426-0900/junit.jar!/org/junit/Test.class,然而這些內(nèi)部文件本身并沒有lastModified的屬性,因而對這些內(nèi)部文件,UrlResourcejarzip等文件的lastModified視為這些內(nèi)部文件的lastModified屬性。對createRelative方法,直接使用URL提供的構(gòu)造函數(shù),忽略傳入的relativePath中的路徑分隔符“/”。

    public InputStream getInputStream() throws IOException {

        URLConnection con = this.url.openConnection();

        con.setUseCaches(false);

        return con.getInputStream();

    }

    protected File getFileForLastModifiedCheck() throws IOException {

        if (ResourceUtils.isJarURL(this.url)) {

            URL actualUrl = ResourceUtils.extractJarFileURL(this.url);

            return ResourceUtils.getFile(actualUrl);

        }

        else {

            return getFile();

        }

    }

    public Resource createRelative(String relativePath) throws MalformedURLException {

        if (relativePath.startsWith("/")) {

            relativePath = relativePath.substring(1);

        }

        return new UrlResource(new URL(this.url, relativePath));

    }

    ClassPathResource

    classpath下資源的封裝,或者說是對ClassLoader.getResource()方法或Class.getResource()方法的封裝。它支持在當(dāng)前classpath中讀取資源文件。可以傳入相對classpath的文件全路徑名和ClassLoader構(gòu)建ClassPathResource,或忽略ClassLoader采用默認ClassLoader(即Thread Context ClassLoader),此時在getInputStream()方法實現(xiàn)時時會使用ClassLoader.getResourceAsStream()方法,由于使用ClassLoader獲取資源時默認相對于classpath的根目錄,因而構(gòu)造函數(shù)會忽略開頭的“/”字符。ClassPathResource還可以使用文件路徑和Class作為參數(shù)構(gòu)建,此時若文件路徑以“/”開頭,表示該文件為相對于classpath的絕對路徑,否則為相對Class實例的相對路徑,在getInputStream()方法實現(xiàn)時使用Class.getResourceAsStream()方法。

    getFile()方法只支持存在于文件系統(tǒng)中的資源;對lastModified的屬性,若是jarzip等文件中的資源,則采用jarzip文件本身的lastModified屬性;equals會同時判斷pathclassloaderclazz字段,而hashCode則只使用path

    public InputStream getInputStream() throws IOException {

        InputStream is = null;

        if (this.clazz != null) {

            is = this.clazz.getResourceAsStream(this.path);

        }

        else {

            is = this.classLoader.getResourceAsStream(this.path);

        }

        if (is == null) {

            throw new FileNotFoundException(

                    getDescription() + " cannot be opened because it does not exist");

        }

        return is;

    }

    public URL getURL() throws IOException {

        URL url = null;

        if (this.clazz != null) {

            url = this.clazz.getResource(this.path);

        }

        else {

            url = this.classLoader.getResource(this.path);

        }

        if (url == null) {

            throw new FileNotFoundException(

                    getDescription() + " cannot be resolved to URL because it does not exist");

        }

        return url;

    }

    public File getFile() throws IOException {

        return ResourceUtils.getFile(getURL(), getDescription());

    }

    protected File getFileForLastModifiedCheck() throws IOException {

        URL url = getURL();

        if (ResourceUtils.isJarURL(url)) {

            URL actualUrl = ResourceUtils.extractJarFileURL(url);

            return ResourceUtils.getFile(actualUrl);

        }

        else {

            return ResourceUtils.getFile(url, getDescription());

        }

    }

    public Resource createRelative(String relativePath) {

        String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);

        return new ClassPathResource(pathToUse, this.classLoader, this.clazz);

    }

    InputStreamResource

    InputStreamResource是對InputStream的封裝,它接收InputStream作為構(gòu)造函數(shù)參數(shù),它的isOpen總是返回true,并且只能被讀取一次(即getInputStream方法只能被調(diào)用一次),existsisReadable方法也總是返回true。由于它不能被多次讀取,只有當(dāng)不用多次讀取的時候才使用該類,并且只有當(dāng)沒有其他可用Resource類時才使用該類。在Spring內(nèi)部貌似沒有使用它。它只實現(xiàn)了getInputStream方法:

    public InputStream getInputStream() throws IOException, IllegalStateException {

        if (this.read) {

            throw new IllegalStateException("InputStream has already been read - " +

                    "do not use InputStreamResource if a stream needs to be read multiple times");

        }

        this.read = true;

        return this.inputStream;

    }

    DescriptiveResource

    DescriptiveResource是對非物理資源的Description的封裝。它實現(xiàn)了getDescription()方法。ResourceDescription屬性主要用于錯誤處理時能更加準確的打印出錯位置的信息,DescriptiveResource提供對那些需要提供Resource接口中的Description屬性作為錯誤打印信息的方法自定義的描述信息。比如在BeanDefinitionReader中,在僅僅使用InputSource作為源加載BeanDefinition時,就可以使用DescriptiveResource定義自己的Description,從而在出錯信息中可以方便的知道問題源在哪里。

    BeanDefinitionResource

    SpringResource可以用于非物理資源的抽,BeanDefinitionResource是對BeanDefinition的封裝。BeanDefinitionResource類似DescriptiveResource,它也只實現(xiàn)了getDescription()方法,用于在解析某個BeanDefinition出錯時顯示錯誤源信息:

    public String getDescription() {

        return "BeanDefinition defined in " + this.beanDefinition.getResourceDescription();

    }

    ContextResource接口

    Spring中還定義了ContextResource接口,繼承自Resource接口,只包含一個方法:

    public interface ContextResource extends Resource {

        String getPathWithinContext();

    }

    getPathWithContext()方法相對于Context的路徑,如ServletContextPortletContextclasspathFileSystem等,在Spring core中它有兩個實現(xiàn)類FileSystemContextResourceClassPathContextResource,他們分別是FileSystemResourceLoaderDefaultResourceLoader中的內(nèi)部類,他們對getPathWithContext()方法的實現(xiàn)只是簡單的返回path值。

    另外,在Spring Web模塊中,有一個ServletContextResource實現(xiàn)類,它使用ServletContextpath作為參數(shù)構(gòu)造,getInputStreamgetURLgetURIgetFile等方法中將實現(xiàn)代理給ServletContext,其中getPathWithContext方法依然返回path字符串:

    public boolean exists() {

        try {

            URL url = this.servletContext.getResource(this.path);

            return (url != null);

        }

        catch (MalformedURLException ex) {

            return false;

        }

    }

    public InputStream getInputStream() throws IOException {

        InputStream is = this.servletContext.getResourceAsStream(this.path);

        if (is == null) {

            throw new FileNotFoundException("Could not open " + getDescription());

        }

        return is;

    }

    public URL getURL() throws IOException {

        URL url = this.servletContext.getResource(this.path);

        if (url == null) {

            throw new FileNotFoundException(

                    getDescription() + " cannot be resolved to URL because it does not exist");

        }

        return url;

    }

    public File getFile() throws IOException {

        String realPath = WebUtils.getRealPath(this.servletContext, this.path);

        return new File(realPath);

    }

    public Resource createRelative(String relativePath) {

        String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);

        return new ServletContextResource(this.servletContext, pathToUse);

    }

    posted on 2012-12-01 12:51 DLevin 閱讀(6752) 評論(1)  編輯  收藏 所屬分類: Spring

    FeedBack:
    # re: 深入Spring IOC源碼之Resource
    2014-04-14 18:14 | luchy
    你好,我也有閱讀源碼的習(xí)慣,覺得你寫的不錯  回復(fù)  更多評論
      

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 永久看日本大片免费35分钟| 国产亚洲综合久久| 久久久精品国产亚洲成人满18免费网站| 毛片免费观看网站| 亚洲国产欧美日韩精品一区二区三区| 亚欧免费无码aⅴ在线观看| 国产成A人亚洲精V品无码性色| jzzjzz免费观看大片免费| 亚洲一区二区视频在线观看 | 78成人精品电影在线播放日韩精品电影一区亚洲 | 57PAO成人国产永久免费视频| 亚洲精品亚洲人成在线麻豆| 在线看免费观看AV深夜影院| 国产色在线|亚洲| 国产一区二区免费在线| 一区二区三区免费电影| 亚洲Av无码专区国产乱码DVD| 全免费a级毛片免费看| 亚洲精品91在线| 在线精品免费视频无码的| 免费人成大片在线观看播放| 亚洲中文久久精品无码| 91短视频在线免费观看| 亚洲中文字幕久久无码| 亚洲人成影院在线观看| 久久香蕉国产线看免费| 亚洲欧洲无卡二区视頻| 亚洲中文无韩国r级电影| 久久免费观看国产精品| 久久久国产亚洲精品| 久久精品夜色噜噜亚洲A∨| 久久精品人成免费| 亚洲丁香婷婷综合久久| 黑人精品videos亚洲人| 久久久久免费看黄A片APP| 一级免费黄色毛片| 亚洲a级在线观看| 激情97综合亚洲色婷婷五| 国产卡一卡二卡三免费入口| 一级毛片视频免费观看| 亚洲国产中文在线视频|