URI 源码分析
需要提前了解下什么是URI,及URI和URL的區別:
[URI、 URL 和 URN 的區別](http://www.jianshu.com/p/09ac6fc0f8cb)
URI 引用包括最多三個部分:模式、模式特定部分和片段標識符。一般為:
模式:模式特定部分:片段
如果省略模式,這個URI引用則是相對的。如果省略片段標識符,這個URI引用就是一個純URI。
URI是對URL的抽象,不僅包括統一資源定位符URL,還包括統一資源名URN。實際上使用的URI大多都是URL。在java中,URI使用java.net.URI類表示,URI類只能標識資源,和解析URI,而不能獲取URI所標識的資源(URN是無法定位到資源的)。
構造
public URI(String str) throws URISyntaxException {new Parser(str).parse(false); }public URI(String scheme, String host, String path, String fragment)throws URISyntaxException{this(scheme, null, host, -1, path, null, fragment); }public URI(String scheme,String authority,String path, String query, String fragment)throws URISyntaxException{ .... }public URI(String scheme,String userInfo, String host, int port,String path, String query, String fragment)throws URISyntaxException{ ... }public URI(String scheme, String ssp, String fragment) throws URISyntaxException {new Parser(toString(scheme, ssp, null, null, null, -1, null, null, fragment)).parse(false); }URI類提供了5中構造方法
1. 根據提供的一個uri字符串構造一個URI對象。
2. 主要針對層次的URI。通過 模式、服務器地址、文件路徑、片段標識構造URI。
3. 主要針對層次的URI。通過 模式、授權機構、文件路徑、查詢條件、片段標識構造URI。
4. 主要針對層次的URI。通過 模式、用戶信息、服務器地址、端口、文件路徑、查詢條件、片段標識構造URI。
5. 主要針對非層次URI。通過 模式、模式特定部分和片段標識創建URI。
create方法
public static URI create(String str) {try {return new URI(str);} catch (URISyntaxException x) {throw new IllegalArgumentException(x.getMessage(), x);} }如果可以確認URI的格式正確,可使用create的工廠方法創建URI。因為該方法不會拋出URISyntaxException異常。
是否透明URL
URI通常情況下都是層次(帶“/”)的,但是也有不透明(沒有“/”)的,層次的URI包含模式,主機,站點等各個部分,當然可能某些部分不包含,但是不透明的URI只包含三個部分,Scheme,Scheme-specific-part,Fragment.
如:mailto:jijianshuai@infcn.com.cn
判斷path是否為空,如果為空則是不透明的,說明URI中沒有“/”。
在URI構造器中解析URI,代碼:new Parser(str).parse(false);
判斷URI中是否存在“/”符號,如果存在就是有層次結構的URI。
如果存在“/”,則調用parseAuthority方法進行解析path。
URI獲取各部分信息
public String getScheme();
public String getSchemeSpecificPart();
public String getRawSchemeSpecificPart();
public String getFragment();
public String getRawFragment();
public String getAuthority();
public String getRawAuthority()
授權機構包括:用戶信息、服務器地址(域名或ip)、端口
user:password@localhost:80
public String getFragment()
public String getRawFragment()
public String getHost()
public String getPath()
public String getRawPath()
路徑包括(目錄結構和文件部分)。如:/dir/index.html
public int getPort()
如果沒有端口則返回-1;
public String getQuery()
public String getRawQuery()
public String getUserInfo()
public String getRawUserInfo()
如果URI是非透明只能獲取到1~3個信息。
如果URI是層次結構則能獲取所有信息。
方法中帶Raw的,是獲取編碼后的URI部分信息。非ascii的字符需要進行編碼,不帶Raw的方法是解碼后的信息。
getScheme、getHost、getPort這三個方法沒有Raw方法,是因為這三部分不會出現非ascii的字符。
resolve 方法
resolve方法可以將相對URI轉換成絕對URI。示例如下:
URI a = URI.create("http://localhost:8080/index.html"); URI b = URI.create("user/userInfo.html"); URI c = a.resolve(b); System.out.println(c);根據a獲取b的絕對路徑
打印結果為:http://localhost:8080/user/userInfo.html
源碼如下
public URI resolve(URI uri) {return resolve(this, uri); }private static URI resolve(URI base, URI child) {// check if child if opaque first so that NPE is thrown// if child is null.if (child.isOpaque() || base.isOpaque())return child;// 5.2 (2): Reference to current document (lone fragment)if ((child.scheme == null) && (child.authority == null)&& child.path.equals("") && (child.fragment != null)&& (child.query == null)) {if ((base.fragment != null) && child.fragment.equals(base.fragment)) {return base;}URI ru = new URI();ru.scheme = base.scheme;ru.authority = base.authority;ru.userInfo = base.userInfo;ru.host = base.host;ru.port = base.port;ru.path = base.path;ru.fragment = child.fragment;ru.query = base.query;return ru;}// 5.2 (3): Child is absoluteif (child.scheme != null)return child;URI ru = new URI(); // Resolved URIru.scheme = base.scheme;ru.query = child.query;ru.fragment = child.fragment;// 5.2 (4): Authorityif (child.authority == null) {ru.authority = base.authority;ru.host = base.host;ru.userInfo = base.userInfo;ru.port = base.port;String cp = (child.path == null) ? "" : child.path;if ((cp.length() > 0) && (cp.charAt(0) == '/')) {// 5.2 (5): Child path is absoluteru.path = child.path;} else {// 5.2 (6): Resolve relative pathru.path = resolvePath(base.path, cp, base.isAbsolute());}} else {ru.authority = child.authority;ru.host = child.host;ru.userInfo = child.userInfo;ru.host = child.host;ru.port = child.port;ru.path = child.path;}// 5.2 (7): Recombine (nothing to do here)return ru; }2.1 如果child的fragment和base的片段標識一樣,就直接返回base的url
2.2 把base不包含fragment的部分和child的fragment構造一個新的URI返回。
relativize 方法
relativize 方法可以將絕對路徑的URI轉換成相對路徑的URI。
URI a = URI.create("http://localhost:8080/"); URI b = URI.create("http://localhost:8080/index.html"); URI c = a.relativize(b); System.out.println(c);獲取b相對a的相對路徑。
打印的結果為:index.html
private static URI relativize(URI base, URI child) {// check if child if opaque first so that NPE is thrown// if child is null.if (child.isOpaque() || base.isOpaque())return child;if (!equalIgnoringCase(base.scheme, child.scheme)|| !equal(base.authority, child.authority))return child;String bp = normalize(base.path);String cp = normalize(child.path);if (!bp.equals(cp)) {if (!bp.endsWith("/"))bp = bp + "/";if (!cp.startsWith(bp))return child;}URI v = new URI();v.path = cp.substring(bp.length());v.query = child.query;v.fragment = child.fragment;return v; }本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
點擊這里快速進入簡書
GIT地址:http://git.oschina.net/brucekankan/
點擊這里快速進入GIT
總結
- 上一篇: 多文件同时读写为什么没有单文件读写快?
- 下一篇: URL 源码分析