`
IXHONG
  • 浏览: 437621 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

模拟tomcat连接器

阅读更多

Tomcat中的连接器是一个独立的模块,可以被插入到servlet容器中,而且还有很多连接器可以使用。例如Coyote,mod_jk,mod_jk2,mod_webapp等。Tomcat中使用的连接器必须满足以下条件: 

 

1.实现org.apache.catalina.Connector接口

 

2.负责创建实现了org.apache.catalina.Request接口的request对象

 

3.负责创建实现了org.apache.catalina.Response接口的response对象

 

Tomcat的连接器等待引入的HTTP请求,创建request对象和response对象,然后调用org.apache.catalina.Container接口的invoke()方法,将request对象和response对象传给servlet容器。

 

package com.whatsmars.tomcat.connector;

/**
 * Created by shenhongxi on 16/4/11.
 */
public final class Bootstrap {

    public static void main(String[] args) {
        HttpConnector connector = new HttpConnector();
        Container container = new SimpleContainer();
        connector.setContainer(container);
        connector.setBufferSize(2048);
        connector.start();
    }
}

 

package com.whatsmars.tomcat.connector;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by shenhongxi on 16/4/11.
 */
public class HttpConnector implements Runnable {

    private Container container;

    boolean stopped;

    private String scheme = "http";

    private int bufferSize;

    public void run() {
        ServerSocket serverSocket = null;
        int port = 8080;
        try {
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        while (!stopped) {
            // Accept the next incoming connection from the server socket
            Socket socket = null;
            try {
                socket = serverSocket.accept();
            } catch (Exception e) {
                continue;
            }
            // Hand this socket off to an HttpProcessor
            HttpProcessor processor = new HttpProcessor(this);
            processor.process(socket);
        }
    }

    public void start() {
        new Thread(this).start();
    }

    public String getScheme() {
        return scheme;
    }

    public int getBufferSize() {
        return bufferSize;
    }

    public void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }

    public Container getContainer() {
        return container;
    }

    public void setContainer(Container container) {
        this.container = container;
    }
}

 

package com.whatsmars.tomcat.connector;

import org.apache.catalina.util.Enumerator;
import org.apache.catalina.util.ParameterMap;
import org.apache.catalina.util.RequestUtil;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.*;

/**
 * Created by shenhongxi on 16/4/11.
 */
public class HttpRequest implements HttpServletRequest {

    private String requestURI;
    private int contentLength;
    private String contentType;
    private String queryString;
    private String method;
    private String protocol;

    protected Map headers = new HashMap();

    protected SocketInputStream input;

    /**
     * The parsed parameters for this request.  This is populated only if
     * parameter information is requested via one of the
     * <code>getParameter()</code> family of method calls.  The key is the
     * parameter name, while the value is a String array of values for this
     * parameter.
     * <p>
     * <strong>IMPLEMENTATION NOTE</strong> - Once the parameters for a
     * particular request are parsed and stored here, they are not modified.
     * Therefore, application level access to the parameters need not be
     * synchronized.
     */
    protected ParameterMap parameters = null; // extends LinkedHashMap has a boolean var 'locked'

    /**
     * Have the parameters for this request been parsed yet?
     */
    protected boolean parsed = false;

    public HttpRequest(SocketInputStream input) {
        this.input = input;
    }

    public void addHeader(String name, String value) {
        name = name.toLowerCase();
        synchronized (headers) {
            ArrayList values = (ArrayList) headers.get(name);
            if (values == null) {
                values = new ArrayList();
                headers.put(name, values);
            }
            values.add(value);
        }
    }

    public String getParameter(String name) {
        parseParameters();
        String values[] = (String[]) parameters.get(name);
        if (values != null)
            return (values[0]);
        else
            return (null);
    }

    public Map getParameterMap() {
        parseParameters();
        return (this.parameters);
    }

    public Enumeration getParameterNames() {
        parseParameters();
        return (new Enumerator(parameters.keySet()));
    }

    public String[] getParameterValues(String name) {
        parseParameters();
        String values[] = (String[]) parameters.get(name);
        if (values != null)
            return (values);
        else
            return null;
    }

    /**
     * Parse the parameters of this request, if it has not already occurred.
     * If parameters are present in both the query string and the request
     * content, they are merged.
     */
    protected void parseParameters() {
        if (parsed) return;
        ParameterMap results = parameters;
        if (results == null)
            results = new ParameterMap();
        results.setLocked(false);
        String encoding = getCharacterEncoding();
        if (encoding == null)
            encoding = "ISO-8859-1";

        // Parse any parameters specified in the query string
        String queryString = getQueryString();
        try {
            RequestUtil.parseParameters(results, queryString, encoding);
        } catch (Exception e) {
            ;
        }

        // Parse any parameters specified in the input stream
        String contentType = getContentType();
        if (contentType == null)
            contentType = "";
        int semicolon = contentType.indexOf(';');
        if (semicolon >= 0) {
            contentType = contentType.substring(0, semicolon).trim();
        } else {
            contentType = contentType.trim();
        }
        if ("POST".equals(getMethod()) && (getContentLength() > 0)
                && "application/x-www-form-urlencoded".equals(contentType)) {
            try {
                int max = getContentLength();
                int len = 0;
                byte buf[] = new byte[getContentLength()];
                ServletInputStream is = getInputStream();
                while (len < max) {
                    int next = is.read(buf, len, max - len);
                    if (next < 0 ) {
                        break;
                    }
                    len += next;
                }
                is.close();
                if (len < max) {
                    throw new RuntimeException("Content length mismatch");
                }
                RequestUtil.parseParameters(results, buf, encoding);
            } catch (UnsupportedEncodingException ue) {
                ;
            } catch (IOException e) {
                throw new RuntimeException("Content read fail");
            }
        }

        // Store the final results
        results.setLocked(true);
        parsed = true;
        parameters = results;
    }

    public void setRequestURI(String requestURI) {
        this.requestURI = requestURI;
    }

    public void setContentLength(int contentLength) {
        this.contentLength = contentLength;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public void setQueryString(String queryString) {
        this.queryString = queryString;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    // ... other methods
}

 

package com.whatsmars.tomcat.connector;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Locale;

/**
 * Created by shenhongxi on 16/4/11.
 */
public class HttpResponse implements HttpServletResponse {
    OutputStream output;
    HttpRequest request;
    PrintWriter writer;

    public HttpResponse(OutputStream output) {
        this.output = output;
    }

    public void setRequest(HttpRequest request) {
        this.request = request;
    }

    /**
     * call this method to send headers and response to the output
     */
    public void finishResponse() {
        // sendHeaders();
        // Flush and close the appropriate output mechanism
        if (writer != null) {
            writer.flush();
            writer.close();
        }
    }

    public void addCookie(Cookie cookie) {

    }

    public boolean containsHeader(String name) {
        return false;
    }

    public String encodeURL(String url) {
        return null;
    }

    public String encodeRedirectURL(String url) {
        return null;
    }

    public String encodeUrl(String url) {
        return null;
    }

    public String encodeRedirectUrl(String url) {
        return null;
    }

    public void sendError(int sc, String msg) throws IOException {

    }

    public void sendError(int sc) throws IOException {

    }

    public void sendRedirect(String location) throws IOException {

    }

    // ... other methods
}

 

package com.whatsmars.tomcat.connector;

import com.whatsmars.tomcat.servlet.StaticResourceProcessor;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/**
 * Created by shenhongxi on 16/4/11.
 */
public class HttpProcessor {

    private HttpConnector connector;
    private HttpRequest request;
    private HttpResponse response;
    private HttpRequestLine requestLine = new HttpRequestLine();

    public HttpProcessor(HttpConnector connector) {
        this.connector = connector;
    }

    public void process(Socket socket) {
        SocketInputStream input = null;
        OutputStream output = null;
        try {
            input = new SocketInputStream(socket.getInputStream(), connector.getBufferSize()); // 1.读取套接字的输入流
            output = socket.getOutputStream();

            // create HttpRequest object and parse
            request = new HttpRequest(input);
            response = new HttpResponse(output);
            response.setRequest(request);
            response.setHeader("Server", "Mars Servlet Container");
            
            parseRequest(input, output); // 解析请求行,即HTTP请求的第一行内容
            parseHeaders(input); // 解析请求头

            if (request.getRequestURI().startsWith("/servlet/")) {
                connector.getContainer().invoke((HttpServletRequest) request, (HttpServletResponse) response);
            } else {
                StaticResourceProcessor processor = new StaticResourceProcessor();
                //processor.process(request, response);
            }

            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void parseHeaders(SocketInputStream input) throws IOException, ServletException{
        while (true) { // 一行一行解析完header
            HttpHeader header = new HttpHeader();
            // Read the next header
            input.readHeader(header);
            if (header.nameEnd == 0) {
                if (header.valueEnd == 0) {
                    return;
                } else {
                    throw new ServletException("httpProcessor parseHeaders colon");
                }
            }
            String name = new String(header.name, 0, header.nameEnd);
            String value = new String(header.value, 0, header.valueEnd);
            request.addHeader(name, value);
            // do something for some headers, ignore others.
            if (name.equals("cookie")) {
                // ...
                // request.addCookie(cookies[i]);
            } else if (name.equals("content-length")) {
                int n = -1;
                try {
                    n = Integer.parseInt(value);
                } catch (Exception e) {
                    throw new ServletException("httpProcessor.parseHeaders.contentLength");
                }
                request.setContentLength(n);
            } else if (name.equals("content-type")) {
                request.setContentType(value);
            }
        }
    }

    private void parseRequest(SocketInputStream input, OutputStream output) throws IOException, ServletException {
        input.readRequestLine(requestLine);

        String method = new String(requestLine.method, 0, requestLine.methodEnd);
        String uri = null;
        String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);

        // Validate the incoming request line
        if (method.length() < 1) {
            throw new ServletException("Missing HTTP request method");
        } else if (requestLine.uriEnd < 1) {
            throw new ServletException("Missing HTTP request URI");
        }
        // Parse any query parameters out of the request URI
        int question = requestLine.indexOf("?");
        if (question >= 0) {
            request.setQueryString(new String(requestLine.uri, question + 1,
                    requestLine.uriEnd - question - 1));
            uri = new String(requestLine.uri, 0, question);
        } else {
            request.setQueryString(null);
            uri = new String(requestLine.uri, 0, requestLine.uriEnd);
        }
        String normalizedUri = normalize(uri);

        ((HttpRequest) request).setMethod(method);
        request.setProtocol(protocol);
        if (normalizedUri != null) {
            ((HttpRequest) request).setRequestURI(normalizedUri);
        }
        else {
            ((HttpRequest) request).setRequestURI(uri);
        }

        if (normalizedUri == null) {
            throw new ServletException("Invalid URI: " + uri + "'");
        }
    }

    // Return a context-relative path, beginning with a "/"
    protected String normalize(String path) {
        if (path == null) return null;
        String normalized = path;
        // ...
        return path;
    }
}

 

package com.whatsmars.tomcat.connector;

/**
 * Created by shenhongxi on 16/4/13.
 */
public final class HttpHeader {

    public static final int INITIAL_NAME_SIZE = 32;
    public static final int INITIAL_VALUE_SIZE = 64;
    public static final int MAX_NAME_SIZE = 128;
    public static final int MAX_VALUE_SIZE = 4096;

    public char[] name;
    public int nameEnd;
    public char[] value;
    public int valueEnd;
    protected int hashCode = 0;

    public HttpHeader() {
        this(new char[INITIAL_NAME_SIZE], 0, new char[INITIAL_VALUE_SIZE], 0);
    }


    public HttpHeader(char[] name, int nameEnd, char[] value, int valueEnd) {
        this.name = name;
        this.nameEnd = nameEnd;
        this.value = value;
        this.valueEnd = valueEnd;
    }


    public HttpHeader(String name, String value) {
        this.name = name.toLowerCase().toCharArray();
        this.nameEnd = name.length();
        this.value = value.toCharArray();
        this.valueEnd = value.length();
    }

    /**
     * Release all object references, and initialize instance variables, in
     * preparation for reuse of this object.
     */
    public void recycle() {
        nameEnd = 0;
        valueEnd = 0;
        hashCode = 0;
    }

}

 

package com.whatsmars.tomcat.connector;

/**
 * Created by shenhongxi on 16/4/13.
 */
public final class HttpRequestLine {

    public static final int INITIAL_METHOD_SIZE = 8;
    public static final int INITIAL_URI_SIZE = 64;
    public static final int INITIAL_PROTOCOL_SIZE = 8;
    public static final int MAX_METHOD_SIZE = 1024;
    public static final int MAX_URI_SIZE = 32768;
    public static final int MAX_PROTOCOL_SIZE = 1024;

    public char[] method;
    public int methodEnd;
    public char[] uri;
    public int uriEnd;
    public char[] protocol;
    public int protocolEnd;

    public HttpRequestLine() {
        this(new char[INITIAL_METHOD_SIZE], 0, new char[INITIAL_URI_SIZE], 0,
                new char[INITIAL_PROTOCOL_SIZE], 0);
    }


    public HttpRequestLine(char[] method, int methodEnd,
                           char[] uri, int uriEnd,
                           char[] protocol, int protocolEnd) {
        this.method = method;
        this.methodEnd = methodEnd;
        this.uri = uri;
        this.uriEnd = uriEnd;
        this.protocol = protocol;
        this.protocolEnd = protocolEnd;
    }

    public int indexOf(String str) {
        // ...
        return -1;
    }

    /**
     * Release all object references, and initialize instance variables, in
     * preparation for reuse of this object.
     */
    public void recycle() {
        methodEnd = 0;
        uriEnd = 0;
        protocolEnd = 0;
    }

}

 

package com.whatsmars.tomcat.connector;

import java.io.IOException;
import java.io.InputStream;

/**
 * Created by shenhongxi on 16/4/11.
 * Extends InputStream to be more efficient reading lines during HTTP header processing.
 */
public class SocketInputStream extends InputStream {

    /**
     * Underlying input stream.
     */
    private InputStream input;

    /**
     * Internal buffer.
     */
    protected byte[] buf;


    /**
     * Last valid byte.
     */
    protected int count;


    /**
     * Position in the buffer.
     */
    protected int pos;

    public SocketInputStream(InputStream input, int bufferSize) {
        this.input = input;
        this.buf = new byte[bufferSize];
    }

    // input => buf => HttpRequestLine
    public void readRequestLine(HttpRequestLine requestLine) throws IOException {
        // Recycling check
        if (requestLine.methodEnd != 0)
            requestLine.recycle();

        // Checking for a blank line

        // Reading the method name

        // Reading URI

        // Reading protocol
    }

    // input => buf => HttpHeader
    public void readHeader(HttpHeader header) throws IOException {
        // Recycling check
        if (header.nameEnd != 0)
            header.recycle();

        // Checking for a blank line

        // Reading the header name

        // Reading the header value (which can be spanned over multiple lines)
    }

    @Override
    public int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return buf[pos++] & 0xff;
    }

    /**
     * Fill the internal buffer using data from the undelying input stream.
     */
    protected void fill()
            throws IOException {
        pos = 0;
        count = 0;
        int nRead = input.read(buf, 0, buf.length);
        if (nRead > 0) {
            count = nRead;
        }
    }
}

 

package com.whatsmars.tomcat.connector;

import com.whatsmars.tomcat.servlet.Constants;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;

/**
 * Created by shenhongxi on 16/4/14.
 */
public class SimpleContainer implements Container {

    public void invoke(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        String servletName = ( (HttpServletRequest) request).getRequestURI();
        servletName = servletName.substring(servletName.lastIndexOf("/") + 1);
        URLClassLoader loader = null;
        try {
            URL[] urls = new URL[1];
            URLStreamHandler streamHandler = null;
            File classPath = new File(Constants.WEB_ROOT);
            String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
            urls[0] = new URL(null, repository, streamHandler);
            loader = new URLClassLoader(urls);
        } catch (IOException e) {
            System.out.println(e.toString() );
        }
        Class myClass = null;
        try {
            myClass = loader.loadClass(servletName);
        }
        catch (ClassNotFoundException e) {
            System.out.println(e.toString());
        }

        Servlet servlet = null;

        try {
            servlet = (Servlet) myClass.newInstance();
            servlet.service((HttpServletRequest) request, (HttpServletResponse) response);
        }
        catch (Exception e) {
            System.out.println(e.toString());
        }
        catch (Throwable e) {
            System.out.println(e.toString());
        }
    }
}

 

package com.whatsmars.tomcat.connector;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by shenhongxi on 16/4/14.
 */
public interface Container {

    public void invoke(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
}

 最后,关于HttpProcessor池,连接器线程和处理器线程的等待与唤醒,请参考多线程知识自行脑补。

 

Request和Response的外观类(包装类)参见http://wely.iteye.com/blog/2290575

 

 

 

0
3
分享到:
评论

相关推荐

    简单的tomcat实现1

    手写tomcat,模拟tomcat数据处理脉络,针对tomcat容器的关键部分提取核心代码,通过浅显的代码,讲述tomcat连接器与容器之间的关系

    APACHE 2.2.9+TOMCAT6.0.18配置负载均衡

    只用用压力测试工具模拟大量用户同时访问,你会发现四个tomcat控制台均有打出控制信息,说明均衡器工作正常。 3、测试Session复制 访问url: http://localhost/examples/servlet/SessionExample 可以得到一个关于...

    2024年Tomcat安装和配置(超详细)

    内容包括Tomcat的基础概念、Java JDK的安装、Tomcat的下载、环境变量的配置、Tomcat的启动和验证、Web应用程序的部署、Tomcat的配置文件编辑、虚拟主机的配置、连接器的设置、会话管理、安全性配置、性能监控以及...

    LojoRentVideoClub:使用DAO模式和JAVA 11,MySQL,Tomcat 8.5,Json Data和Ajax和jQuery的视频租用Web应用程序

    数据库连接器。 -Gson库。 -JAVA 11。 对于Ajax方法。 井上: :rocket: Eclipse企业版: 项目结构和后台开发(JAVA 11)。 WebStorm: WebContent软件包(HTML,CSS3,JS ES 6,用于Ajax调用的jQuery)的...

    Java案例开发锦集

    案例5 利用DES加密解密 第七章 Java与数据库 案例1 在Applet中应用JDBC访问数据库 案例2 通过JDBC-ODBC桥连接数据库 案例3 通过tomcat数据源访问数据库 案例4 JDBC连接池的实现 案例5 用...

    wince6.0模拟器|wince软件6.0模拟器下载(附使用方法) - 软件学堂

    wince6.0模拟器是一个车载式PC模拟器,英文全称为:windows embedded ce6.0,主要是使用在3D地图及软件模拟方面,像车载凯立德导航就可以完全的在wince6.0模拟器中使用。另外它集成了GPS模拟器(Virace GPS),可以...

    在线购物系统

    模拟当当网购物系统 分层开发 表现层+控制器+业务层 表现层使用jsp、jstl、jQuery技术 控制器使用smartstruts框架的控制器 业务层使用javaBean 数据访问层使用DAO+工厂、dbcp连接池 通用层:共通的javaBean

    Java项目开发与毕业设计指导

    使用Eclipse导入项目ch09, 在src/config.properties中配置数据库连接信息, 然后部署项目、启动tomcat。 访问http://localhost:8080/ajax即可启动本程序。 Ch10:一个简单的编译器实现 安装JDK、配置环境变量,...

    最全面的门户网站架构设计方案.doc

    5 3.4.3 WEB服务器集群内存性能核算 5 3.4.4 网络带宽 5 4 性能模拟测试及性能推算 6 4.1 测试环境 6 4.2 测试结果 8 4.2.1 1个客户端模拟不同线和并发请求结果 8 4.2.2 10个客户端请求 8 4.3 结果分析 9 4.4 根据...

    百度地图开发java源码-TypicalWebProject:一个典型的JavaWeb项目

    对Controller层:模拟了SpringMVC,用过滤器+反射,对提交的表单信息封装在JavaBean对象中。 手写了一个数据库连接池。 令牌机制防止表单重复提交。 注册表单的JS验证、Ajax用户名唯一性验证等等。 开发环境: jdk...

    JAVA上百实例源码以及开源项目源代码

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    Spring.3.x企业应用开发实战(完整版).part2

    7.10.3 在Tomcat下的配置 7.10.4 在其他Web应用服务器下的配置 7.11 小结 第3篇 数据访问 第8章 Spring对DAO的支持 8.1 Spring的DAO理念 8.2 统一的异常体系 8.2.1 Spring的DAO异常体系 8.2.2 JDBC的异常转换器 ...

    Spring3.x企业应用开发实战(完整版) part1

    7.10.3 在Tomcat下的配置 7.10.4 在其他Web应用服务器下的配置 7.11 小结 第3篇 数据访问 第8章 Spring对DAO的支持 8.1 Spring的DAO理念 8.2 统一的异常体系 8.2.1 Spring的DAO异常体系 8.2.2 JDBC的异常转换器 ...

    低清版 大型门户网站是这样炼成的.pdf

    1.2.5 支持集群功能的web服务器tomcat 21 1.2.6 开源数据库服务器之骄子mysql 23 1.2.7 功能强大的flv流媒体服务器red5 24 1.3 门户网站开发指导思想 26 1.4 ssh 2组合框架—门户网站开发之首选 28 1.4.1 mvc...

    JavaScript完全自学宝典 源代码

    16.1.html 使用JavaScript访问驱动器。 16.2.html 在JavaScript中使用FileSystemObject操作文件夹。 16.3.html 使用JavaScript获取指定文件并列出其内容。 16.4.html 在JavaScript中使用...

    Web安全深度剖析(张柄帅)

    6.3 文本编辑器上传漏洞 123 6.4 修复上传漏洞 127 6.5 小结 128 第7章 XSS跨站脚本漏洞 129 7.1 XSS原理解析 129 7.2 XSS类型 130 7.2.1 反射型XSS 130 7.2.2 存储型XSS 131 7.2.3 DOM XSS 132 7.3 检测XSS 133 ...

    Java开发技术大全(500个源代码).

    listConstructors.java 利用反射机制获取构造器列表 listFields.java 利用反射机制获取成员属性列表 listMethods.java 利用反射机制获取成员方法列表 loadClass.java 动态装载一个类 Shape.java 一个用于测试的...

    AJAX基础概念、核心技术与典型案例(内涵动态实例)

    服务器采用Tomcat 5.0 及以上版本 开发工具采用Eclipse 3.1以上版本 3.本书所附光盘范例 第1章(/C01/) JsWeb 传统的JavaScript模式实现刷新 IframeWeb 基于框架的不刷新模式 AjaxWeb 基于...

Global site tag (gtag.js) - Google Analytics