URL 源码分析

URL表示统一资源定位器,指向世界上“资源”的指针万维网。资源可以是简单的文件或目录,或者它可以是对更复杂对象的引用,例如对数据库或搜索引擎的查询。这个类的作用就是URL的定位的作用,定位了每个资源符号引用的位置。整个URL大体上就是对URL内容进行规范,对URL进行解析。

构造方法是通过文件里面的端口和文件的访问主机对这个URL进行构造。

public URL(String protocol, String host, int port, String file)
    throws MalformedURLException
{
    this(protocol, host, port, file, null);
}

URL的构造方法,这个构造方法里面传输了URL里面的协议,主机名,端口号和文件名,最后通过流协议处理器来进行URL的解析。

    public URL(String protocol, String host, int port, String file,
               URLStreamHandler handler) throws MalformedURLException {
        if (handler != null) {
        	//安全管理器检查
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkSpecifyHandler(sm);
            }
        }
        
        protocol = protocol.toLowerCase();
        this.protocol = protocol;
        //判断主机名是否为空
        if (host != null) {
			//根据冒号和中括号来判断主机名是否是ip地址
            if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
                host = "["+host+"]";
            }
            this.host = host;
			//端口号小于-1,抛出异常说明这个端口号是无效端口。
            if (port < -1) {
                throw new MalformedURLException("Invalid port number :" +
                                                    port);
            }
            this.port = port;
            //判断主机名中是否有端口号
            authority = (port == -1) ? host : host + ":" + port;
        }

		//Parts类对文件的信息进行处理。
        Parts parts = new Parts(file);
        path = parts.getPath();
        query = parts.getQuery();

        if (query != null) {
            this.file = path + "?" + query;
        } else {
            this.file = path;
        }
        ref = parts.getRef();

//注意:我们这里没有对URL进行完全验证。因为太冒险会变化。现在,但仅供将来参考。-比尔
        if (handler == null &&
            (handler = getURLStreamHandler(protocol)) == null) {
            throw new MalformedURLException("unknown protocol: " + protocol);
        }
        this.handler = handler;
        //调用URL流处理器来进行URL的解析。
        if (host != null && isBuiltinStreamHandler(handler)) {
        	//IP地址工具类,检查存在的表单。
            String s = IPAddressUtil.checkExternalForm(this);
            if (s != null) {
                throw new MalformedURLException(s);
            }
        }
        //判断是否是jar的连接协议
        if ("jar".equalsIgnoreCase(protocol)) {
            if (handler instanceof sun.net.www.protocol.jar.Handler) {
                String s = ((sun.net.www.protocol.jar.Handler) handler).checkNestedProtocol(file);
                if (s != null) {
                    throw new MalformedURLException(s);
                }
            }
        }
    }

URL反序列化状态值

   public UrlDeserializedState(String protocol,
                                String host, int port,
                                String authority, String file,
                                String ref, int hashCode) {
        this.protocol = protocol;
        this.host = host;
        this.port = port;
        this.authority = authority;
        this.file = file;
        this.ref = ref;
        this.hashCode = hashCode;
    }

文件信息分离,分离“#”符号以后的引用内容,分离"?"以后的参数。见文末“#”引用在URL地址中的作用。

class Parts {
    String path, query, ref;

    Parts(String file) {
    	//分割URL中“#”引用符号
        int ind = file.indexOf('#');
        ref = ind < 0 ? null: file.substring(ind + 1);
        file = ind < 0 ? file: file.substring(0, ind);
        int q = file.lastIndexOf('?');
        if (q != -1) {
            query = file.substring(q+1);
            path = file.substring(0, q);
        } else {
            path = file;
        }
    }

    String getPath() {
        return path;
    }

    String getQuery() {
        return query;
    }

    String getRef() {
        return ref;
    }
}

URL读取内容处理方法。设置URLStreamHandler 目的是为了进行开启连接和进行URL的字符串的解析。

   private Object readResolve() throws ObjectStreamException {

        URLStreamHandler handler = null;
		//已签入readObject
        handler = getURLStreamHandler(tempState.getProtocol());

        URL replacementURL = null;
        //判断流处理器是否是从sun.net.www.protocol调用
        if (isBuiltinStreamHandler(handler.getClass().getName())) {
        	//配置新的URL
            replacementURL = fabricateNewURL();
        } else {
        	//设置反序列化的参数
            replacementURL = setDeserializedFields(handler);
        }
        return replacementURL;
    }

	//设置URL反序列化参数。
    private URL setDeserializedFields(URLStreamHandler handler) {
        URL replacementURL;
        String userInfo = null;
        String protocol = tempState.getProtocol();
        String host = tempState.getHost();
        int port = tempState.getPort();
        String authority = tempState.getAuthority();
        String file = tempState.getFile();
        String ref = tempState.getRef();
        int hashCode = tempState.getHashCode();

//构建权限部分
        if (authority == null
            && ((host != null && host.length() > 0) || port != -1)) {
            if (host == null)
                host = "";
            authority = (port == -1) ? host : host + ":" + port;

//处理包含用户信息的主机
            int at = host.lastIndexOf('@');
            if (at != -1) {
                userInfo = host.substring(0, at);
                host = host.substring(at+1);
            }
        } else if (authority != null) {
//构建用户信息部分
            int ind = authority.indexOf('@');
            if (ind != -1)
                userInfo = authority.substring(0, ind);
        }

//构造路径和查询部分
        String path = null;
        String query = null;
        if (file != null) {
//修正:只有在等级制度下才能这样做?
            int q = file.lastIndexOf('?');
            if (q != -1) {
                query = file.substring(q+1);
                path = file.substring(0, q);
            } else
                path = file;
        }

//设置对象字段。
        this.protocol = protocol;
        this.host = host;
        this.port = port;
        this.file = file;
        this.authority = authority;
        this.ref = ref;
        this.hashCode = hashCode;
        this.handler = handler;
        this.query = query;
        this.path = path;
        this.userInfo = userInfo;
        replacementURL = this;
        return replacementURL;
    }
static final String BUILTIN_HANDLERS_PREFIX = "sun.net.www.protocol";

boolean isBuiltinStreamHandler(URLStreamHandler handler) {
   Class<?> handlerClass = handler.getClass();
   return isBuiltinStreamHandler(handlerClass.getName())
             || (handlerClass.getClassLoader() == null);
}

private boolean isBuiltinStreamHandler(String handlerClassName) {
    return (handlerClassName.startsWith(BUILTIN_HANDLERS_PREFIX));
}
	//临时参数存放
    private transient UrlDeserializedState tempState;

    private URL fabricateNewURL()
                throws InvalidObjectException {
//从反序列化对象创建URL字符串
        URL replacementURL = null;
        //获取URL字符串
        String urlString = tempState.reconstituteUrlString();

        try {
            replacementURL = new URL(urlString);
        } catch (MalformedURLException mEx) {
            resetState();
            InvalidObjectException invoEx = new InvalidObjectException(
                    "Malformed URL: " + urlString);
            invoEx.initCause(mEx);
            throw invoEx;
        }
        replacementURL.setSerializedHashCode(tempState.getHashCode());
        resetState();
        return replacementURL;
    }
final class UrlDeserializedState {
    private final String protocol;
    private final String host;
    private final int port;
    private final String authority;
    private final String file;
    private final String ref;
    private final int hashCode;

    public UrlDeserializedState(String protocol,
                                String host, int port,
                                String authority, String file,
                                String ref, int hashCode) {
        this.protocol = protocol;
        this.host = host;
        this.port = port;
        this.authority = authority;
        this.file = file;
        this.ref = ref;
        this.hashCode = hashCode;
    }

//预计算StringBuilder的长度
        int len = protocol.length() + 1;
        if (authority != null && authority.length() > 0)
            len += 2 + authority.length();
        if (file != null) {
            len += file.length();
        }
        if (ref != null)
            len += 1 + ref.length();
        StringBuilder result = new StringBuilder(len);
        result.append(protocol);
        result.append(":");
        if (authority != null && authority.length() > 0) {
            result.append("//");
            result.append(authority);
        }
        if (file != null) {
            result.append(file);
        }
        if (ref != null) {
            result.append("#");
            result.append(ref);
        }
        return result.toString();
    }
}

附:URL类的使用方法
https://www.cnblogs.com/blackiesong/p/6182038.html

URL中#的作用
https://www.cnblogs.com/kaituorensheng/p/3776527.html

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值