zoukankan      html  css  js  c++  java
  • Java实现Http服务器(二)

    上节讲到的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 + '
    ');
                }
            }
    
            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<Object>() {
                            public Object run() {
                                if (loadProviderFromProperty())
                                    return provider;
                                if (loadProviderAsService())
                                    return provider;
                                provider = new sun.net.httpserver.DefaultHttpServerProvider();
                                return provider;
                            }
                        });
            }
        }
    
    }
    

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

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

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

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

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

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

    com.sun.net.httpServer.HttpServer.java

    方法作用: 

    创建一个HttpServer实例,该实例绑定于一个确定的网络地址(由IP地址和端口号组成)
    指定一个最大的监听backlog的长度,这个长度是指允许在这个监听Socket上排队等待连接的最大数量。

    该HttpServer实例来自于当前的HttpServerProvider

    /**
         * Create a <code>HttpServer</code> 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 <code>null</code> 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.
         *
         * <p> This method transforms the name of the given service class into a
         * provider-configuration filename as described above and then uses the
         * <tt>getResources</tt> 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.
         *
         * <p> 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. <p>
         *
         * @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 <tt>null</tt> if the system
         *         class loader (or, failing that the bootstrap class loader) is to
         *         be used
         *
         * @return An <tt>Iterator</tt> that yields provider objects for the given
         *         service, in some arbitrary order.  The iterator will throw a
         *         <tt>ServiceConfigurationError</tt> 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.
         *
         * <p> The first invocation of this method locates the default provider
         * object as follows: </p>
         *
         * <ol>
         *
         *   <li><p> If the system property
         *   <tt>com.sun.net.httpserver.HttpServerProvider</tt> 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.  </p></li>
         *
         *   <li><p> 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
         *   <tt>com.sun.net.httpserver.HttpServerProvider</tt> in the resource
         *   directory <tt>META-INF/services</tt>, 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.  </p></li>
         *
         *   <li><p> 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.  </p></li>
         *
         * </ol>
         *
         * <p> Subsequent invocations of this method return the provider that was
         * returned by the first invocation.  </p>
         *
         * @return  The system-wide default HttpServerProvider
         */
        public static HttpServerProvider provider () {
            synchronized (lock) {
                if (provider != null)
                    return provider;
                return (HttpServerProvider)AccessController
                    .doPrivileged(new PrivilegedAction<Object>() {
                            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();
        }
    }
    

      

  • 相关阅读:
    HTML: vertical algin Big/small div in same row (bootstrap)
    unix时间转换
    chrome工具分析
    DNF 包管理器
    安装nodejs
    location属性解释
    angular深入理解途径
    ui-router与ngRoute
    angular $location服务获取url
    Python文件操作
  • 原文地址:https://www.cnblogs.com/wuxinliulei/p/4923969.html
Copyright © 2011-2022 走看看