spring5/springboot2源码学习 -- ProtocolResolver

接口定义

@FunctionalInterface
public interface ProtocolResolver {
    Resource resolve(String location, ResourceLoader resourceLoader);
}

作用

可以用于自定义协议解析,比如spring就有一个 “classpath:”开头的特定协议(但是spring并不是自定义ProtocolResolver 实现来完成这个功能的)。
在spring中,一个通过一个字符串表示的路径,通过ResourceLoader加载成为Resource过程的方法如下:

public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        //可以看到,如果我们自定义了ProtocolResolver,是会优先调用的
        for (ProtocolResolver protocolResolver : this.protocolResolvers) {
            Resource resource = protocolResolver.resolve(location, this);
            //根据返回值是否为null判断自定义的ProtocolResolver是否解决了resource的加载
            if (resource != null) {
                return resource;
            }
        }
                //根据location的开头判断是哪一种Resource,eg: http,classpath,file等
        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }
        else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            try {
                // Try to parse the location as a URL...
                URL url = new URL(location);
                return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
            }
            catch (MalformedURLException ex) {
                // No URL -> resolve as resource path.
                return getResourceByPath(location);
            }
        }
    }

示例

比如我现在要自定义一个以“my”开头的协议,当Resource的location字符串以my开头时,我就去classpath底下找(其实这就是classpath前缀的作用):

自定义一个ProtocolResolver:

package pk.ext;

import org.springframework.core.io.ProtocolResolver;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.util.logging.Logger;

/**
 * @author pk
 * @date 2018/1/16
 */
public class MyProtocolResolver implements ProtocolResolver {
    private static final Logger logger = Logger.getLogger(MyProtocolResolver.class.getName());

    @Override
    public Resource resolve(String location, ResourceLoader resourceLoader) {
        if (location.startsWith("my")) {
            logger.info("MyProtocolResolver resolve this resource....");
            return resourceLoader.getResource(location.replace("my", "classpath"));
        }
        return null;
    }
}

加载resource:


/**
 * @author pk
 * @date 2018/1/16
 */
public class Main2 {

    private static final Logger logger = Logger.getLogger(Main2.class.getName());

    public static void main(String[] args) throws IOException {
    //这里实例化一个ApplicationContext也可以
//      AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig1.class, MyConfig2.class);

        DefaultResourceLoader bf = new DefaultResourceLoader();
        //@1
        //bf.addProtocolResolver(new MyProtocolResolver());

        Resource resource = bf.getResource("my:a.txt");

        InputStream inputStream = resource.getInputStream();

        byte[] bytes = new byte[2];
        inputStream.read(bytes);

        logger.info(new String(bytes));

    }
}

当我们把 1处的添加ProtocolResolver注释掉的时候,运行会报错:

Exception in thread "main" java.io.FileNotFoundException: class path resource [my:a.txt] cannot be opened because it does not exist
    at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180)
    at pk.Main2.main(Main2.java:32)

取消注释,则可以正常加载到classpath下的a.txt文件

注意点

仅仅实现ResourceLoader接口,是不具备解析“classpath*”开头的location的;
解析classpath*的能力由ResourcePatternResolver接口定义;
AbstractApplicationContext中的默认实现是PathMatchingResourcePatternResolver

结论

可以用于自定义解析resource的实现
好吧,其实好像不太可能会需要自定义一个加载resource的协议,但是毕竟知识点么,技多不压身

水平有限,最近在看spring源码,分享学习过程,希望对各位有点微小的帮助。
如有错误,请指正~

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值