首页 > 数据库技术 > 详细

HSQLDB源码阅读 (一)从程序入口开始

时间:2014-10-30 13:13:36      阅读:303      评论:0      收藏:0      [点我收藏+]
最近一段业余时间,学围棋、五子棋、黑白棋、2048,完事之后,学一点就学不进去了——年龄大了,学什么都困难了。
此为题外话,想来想去,也许业余时间只有读读代码,才学得进去吧。

hsqldb是一个开放源代码的JAVA数据库,其具有标准的SQL语法和JAVA接口。当然为作源码阅读的主要原因是代码量比较小,作为首次阅读源码,这很重要。

于是就从 http://hsqldb.org/ 下载了源码。
源码是下载下来了,src目录下,这么多文件以及文件夹,之前也没有阅读一个完整源代码的经验,从何开始呢?
bubuko.com,布布扣

原本想一个个文件的看吧,突然灵光一闪,应该从程序入口开始。
hsqldb可以使用命令行方式 java -cp xxxx org.hsqldb.server.Server 或者  java -cp xxxx org.hsqldb.server.WebServer的方式,作为服务器启动。
就从Server/WebServer的main方法开始。


点击(此处)折叠或打开

  1. public static void main(String[] args) {

  2.         HsqlProperties argProps = null;

  3.         argProps = HsqlProperties.argArrayToProps(args,
  4.                 ServerProperties.sc_key_prefix);

  5.         String[] errors = argProps.getErrorKeys();

  6.         if (errors.length != 0) {
  7.             System.out.println("no value for argument:" + errors[0]);
  8.             printHelp("server.help");

  9.             return;
  10.         }

  11.         String propsPath = argProps.getProperty(ServerProperties.sc_key_props);
  12.         String propsExtension = "";

  13.         if (propsPath == null) {
  14.             propsPath = "server";
  15.             propsExtension = ".properties";
  16.         } else {
  17.             argProps.removeProperty(ServerProperties.sc_key_props);
  18.         }

  19.         propsPath = FileUtil.getFileUtil().canonicalOrAbsolutePath(propsPath);

  20.         ServerProperties fileProps = ServerConfiguration.getPropertiesFromFile(
  21.             ServerConstants.SC_PROTOCOL_HSQL, propsPath, propsExtension);
  22.         ServerProperties props =
  23.             fileProps == null
  24.             ? new ServerProperties(ServerConstants.SC_PROTOCOL_HSQL)
  25.             : fileProps;

  26.         props.addProperties(argProps);
  27.         ServerConfiguration.translateDefaultDatabaseProperty(props);

  28.         // Standard behaviour when started from the command line
  29.         // is to halt the VM when the server shuts down. This may, of
  30.         // course, be overridden by whatever, if any, security policy
  31.         // is in place.
  32.         ServerConfiguration.translateDefaultNoSystemExitProperty(props);
  33.         ServerConfiguration.translateAddressProperty(props);

  34.         // finished setting up properties;
  35.         Server server = new Server();

  36.         try {
  37.             server.setProperties(props);
  38.         } catch (Exception e) {
  39.             server.printError("Failed to set properties");
  40.             server.printStackTrace(e);

  41.             return;
  42.         }

  43.         // now messages go to the channel specified in properties
  44.         server.print("Startup sequence initiated from main() method");

  45.         if (fileProps != null) {
  46.             server.print("Loaded properties from [" + propsPath
  47.                          + propsExtension + "]");
  48.         } else {
  49.             server.print("Could not load properties from file");
  50.             server.print("Using cli/default properties only");
  51.         }

  52.         server.start();
  53.     }
在main方法中,主要完成参数的读取、new Server对象设置参数后调用start方法。
在此方法中,声明一个HsqlProperties类来读取、解析参数是一个不错的代码方式,可以将配置项都体现在该类中——如果代码都在Server(也即main所在的类)实现的话,那就显得Server职责过多。

下面再看server.start方法

点击(此处)折叠或打开

  1. public int start() {

  2.         printWithThread("start() entered");

  3.         int previousState = getState();

  4.         if (serverThread != null) {
  5.             printWithThread("start(): serverThread != null; no action taken");

  6.             return previousState;
  7.         }

  8.         setState(ServerConstants.SERVER_STATE_OPENING);

  9.         serverThread = new ServerThread("HSQLDB Server ");

  10.         if (isDaemon) {
  11.             serverThread.setDaemon(true);
  12.         }

  13.         serverThread.start();

  14.         // call synchronized getState() to become owner of the Server Object‘s monitor
  15.         while (getState() == ServerConstants.SERVER_STATE_OPENING) {
  16.             try {
  17.                 Thread.sleep(100);
  18.             } catch (InterruptedException e) {}
  19.         }

  20.         printWithThread("start() exiting");

  21.         return previousState;
  22.     }
这里开启了一个后台线程,去处理启动数据库,然后开启端口监听,而主线程,则在这里每隔100毫秒检查一下状态,一直等到启动结束或者关闭等状态。
这里要开一个新的线程,因为当前线程可能是别的地方调用了方法,需要返回值的。

那我们再来看看程序的主体工作又是在做什么,先是ServerThread

点击(此处)折叠或打开

  1. private class ServerThread extends Thread {

  2.         /**
  3.          * Constructs a new thread in which to execute the run method
  4.          * of this server.
  5.          *
  6.          * @param name The thread name
  7.          */
  8.         ServerThread(String name) {

  9.             super(name);

  10.             setName(name + ‘@‘ + Integer.toString(Server.this.hashCode(), 16));
  11.         }

  12.         /**
  13.          * Executes the run() method of this server
  14.          */
  15.         public void run() {
  16.             Server.this.run();
  17.             printWithThread("ServerThread.run() exited");
  18.         }
  19.     }
这里代码很简单,这是Server的一个内部类,然后又回到Server.run方法去了。

点击(此处)折叠或打开

  1. private void run() {

  2.         StopWatch sw;
  3.         ThreadGroup tg;
  4.         String tgName;

  5.         printWithThread("run() entered");
  6.         print("Initiating startup sequence...");
  7.         printProperties();

  8.         sw = new StopWatch();

  9.         setServerError(null);

  10.         try {

  11.             // Faster init first:
  12.             // It is huge waste to fully open the databases, only
  13.             // to find that the socket address is already in use
  14.             openServerSocket();
  15.         } catch (Exception e) {
  16.             setServerError(e);
  17.             printError("run()/openServerSocket(): ");
  18.             printStackTrace(e);
  19.             shutdown(true);

  20.             return;
  21.         }

  22.         tgName = "HSQLDB Connections @"
  23.                  + Integer.toString(this.hashCode(), 16);
  24.         tg = new ThreadGroup(tgName);

  25.         tg.setDaemon(false);

  26.         serverConnectionThreadGroup = tg;

  27.         // Mount the databases this server is supposed to host.
  28.         // This may take some time if the databases are not all
  29.         // already open.
  30.         if (!openDatabases()) {
  31.             setServerError(null);
  32.             printError("Shutting down because there are no open databases");
  33.             shutdown(true);

  34.             return;
  35.         }

  36.         // At this point, we have a valid server socket and
  37.         // a valid hosted database set, so its OK to start
  38.         // listening for connections.
  39.         setState(ServerConstants.SERVER_STATE_ONLINE);
  40.         print(sw.elapsedTimeToMessage("Startup sequence completed"));
  41.         printServerOnlineMessage();

  42.         // isShuttingDown is only read after socket connections are ‘accept‘ed.
  43.         isShuttingDown = false; // In case shutdown was aborted previously.

  44.         try {
  45.             /*
  46.              * This loop is necessary for UNIX w/ Sun Java 1.3 because
  47.              * in that case the socket.close() elsewhere will not
  48.              * interrupt this accept().
  49.              */
  50.             while (socket != null) {
  51.                 try {
  52.                     handleConnection(socket.accept());
  53.                 } catch (java.io.InterruptedIOException iioe) {}
  54.             }
  55.         } catch (IOException ioe) {
  56.             if (getState() == ServerConstants.SERVER_STATE_ONLINE) {
  57.                 setServerError(ioe);
  58.                 printError(this + ".run()/handleConnection(): ");
  59.                 printStackTrace(ioe);
  60.             }
  61.         } catch (Throwable t) {
  62.             printWithThread(t.toString());
  63.         } finally {
  64.             shutdown(false); // or maybe getServerError() != null?
  65.         }
  66.     }
写过tcp服务端的人可能比较熟悉,就是绑定socket端口,然后while循环一直监听到有客户端进行连接,有连接就调用handleConnection进行处理。


点击(此处)折叠或打开

  1. public void handleConnection(Socket s) {

  2.         Thread t;
  3.         Runnable r;
  4.         String ctn;

  5.         printWithThread("handleConnection(" + s + ") entered");

  6.         if (!allowConnection(s)) {
  7.             try {
  8.                 s.close();
  9.             } catch (Exception e) {}

  10.             printWithThread("allowConnection(): connection refused");
  11.             printWithThread("handleConnection() exited");

  12.             return;
  13.         }

  14.         // Maybe set up socket options, SSL
  15.         // Session tracing/callbacks, etc.
  16.         if (socketFactory != null) {
  17.             socketFactory.configureSocket(s);
  18.         }

  19.         if (serverProtocol == ServerConstants.SC_PROTOCOL_HSQL) {
  20.             r = new ServerConnection(s, this);
  21.             ctn = ((ServerConnection) r).getConnectionThreadName();
  22.         } else {
  23.             r = new WebServerConnection(s, (WebServer) this);
  24.             ctn = ((WebServerConnection) r).getConnectionThreadName();
  25.         }

  26.         t = new Thread(serverConnectionThreadGroup, r, ctn);

  27.         t.start();
  28.         printWithThread("handleConnection() exited");
  29.     }
在这里,为每一个客户端新建一个线程进行处理(线程放入ThreadGroup中),处理函数转接到ServerConnection/WebServerConnection——分别对应不同的客户端协议处理。

至此,Server这个入口基本上清晰了。
1. 解析配置(含命令行的、配置文件的)
2. 声明一个服务监听线程,打开socket端口,进行监听
3. 对于每一个连接而来的客户端,声明一个线程,进行处理
4. 下一步客户端协议的请求响应处理,进入ServerConnection/WebServerConnection中

WebServer继承自Server,内容基本一样。

[相关源码文件]
Server.java
WebServer.java
HsqlProperties.java
ServerProperties.java
ServerConfiguration.java
HsqlSocketFactory.java









HSQLDB源码阅读 (一)从程序入口开始

原文:http://blog.chinaunix.net/uid-29966746-id-4561171.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!