博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java实现Http服务器(二)
阅读量:7239 次
发布时间:2019-06-29

本文共 17874 字,大约阅读时间需要 59 分钟。

上节讲到的JDK自带的HttpServer组件,实现方法大概有三十个类构成,下面尝试着理解下实现思路。

由于Java的source代码中有很多注释,粘贴上来看着费劲,自己写个程序消除注释。

import java.io.BufferedReader;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;/** * @author 作者 E-mail: * @version 创建时间:2015-10-30 下午02:38:17 类说明 处理从JDK当中的注释 */public class Test{    public static void main(String[] args) throws IOException    {        FileInputStream inputStream = new FileInputStream("source");        FileOutputStream outputStream = new FileOutputStream("res");        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));        final StringBuilder builder = new StringBuilder();        String tempstr = null;        while ((tempstr = br.readLine()) != null)        {            if (tempstr.indexOf('*') == -1)            {                builder.append(tempstr + '\n');            }        }        outputStream.write(builder.toString().getBytes("gbk"));    }}

 com.sun.net.httpserver包下的类和接口提供了一系列的标准

 sun.net.httpserver包下类根据标准做了一系列的实现

 

 

com.sun.net.httpserver.HttpServer.java

package com.sun.net.httpserver;import com.sun.net.httpserver.spi.HttpServerProvider;public abstract class HttpServer {    protected HttpServer () {    }	    //默认创建HttpServer对象    public static HttpServer create () throws IOException {        return create (null, 0);    }    //根据InetSocketAddress对象和backlog对象创建HttpServer对象    public static HttpServer create (InetSocketAddress addr, int backlog) throws IOException     {   	    //HttpServer实例的服务提供者HttpServerProvider        HttpServerProvider provider = HttpServerProvider.provider();        //由服务提供者创建HttpServer对象		return provider.createHttpServer (addr, backlog);    }    	//绑定网络地址接口    public abstract void bind (InetSocketAddress addr, int backlog) throws IOException;    	//启动httpServer接口    public abstract void start () ;	//设置线程池    public abstract void setExecutor (Executor executor);    public abstract Executor getExecutor () ;    public abstract void stop (int delay);    	//指定url和相应的处理Handler    public abstract HttpContext createContext (String path, HttpHandler handler) ;        public abstract HttpContext createContext (String path) ;    public abstract void removeContext (String path) throws IllegalArgumentException ;    public abstract void removeContext (HttpContext context) ;    public abstract InetSocketAddress getAddress() ;}

  

 com.sun.net.httpserver.spi.HttpServerProvider

 
package com.sun.net.httpserver.spi;import java.io.FileDescriptor;import java.io.IOException;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.Iterator;import sun.misc.Service;import sun.misc.ServiceConfigurationError;import sun.security.action.GetPropertyAction;public abstract class HttpServerProvider {    public abstract HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException;    public abstract HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException;    private static final Object lock = new Object();    private static HttpServerProvider provider = null;    protected HttpServerProvider() {        SecurityManager sm = System.getSecurityManager();        if (sm != null)            sm.checkPermission(new RuntimePermission("httpServerProvider"));    }    private static boolean loadProviderFromProperty() {        String cn = System.getProperty("com.sun.net.httpserver.HttpServerProvider");        if (cn == null)            return false;        try {            Class c = Class.forName(cn, true,                                    ClassLoader.getSystemClassLoader());            provider = (HttpServerProvider)c.newInstance();            return true;        } catch (ClassNotFoundException x) {            throw new ServiceConfigurationError(x);        } catch (IllegalAccessException x) {            throw new ServiceConfigurationError(x);        } catch (InstantiationException x) {            throw new ServiceConfigurationError(x);        } catch (SecurityException x) {            throw new ServiceConfigurationError(x);        }    }    private static boolean loadProviderAsService() {        Iterator i = Service.providers(HttpServerProvider.class,                                       ClassLoader.getSystemClassLoader());        for (;;) {            try {                if (!i.hasNext())                    return false;                provider = (HttpServerProvider)i.next();                return true;            } catch (ServiceConfigurationError sce) {                if (sce.getCause() instanceof SecurityException) {                    // Ignore the security exception, try the next provider                    continue;                }                throw sce;            }        }    }    public static HttpServerProvider provider () {        synchronized (lock) {            if (provider != null)                return provider;            return (HttpServerProvider)AccessController                .doPrivileged(new PrivilegedAction() {                        public Object run() {                            if (loadProviderFromProperty())                                return provider;                            if (loadProviderAsService())                                return provider;                            provider = new sun.net.httpserver.DefaultHttpServerProvider();                            return provider;                        }                    });        }    }}

 

 

 

-----------------------分割线---------------------

上面说到com.sun.net.httpServer包下类和接口都是提供了一套标准,应用程序使用API的时候只关心这套标准,具体标准的实现应用程序是不关心的,实现了应用程序开发者和服务提供者的解耦,服务提供者可以提供多种多样的实现。

对于同一个功能,不同的厂家会提供不同的产品,比如不同品牌的轮胎、插头等。在软件行业,情况也是如此。比如,对于数据的加密解密,不同的厂家使用不同的算法,提供强度各异的不同软件包。应用软件根据不同的开发需求,往往需要使用不同的软件包。每次更换不同的软件包,都会重复以下过程:更改应用软件代码 -> 重新编译 -> 测试 -> 部署。这种做法一般被称为开发时绑定。这其实是一种比较原始的做法,缺乏灵活性和开放性。于是应用运行时绑定服务提供者的做法流行开来。具体做法是,使用配置文件指定,然后在运行时载入具体实现。 SE 平台提供的 Service Provider 机制是折衷了开发时绑定和运行时绑定两种方式,很好的满足了高效和开放两个要求。

  构成一个 Service Provider 框架需要大致三个部分,图 1 给出了一个典型的 Service Provider 组件结构。 SE 平台的大部分 Service Provider 框架都提供了 3 个主要个组件:面向开发者的 Application 接口,面向服务提供商的 Service Provider 接口和真正的服务提供者。

 

---------------------------分割线------------------------

重点关注Application接口的两个方法

com.sun.net.httpServer.HttpServer.java

方法作用: 

创建一个HttpServer实例,该实例绑定于一个确定的网络地址(由IP地址和端口号组成)

指定一个最大的监听backlog的长度,这个长度是指允许在这个监听Socket上排队等待连接的最大数量。

该HttpServer实例来自于当前的HttpServerProvider

/**     * Create a HttpServer instance which will bind to the     * specified {@link java.net.InetSocketAddress} (IP address and port number)     *     * A maximum backlog can also be specified. This is the maximum number of     * queued incoming connections to allow on the listening socket.     * Queued TCP connections exceeding this limit may be rejected by the TCP implementation.     * The HttpServer is acquired from the currently installed {@link HttpServerProvider}     *     * @param addr the address to listen on, if null then bind() must be called     *  to set the address     * @param backlog the socket backlog. If this value is less than or equal to zero,     *          then a system default value is used.     * @throws BindException if the server cannot bind to the requested address,     *          or if the server is already bound.     * @throws IOException     */    public static HttpServer create (        InetSocketAddress addr, int backlog    ) throws IOException {        HttpServerProvider provider = HttpServerProvider.provider();        return provider.createHttpServer (addr, backlog);    }

这个模式和JAXP获取XML解析对象的过程很像

 

com.sun.net.httpServer.HttpServerProvider.java  

方法作用:

     针对JVM的请求返回系统的HttpServerProvider,查找过程

1:如果系统属性(system property) com.sun.net.httpserver.HttpServerProvider被定义过,找到相应的类

private static boolean loadProviderFromProperty() {        String cn = System.getProperty("com.sun.net.httpserver.HttpServerProvider");        if (cn == null)            return false;        try {            Class c = Class.forName(cn, true,                                    ClassLoader.getSystemClassLoader());            provider = (HttpServerProvider)c.newInstance();            return true;        } catch (ClassNotFoundException x) {            throw new ServiceConfigurationError(x);        } catch (IllegalAccessException x) {            throw new ServiceConfigurationError(x);        } catch (InstantiationException x) {            throw new ServiceConfigurationError(x);        } catch (SecurityException x) {            throw new ServiceConfigurationError(x);        }    }

  

    2:第三方jar包的属性文件当中是否有相应设置

查找所有加载的jar包中META-INF/services目录下的配置文件,文件名为

private static boolean loadProviderAsService() {        Iterator i = Service.providers(HttpServerProvider.class,ClassLoader.getSystemClassLoader());        for (;;) {            try {                if (!i.hasNext())                    return false;                provider = (HttpServerProvider)i.next();                return true;            } catch (ServiceConfigurationError sce) {                if (sce.getCause() instanceof SecurityException) {                    // Ignore the security exception, try the next provider                    continue;                }                throw sce;            }        }    }

sun.misc.Service.java

/**     * Locates and incrementally instantiates the available providers of a     * given service using the given class loader.     *     * 

This method transforms the name of the given service class into a * provider-configuration filename as described above and then uses the * getResources method of the given class loader to find all * available files with that name. These files are then read and parsed to * produce a list of provider-class names. The iterator that is returned * uses the given class loader to lookup and then instantiate each element * of the list. * *

Because it is possible for extensions to be installed into a running * Java virtual machine, this method may return different results each time * it is invoked.

* * @param service * The service's abstract service class * * @param loader * The class loader to be used to load provider-configuration files * and instantiate provider classes, or null if the system * class loader (or, failing that the bootstrap class loader) is to * be used * * @return An Iterator that yields provider objects for the given * service, in some arbitrary order. The iterator will throw a * ServiceConfigurationError if a provider-configuration * file violates the specified format or if a provider class cannot * be found and instantiated. * * @throws ServiceConfigurationError * If a provider-configuration file violates the specified format * or names a provider class that cannot be found and instantiated * * @see #providers(java.lang.Class) * @see #installedProviders(java.lang.Class) */ public static Iterator providers(Class service, ClassLoader loader) throws ServiceConfigurationError { return new LazyIterator(service, loader); }

Service.java下面的内部类

/**     * Private inner class implementing fully-lazy provider lookup     */    private static class LazyIterator implements Iterator {        Class service;        ClassLoader loader;        Enumeration configs = null;        Iterator pending = null;        Set returned = new TreeSet();        String nextName = null;        private LazyIterator(Class service, ClassLoader loader) {            this.service = service;            this.loader = loader;        }        public boolean hasNext() throws ServiceConfigurationError {            if (nextName != null) {                return true;            }            if (configs == null) {                try {                    String fullName = prefix + service.getName();                    if (loader == null)                        configs = ClassLoader.getSystemResources(fullName);                    else                        configs = loader.getResources(fullName);                } catch (IOException x) {                    fail(service, ": " + x);                }            }            while ((pending == null) || !pending.hasNext()) {                if (!configs.hasMoreElements()) {                    return false;                }                pending = parse(service, (URL)configs.nextElement(), returned);            }            nextName = (String)pending.next();            return true;        }        public Object next() throws ServiceConfigurationError {            if (!hasNext()) {                throw new NoSuchElementException();            }            String cn = nextName;            nextName = null;            try {                return Class.forName(cn, true, loader).newInstance();            } catch (ClassNotFoundException x) {                fail(service,                     "Provider " + cn + " not found");            } catch (Exception x) {                fail(service,                     "Provider " + cn + " could not be instantiated: " + x,                     x);            }            return null;        /* This cannot happen */        }        public void remove() {            throw new UnsupportedOperationException();        }    }

  

 

 

/**     * Returns the system wide default HttpServerProvider for this invocation of     * the Java virtual machine.     *     * 

The first invocation of this method locates the default provider * object as follows:

* *
    * *
  1. If the system property * com.sun.net.httpserver.HttpServerProvider is defined then it is * taken to be the fully-qualified name of a concrete provider class. * The class is loaded and instantiated; if this process fails then an * unspecified unchecked error or exception is thrown.

  2. * *
  3. If a provider class has been installed in a jar file that is * visible to the system class loader, and that jar file contains a * provider-configuration file named * com.sun.net.httpserver.HttpServerProvider in the resource * directory META-INF/services, then the first class name * specified in that file is taken. The class is loaded and * instantiated; if this process fails then an unspecified unchecked error or exception is * thrown.

  4. * *
  5. Finally, if no provider has been specified by any of the above * means then the system-default provider class is instantiated and the * result is returned.

  6. * *
* *

Subsequent invocations of this method return the provider that was * returned by the first invocation.

* * @return The system-wide default HttpServerProvider */ public static HttpServerProvider provider () { synchronized (lock) { if (provider != null) return provider; return (HttpServerProvider)AccessController .doPrivileged(new PrivilegedAction() { public Object run() { if (loadProviderFromProperty()) return provider; if (loadProviderAsService()) return provider; provider = new sun.net.httpserver.DefaultHttpServerProvider(); return provider; } }); } }

  

 最终如果前两种方法都没有找到相应的HttpServerProvider实例,则使用sun公司为我们提供的HttpServerProvider实例

sun.net.httpserver.DefaultHttpServerProvider类

也就是我们通常使用的类。

 

sun.net.httpserver.DefaultHttpServerProvider类

package sun.net.httpserver;import java.net.*;import java.io.*;import com.sun.net.httpserver.*;import com.sun.net.httpserver.spi.*;public class DefaultHttpServerProvider extends HttpServerProvider {    public HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException {        return new HttpServerImpl (addr, backlog);    }    public HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException {        return new HttpsServerImpl (addr, backlog);    }}

 sun.net.httpserver.HttpServerImpl类 (其实还有HTTPS的实现类,这里先不讲)

package sun.net.httpserver;import java.net.*;import java.io.*;import java.nio.*;import java.security.*;import java.nio.channels.*;import java.util.*;import java.util.concurrent.*;import javax.net.ssl.*;import com.sun.net.httpserver.*;import com.sun.net.httpserver.spi.*;public class HttpServerImpl extends HttpServer {    ServerImpl server;    HttpServerImpl () throws IOException {        this (new InetSocketAddress(80), 0);    }    HttpServerImpl (        InetSocketAddress addr, int backlog    ) throws IOException {        server = new ServerImpl (this, "http", addr, backlog);    }    public void bind (InetSocketAddress addr, int backlog) throws IOException {        server.bind (addr, backlog);    }    public void start () {        server.start();    }    public void setExecutor (Executor executor) {        server.setExecutor(executor);    }    public Executor getExecutor () {        return server.getExecutor();    }    public void stop (int delay) {        server.stop (delay);    }    public HttpContextImpl createContext (String path, HttpHandler handler) {        return server.createContext (path, handler);    }    public HttpContextImpl createContext (String path) {        return server.createContext (path);    }    public void removeContext (String path) throws IllegalArgumentException {        server.removeContext (path);    }    public void removeContext (HttpContext context) throws IllegalArgumentException {        server.removeContext (context);    }    public InetSocketAddress getAddress() {        return server.getAddress();    }}

  

 

转载于:https://www.cnblogs.com/wuxinliulei/p/4923969.html

你可能感兴趣的文章
react-native-storage + AsyncStorage 实现数据存储
查看>>
Cobaltstrike、armitage联动
查看>>
pandas set_index和reset_index的用法
查看>>
[Bash] View Files and Folders in Bash
查看>>
PEACHPIE 0.9.11 版本发布,可以上生产了
查看>>
异常检测——局部异常因子(Local Outlier Factor ,LOF)算法
查看>>
记录一次广州白云区项目数据库连接失败问题的解决过程
查看>>
干货:Vue粒子特效(vue-particles插件)
查看>>
Silverlight自定义数据绑定控件应该如何处理IEditableObject和IEditableCollectionView对象...
查看>>
加密PDF为只读模式
查看>>
让你编写的控件库在 XAML 中有一个统一的漂亮的命名空间(xmlns)和命名空间前缀...
查看>>
MySQL数据库的锁详解【转】
查看>>
ip route 解释
查看>>
【转】Android中保持Service的存活
查看>>
Consul功能简介
查看>>
IdentityServer4实战 - API与IdentityServer的交互过程解析
查看>>
Delphi编程 -- 使用CPUID指令获取CPU信息(转自大富翁)
查看>>
Android setRequestedOrientation用法
查看>>
面向对象三大基本特性,五大基本原则
查看>>
更改窗口图标并将其显示在任务栏
查看>>