回复
基础篇:JAVA资源之IO、字节编码、URL和Spring.Resource(下篇)
老老老JR老北
发布于 2023-12-5 10:44
浏览
0收藏
6 URL概念及与URL的区别
- URL全称是
Uniform Resource Location
,统一资源定位符 - URL就是URI的子集,它除了标识资源,还提供找到资源的路径;在Java类库中,URI类不包含任何访问资源的方法,它唯一的作用就是解析,而URL类可以打开一个到达资源的流
- 同属URI子集的URN(统一资源名称),只标识资源名称,却不指定如何定位资源;如:
mailto:clswcl@gmail.com
就是一种URN,知道这是个邮箱,却不知道该怎么查找定位 - 通俗就是,URN告诉你有一个地方叫广州,但没有说怎么去,你可以搭动车,也可以搭飞机;URL会告诉你坐飞机去广州,而另一URL则说搭动车去
- URL的一般语法规则
协议://主机名:端口/路径?查询#片段
[protocol]:[//host:port][/path][?query][#fragment]
- URL的构造方法、获取方法
//基于URL模式构造URL实例
public URL(String spec) throws MalformedURLException
//其中file相当于path、query和fragment三个部分组成
public URL(String protocol, String host, int port, String file) throws MalformedURLException
//根据类加载器获取URL
URL systemResource = ClassLoader.getSystemResource(String name)
Enumeration<URL> systemResources = ClassLoader.getSystemResources(String name)
URL resource = Main.class.getResource(String name)
Enumeration<URL> resources = Main.class.getClassLoader().getResources(String name)
- 通过URL获取资源数据的操作函数
public final InputStream openStream() throws java.io.IOException
public URLConnection openConnection() throws java.io.IOException
public final Object getContent() throws java.io.IOException
7 Spring.Resource与Spring资源获取方式
- 讲到资源,就得提下Spring获取资源方式,常用的有两种
○ 通过Resource接口的子类获取资源
○ 通过ResourceLoader接口的子类获取资源
- Spring.Resource 资源操作函数一览
public interface Resource extends InputStreamSource {
//判断资源是否存在
boolean exists(); //
//返回当前资源对应的URL,不能解析则会抛出异常;如ByteArrayResource就不能解析为一个URL
URL getURL() throws IOException;
//返回当前资源对应的URI
URI getURI() throws IOException;
//返回当前资源对应的File
File getFile() throws IOException;
//返回对应的ReadableByteChannel
default ReadableByteChannel readableChannel() throws IOException
- 介绍下Resource相关子类的使用
- 1FileSystemResource:通过文件系统获取资源
Resource resource = new FileSystemResource("D:/example.txt");
File file= new File("example.txt");
Resource resource2 = new FileSystemResource(file);
- 2ByteArrayResource:获取byte数组表示的资源
○ 基于ByteArrayInputStream和字节数组实现,应用场景类似ByteArrayInputStream,缓存byte[]资源
- 3ClassPathResource:获取类路径下的资源
public class ClassPathResource extends AbstractFileResolvingResource {
//ClassPathResource.java 的三个属性
private final String path;
//使用Class或ClassLoader加载资源
private ClassLoader classLoader;
private Class<?> clazz;
---使用方式----
Resource resource = new ClassPathResource("test.txt");
- 4InputStreamResource:接收一个InputStream对象,获取输入流封装的资源
- 5ServletContextResourse:加载ServletContext环境下(相对于Web应用根目录的)路径资源,获取的资源
- 6UrlResource:通过URL访问http资源和FTP资源等
8 ResourceLoader 获取资源
resource.png
- ResourceLoader是为了屏蔽了Resource的具体实现,统一资源的获取方式。你即能从ResourceLoader加载ClassPathResource,也能加载FileSystemResource等
public interface ResourceLoader {
// 默认从类路径加载的资源 前缀: "classpath:",获取ClassPathResource
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
Resource getResource(String location);
- ResourceLoader接口默认对classpath路径下面的资源进行加载
public interface ResourcePatternResolver extends ResourceLoader {
// 默认加载所有路径(包括jar包)下面的文件,"classpath*:", 获取ClassPathResource
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
- ResourcePatternResolver默认会加载所有路径下面的文件,获得ClassPathResource;classpath:只会在class类路径下查找;而classpath*:会扫描所有JAR包及class类路径下出现的文件
//Ant风格表达式 com/smart/**/*.xml
ResourcePatternResoler resolver = new PathMatchingResourcePatternResolver();
Resource resources[] = resolver.getResources("com/smart/**/*.xml");
// ApplicationContext ctx
//FileSystemResource资源
Resource template = ctx.getResource("file:///res.txt");
//UrlResource资源
Resource template = ctx.getResource("https://my.cn/res.txt");
- ResourceLoader方法getResource的locationPattern可设置资源模式前缀来获取非ClassPathResource资源,locationPattern支持Ant风格
前缀 | 示例 | 描述 |
classpath: | classpath:config.xml | 从类路径加载 |
file: | file:///res.txt | 从文件系统加载FileSystemResource |
http: | 加载UrlResource |
9 JAVA.Properties了解一下
- Properties是java自带的配置处理类;Properties加载资源的两种方式
public class Properties extends Hashtable<Object,Object>{
.... //可根据Reader或者InputStream加载properties文件内容
public synchronized void load(Reader reader) throws IOException
public synchronized void load(InputStream inStream) throws IOException
- Properties读取配置示例代码
//res.properties
username = root
password = password
-------代码示例-------------
InputStream input = ClassLoader.getSystemResourceAsStream("res.properties");
Properties prop = new Properties();
prop.load(inputStream); //根据inputStream载入资源
String username = prop.getProperty("username");
10 yml配置资源的读取
- 普通java项目如果需要读取yml可引入jackson-dataformat-yaml,而springboot默认配置支持yml的读取
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.9.5</version>
</dependency>
- 基于jackson-dataformat-yaml对yml配置资源的读取
//res.yml 配置
name: chen
params:
url: http://www.my.com
----------代码示例---------------
InputStream input = ClassLoader.getSystemResourceAsStream("res.yml");
Yaml yml = new Yaml();
Map map = new Yaml().loadAs(input, LinkedHashMap.class);; //根据inputStream载入资源
String name = MapUtils.getString(map,"name"); // chen
//url: http://www.my.com
String url = MapUtils.getString((Map)map.get("params"),"url")
11 优雅地关闭资源,try-with-resource语法和lombok@Cleanup
- 资源的打开就需要对应的关闭,但我们常会忘记关闭资源,或在多处代码关闭资源感到杂乱,有没有简洁的关闭方法呢?
- 自动关闭资源类需实现AutoCloseable接口和配和try-with-resource语法糖使用
public class YSOAPConnection implements AutoCloseable {
private SOAPConnection connection;
public static YSOAPConnection open(SOAPConnectionFactory soapConnectionFactory) throws SOAPException {
YSOAPConnection ySoapConnection = new YSOAPConnection();
SOAPConnection connection = soapConnectionFactory.createConnection();
ySoapConnection.setConnection(connection);
return ySoapConnection;
}
public SOAPMessage call(SOAPMessage request, Object to) throws SOAPException {
return connection.call(request, to);
}
@Override
public void close() throws SOAPException {
if (connection != null) { connection.close(); }
}
}
//自动关闭的资源类使用示例
try (YSOAPConnection soapConnection=YSOAPConnection.open(soapConnectionFactory)){
SOAPMessage soapResponse = soapConnection.call(request, endpoint);
...//数据操作
} catch (Exception e) {
log.error(e.getMessage(), e);
...
}
- lombok注解@Cleanup,对象生命周期结束时会调用
public void close()
;对象需实现AutoCloseable接口
import lombok.Cleanup;
@Cleanup // @Cleanup的使用
YSOAPConnection soapConnection=YSOAPConnection.open(soapConnectionFactory)
12 资源不关闭,会导致什么最坏的结果
- JDK的原生资源类不关闭,它也不会永远存在。JVM会借助finalize自动关闭它,例如FileInputStream
//FileInputStream.java - JDK8
//jdk8的FileInputStream重写了finalize,保证对象回收前开启的资源被关闭
protected void finalize () throws IOException {
if (guard != null) {
guard.warnIfOpen();
}
if ((fd != null) && (fd != FileDescriptor.in)) {
close();
}
}
- 在JDK9后,用Cleaner机制代替了finalize机制;Cleaner机制自动回收的对象同样需要实现AutoCloseable接口;Cleaner是基于PhantomReference实现的;对实现细节感兴趣的同学,可自行查阅下相关文档
- 但是使用JDK的提供的资源关闭机制的,那么资源的关闭比手动关闭时要延后很长时间的。据测试,使用try-with-resources关闭资源,并让垃圾回收器回收它的时间在12纳秒。而使用finalizer机制,时间增加到550纳秒
- 不及时关闭资源,就会占用资源,影响其他线程的执行;比如linux的文件资源,linux进程默认能打开的最大文件数是1024(有的是2048,此数值是可配置的);如果一个线程持有十几个文件资源,还要等550纳秒用finalizer机制释放资源,同进程的其他线程都等到花谢了
参考文章
- 从源码角度理解Java设计模式——装饰者模式[1]
- Java中的管道流[2]
- InputStream乱码问题的解决方法[3]
- 未关闭的文件流会引起内存泄露么?[4]
- char类型与字符编码[5]
- 结合Java详谈字符编码和字符集[6]
- Cleaner 对比 finalize 对比 AutoCloseable[7]
文章转载自公众号:潜行前行
分类
标签
已于2023-12-5 10:44:20修改
赞
收藏
回复
相关推荐