• spring源码分析-core.io包里面的类


    前些日子看《深入理解javaweb开发》时,看到第一章java的io流,发觉自己对io流真的不是很熟悉。然后看了下JDK1.7中io包的一点点代码,又看了org.springframework.core.io包的一些类和组织方式,当作是学习吧。总结一下。

    先挂下spring.core.io包的类图,其中接口是方框表示,抽象类带了abstract前缀,剩下那个两个框重贴的则代表实现类。没怎么划过类图,如果有好的画类图工具请推荐给我。

    画得不好的地方就见谅了。注:以下源码匹配的是spring-core-4.1.6Release.jar里面的org.springframework.core.io包。

    先看处于最上层的接口,叫InputStreamSource,里面只有一个抽象方法

    接下是resources,这个接口我们一般都会用到,贴源码:

    public interface Resource extends InputStreamSource {
    
        boolean exists();//文件是否存在
        
        boolean isReadable();//是否可读
    
        boolean isOpen();//资源是否被一个inputstream打开,如果已被打开,则不允许其他流再打开
    
        URL getURL() throws IOException;//获取资源url路径,当不能以url描述时抛出ioException异常
    
        
        URI getURI() throws IOException;//获取资源uri路径,当不能以url描述时抛出ioException异常
    
        File getFile() throws IOException;//获取file,file在IO流中仅仅是一个指向作用
    
        long contentLength() throws IOException;//资源的字节长度,可以拿来算资源的大小
    
        long lastModified() throws IOException;//资源最后修改时间
    
        Resource createRelative(String relativePath) throws IOException;//根据资源相对路径创建资源
    
        String getFilename();//返回文件名
    
        String getDescription();//资源描述
    
    }

    后面是abstractResource,这是个挺重要的类,主要是对resource接口的基本实现,

    public abstract class AbstractResource implements Resource {
    
        @Override
        public boolean exists() {
            //看是否能在硬盘上找到
            try {
                return getFile().exists();
            }
            catch (IOException ex) {
                // 试一下能不能打开输出流
                try {
                    InputStream is = getInputStream();
                    is.close();
                    return true;
                }
                catch (Throwable isEx) {
                    return false;
                }
            }
        }
    
        /**
         * 一般都是可读的,所以默认方法是true
         */
        @Override
        public boolean isReadable() {
            return true;
        }
    
        /**
         * 默认值是false,没有inputStream来读时的默认状态
         */
        @Override
        public boolean isOpen() {
            return false;
        }
    
        /**
         * url这个属性一般只出现在web的IO资源中,网络resource需要override这个方法,其他类型资源敢访问这个方法,抛个异常给他
         */
        @Override
        public URL getURL() throws IOException {
            throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
        }
    
        
        @Override
        public URI getURI() throws IOException {
            URL url = getURL();
            try {
                            //url可以转成uri,uri不能转url
                return ResourceUtils.toURI(url);
            }
            catch (URISyntaxException ex) {
                throw new NestedIOException("Invalid URI [" + url + "]", ex);
            }
        }
    
        /**
         * JDK的File类都是返回绝对路径的File,当一个资源没有绝对路径时,抛个异常给它没毛病
         */
        @Override
        public File getFile() throws IOException {
            throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
        }
    
        /**
         * inputStream读取byte[]字节流,并返回该数组的长度,相当于把文件读了一次
         */
        @Override
        public long contentLength() throws IOException {
            InputStream is = this.getInputStream();
                    //Assert应该是叫断言
            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 {
                                  //一定要在finally中关闭流
                    is.close();
                }
                catch (IOException ex) {
                }
            }
        }
    
        /**
         * 返回getFileForLastModifiedCheck().lastModified()的值,该职为0L,抛个异常给他没毛病
         */
        @Override
        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;
        }
    
        /**
         * 调用getFile方法
         */
        protected File getFileForLastModifiedCheck() throws IOException {
            return getFile();
        }
    
        /**
         * 直接假定相对资源创建不了,再抛个异常给他
         */
        @Override
        public Resource createRelative(String relativePath) throws IOException {
            throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
        }
    
        /**
         * 又是一个假定,假定filename文件名为null
         */
        @Override
        public String getFilename() {
            return null;
        }
    
        /**
         * 很简单,不解释
         */
        @Override
        public String toString() {
            return getDescription();
        }
    
        /**
         * 判断两文件是否相等
         */
        @Override
        public boolean equals(Object obj) {
            return (obj == this ||
                (obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));
        }
    
        /**
         * 返回hashCode
         */
        @Override
        public int hashCode() {
            return getDescription().hashCode();
        }
    
    }
        

    至于其他实现类其实都是在接口和抽象类的基础上去拓展,所以我并不是读得很仔细,先这样子吧。

    小总结:其实为什么要分好几层去继承刚开始我是很不懂的,后面看了源代码和小伙伴的博文后便豁然开朗了。

    1.resources是高度抽象的接口,里面是对所有资源文件的具体方法抽象,但是并不是每个资源都有这个抽象里面的所有方法,所以abstractResource对其进行了一般的实现,

    对于一些并不是所有的Resources都会有方法,例如非网络资源没有url和uri属性,默认方法就直接抛异常了,简单粗暴。举个栗子,不是所有的动物都会游泳,一只猪想游泳,先抛个异常给猪接着先。

    2.resources里面有isOpen(),isReadAble()接口,这是个小技巧吧,类似与模版方法模式的钩子方法,也是很值得我们学习的。

  • 相关阅读:
    centos7 nfs安装
    Rasa在PyCharm中进行debug
    IOS的? !
    IOS中IndexPath
    移动端文本框点击后网页变大的解决办法
    h5 在全屏iphonex中的适配
    net5中得logging保存到文件中
    SQL SERVER 2000数据库置疑处理
    ILSpy源码下载后,编译不过的问题
    Tigase8.x 搭配Mysql8及以上启动时报错(Nodes redirection table: tig_cluster_nodes doesn't exits)的解决方法
  • 原文地址:https://www.cnblogs.com/sundaymorning/p/7570179.html
Copyright © 2020-2023  润新知