站在巨人的肩膀,感受抽象的力量

本文深入剖析Spring配置框架,探讨了配置内容获取的Resource抽象,配置内容解析的PropertySource抽象,以及配置项赋值的PropertySources抽象。通过这些抽象,Spring能够灵活处理不同格式和来源的配置,同时解决配置冲突问题,展示了抽象在系统设计中的重要性。
摘要由CSDN通过智能技术生成

通过深入剖析Spring配置的抽象设计,针对性讲解spring配置框架,让你感受抽象的魅力。你说配置就是properties文件,这个抽象层次就很低,因为yaml也可以是配置文件。好的抽象能为系统提供必要的扩展性和可维护性。

1.实现一个类似于Spring的配置框架

何为配置?所谓配置是一种通过调整参数,在不改动软件代码的情况下,改变系统行为的方式。接下来为大家抽象配置必做的三件事情,你看是不是这个理?

  1. 配置内容获取
  2. 配置内容解析
  3. 配置项赋值

如果认同以上观点请往下面接着看。要想实现这样的功能,框架必须要具备一定的灵活性和扩展性。一定要设计得足够抽象,不能写死。比如关于文件格式你如果写死为properties,就没办法支持yaml和xml了。要让设计满足这样的灵活性,有三个核心抽象,你必须要了解这三个抽象分别是Resource抽象(配置内容获取),PropertySource抽象(配置内容解析),以及PropertySources抽象(配置项赋值)。

1.1 配置内容获取:Resource抽象

获取配置内容,是配置系统要做的第一件事情。配置内容(通常是以配置文件的形式)可以从classpath,文件系统或者网络字节流获取。**所以我们需要一个相对大的概念,来统合这些差异性,Resource是个不错的选择,因为它能屏蔽配置内容来源、及格式的差异性。**因为这个抽象程度比较高,所以共性就只剩下对外部资源字节流的获取了。如下所示,我们在Resource抽象中只定义了getInputStream()来获取字节输入流(最好的选择)。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.core.io;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import org.springframework.lang.Nullable;

public interface Resource extends InputStreamSource {
   
    boolean exists();

    default boolean isReadable() {
   
        return this.exists();
    }

    default boolean isOpen() {
   
        return false;
    }

    default boolean isFile() {
   
        return false;
    }

    URL getURL() throws IOException;

    URI getURI() throws IOException;

    File getFile() throws IOException;

    default ReadableByteChannel readableChannel() throws IOException {
   
        return Channels.newChannel(this.getInputStream());
    }

    long contentLength() throws IOException;

    long lastModified() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    @Nullable
    String getFilename();

    String getDescription();
}

不同类型的Resource意味着获取字节流的方式会不一样,比如ClassPathResource是从ClassPath获取文件。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.core.io;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

public class ClassPathResource extends AbstractFileResolvingResource {
   
    private final String path;
    @Nullable
    private ClassLoader classLoader;
    @Nullable
    private Class<?> clazz;

    public ClassPathResource(String path) {
   
        this(path, (ClassLoader)null);
    }

    public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
   
        Assert.notNull(path, "Path must not be null");
        String pathToUse = StringUtils.cleanPath(path);
        if (pathToUse.startsWith("/")) {
   
            pathToUse = pathToUse.substring(1);
        }

        this.path = pathToUse;
        this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
    }

    public ClassPathResource(String path, @Nullable Class<?> clazz) {
   
        Assert.notNull(path, "Path must not be null");
        this.path = StringUtils.cleanPath(path);
        this.clazz = clazz;
    }

    /** @deprecated */
    @Deprecated
    protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
   
        this.path = StringUtils.cleanPath(path);
        this.classLoader = classLoader;
        this.clazz = clazz;
    }

    public final String getPath() {
   
        return this.path;
    }

    @Nullable
    public final ClassLoader getClassLoader() {
   
        return this.clazz != null ? this.clazz.getClassLoader() : this.classLoader;
    }

    public boolean exists() {
   
        return this.resolveURL() != null;
    }

    public boolean isReadable() {
   
        URL url = this.resolveURL();
        return url != null && this.checkReadable(url);
    }

    @Nullable
    protected URL resolveURL() {
   
        try {
   
            if (this.clazz != null) {
   
                return this.clazz.getResource(this.path);
            } else {
   
                return this.classLoader != null ? this.classLoader.getResource(this.path) : ClassLoader.getSystemResource(this.path);
            }
        } catch (IllegalArgumentException var2) {
   
            return null;
        }
    }

    public InputStream getInputStream() throws IOException {
   
        InputStream is;
        if (this.clazz != null) {
   
            is = this.clazz.getResourceAsStream(this.path);
        } else if (this.classLoader != null) {
   
            is = this.classLoader.getResourceAsStream(this.path);
        } else {
   
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }

        if (is == null) {
   
            throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");
        } else {
   
            return is;
        }
    }

    public URL getURL() throws IOException {
   
        URL url = this.resolveURL();
        if (url == null) {
   
            throw new FileNotFoundException(this.getDescription() + " cannot be resolved to URL because it does not exist");
        } else {
   
            return url;
        }
    }

    public Resource createRelative(String relativePath) {
   
        String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
        return this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) : new ClassPathResource(pathToUse, this.classLoader);
    }

    @Nullable
    public String getFilename() {
   
        return StringUtils.getFilename(this.path);
    }

    public String getDescription() {
   
        StringBuilder builder = new<
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值