整体过程 根据URI获取scheme信息;通过scheme判断是否使用缓存;如果不用缓存,则直接创建FileSystem;否则从缓存中获取; FileSystem创建过程 首次使用时,通过ServiceLoader方法将FileSystem所有实现类加载到内存,并缓存所有的class对象;每次通过scheme获取文件系统对应的class对象,实例化和初始化; private static FileSystem createFileSystem(URI uri, Configuration conf ) throws IOException { Class<?> clazz = getFileSystemClass(uri.getScheme(), conf); FileSystem fs = (FileSystem)ReflectionUtils.newInstance(clazz, conf); fs.initialize(uri, conf); return fs; } 从缓存获取FileSystem过程 根据url和conf创建key;如果缓存中存在key,则直接返回FileSystem;否则,创建FileSystem,加入缓存并返回; FileSystem get(URI uri, Configuration conf) throws IOException{ Key key = new Key(uri, conf); return getInternal(uri, conf, key); } ServiceLoader加载的 FileSystem实现类
get()注意事项
使用get()方法获取FileSystem实例时,每个请求都会生成一个key,如果参数中没有传入用户名和密码,则每次使用同一个UserGroupInformation实例,key的hashcode相同,返回同一个FileSystem实例;反之,如果传入用户相关的参数,导致每个请求都会创建新的UserGroupInformation实例,从而key的hashcode不同,进而创建新的FileSystem实例,缓存并返回;(蛋疼的逻辑)
实验说明
传入user信息时,相同配置的两次请求,产生不同的FileSystem实例,如下图:
没有传入user信息时,相同配置的两次请求,返回相同的FileSystem实例,如下图:
参考:
https://stackoverflow.com/questions/20057881/hadoop-filesystem-closed-exception-when-doing-bufferedreader-close