上节讲到的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<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();
}
}

  

Java实现Http服务器(二)的更多相关文章

  1. Java获取Web服务器文件

    Java获取Web服务器文件 如果获取的是服务器上某个目录下的有关文件,就相对比较容易,可以设定死绝对目录,但是如果不能设定死绝对目录,也不确定web服务器的安装目录,可以考虑如下两种方式: 方法一: ...

  2. 一个java页游服务器框架

    一.前言 此游戏服务器架构是一个单服的形式,也就是说所有游戏逻辑在一个工程里,没有区分登陆服务器.战斗服务器.世界服务器等.此架构已成功应用在了多款页游服务器 .在此框架中没有实现相关业务逻辑,只有简 ...

  3. Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解

    Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解 (本文转自: http://blog.csdn.net/yinhaide/article/details/44756 ...

  4. JAVA编写WEB服务器

    一.超文本传输协议  1.1 HTTP请求  1.2 HTTP应答  二.Socket类  三.ServerSocket类  四.Web服务器实例  4.1 HttpServer类  4.2 Requ ...

  5. Java Web高性能开发(二)

    今日要闻: 性价比是个骗局: 对某个产品学上三五天个把月,然后就要花最少的钱买最多最好的东西占最大的便宜. 感谢万能的互联网,他顺利得手,顺便享受了智商上的无上满足以及居高临下的优越感--你们一千块买 ...

  6. 实战WEB 服务器(JAVA编写WEB服务器)

    实战WEB 服务器(JAVA编写WEB服务器) 标签: web服务服务器javawebsockethttp服务器 2010-04-21 17:09 11631人阅读 评论(24) 收藏 举报  分类: ...

  7. Java进阶(三十二) HttpClient使用详解

    Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...

  8. 分享:Java 开发精美艺术二维码

    博客地址:https://ainyi.com/58 Java 开发精美艺术二维码 看到网络上各种各样的二维码层出不穷,好像很炫酷的样子,一时兴起,我也要制作这种炫酷二维码效果 例如: 根据以往例子 根 ...

  9. 一个JAVA的WEB服务器事例

    其实编写一个入门级别的JAVA的WEB服务器,很简单,用SOCKET类即可实现.相关内容可以参考:http://www.cnblogs.com/liqiu/p/3253022.html 一.首先创建一 ...

随机推荐

  1. JavaEE自定义标签:标签类的创建、tld配置文件的创建(位置、如何创建)、Web-XML配置、JSP应用

    1.标签 以类似于html标签的方式实现的java代码的封装. 第一:形成了开发标签的技术标准---自定义标签的技术标准. 第二:java标准标签库(sun之前自己开发的一系列的标签的集合)jstl, ...

  2. Win7 下安装RabbitMQ

    RabbitMQ依赖erlang,所以先安装erlang,然后再安装RabbitMQ; 下载RabbitMQ,下载地址: rabbitmq-server-3.5.6.exe和erlang,下载地址:o ...

  3. sql server和my sql 命令(语句)的差别,sql server与mysql的比較

    sql与mysql的比較 1.连接字符串 sql  :Initial Catalog(database)=x;  --数据库名称       Data Source(source)=x;        ...

  4. Jafka来源分析——文章

    Kafka它是一个分布式消息中间件,我们可以大致分为三个部分:Producer.Broker和Consumer.当中,Producer负责产生消息并负责将消息发送给Kafka:Broker能够简单的理 ...

  5. android 60 发送短信

    import android.os.Bundle; import android.app.Activity; import android.telephony.SmsManager; import a ...

  6. careercup-数组和字符串1.6

    1.6 给定一幅由N*N矩阵表示的如下,其中每个像素的大小为4个字节,编写一个方法,将图像旋转90度.不占用额外内存空间能否做到? 类似leetcode:Rotate Image 思路: 我们这里以逆 ...

  7. [转]cookie、session、sessionid 与jsessionid

    cookie.session.sessionid 与jsessionid,要想明白他们之间的关系,下面来看个有趣的场景来帮你理解. 我们都知道银行,银行的收柜台每天要接待客户存款/取款业务,可以有几种 ...

  8. Android UI 开发

    今天主要学习了Android UI开发的几个知识 6大布局 样式和主题→自定义样式.主题 JUnit单元测试 Toast弹窗功能简介 6大布局 RelativeLayout LinearLayout ...

  9. Java线性表的排序

    Java线性表的排序 ——@梁WP 前言:刚才在弄JDBC的时候,忽然觉得order-by用太多了没新鲜感,我的第六感告诉我java有对线性表排序的封装,然后在eclipse里随便按了一下“.” ,哈 ...

  10. apache安全之修改或隐藏版本信息

    修改apache版本信息    在安装之前,编辑原文件httpd-2.2.31/include/ap_release.h文件如下:     40 #define AP_SERVER_BASEVENDO ...