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

Derby源代码分析 -- 服务器启动(一)

阅读更多
一直以来都想研究下数据库的实现原理,Derby在我眼里绝对是一个完美的切入点。首先它是100%纯Java实现,对于我这种Java程序员来说简直完美的,不需要去懂C,C++...等等无疑减少了很大的难度;其次,它是开源的,当然这个就是废话,不然我去哪里弄它的源码去。废话少说,首先简单的介绍下Derby。

Derby的启动方式有两种,一种是网络服务器的方式,这种方式就和大家平时用的Oracle,SQL Server,DB2等等没什么区别,另外一种是嵌入式方式,是一种类似于Access的方式,在这种方式下,Derby与应用程序运行于同一个JVM下,随着应用程序的关闭而关闭(我很欣赏这个方式,呵呵)。另外,Java6中包含的Java DB其实就是Derby。具体的可以google下Derby,会有更加详细的介绍,我这里就不赘述了。

好了,简单的介绍后,来转入正题,看一下Derby服务器的启动上。

1. 首先来了解下网络服务器的方式

Derby有几种启动方式,其中一种就是用bin目录下的startNetworkServer.bat这个脚本文件。可以大致的看一下它,可以发现Derby网络服务器方式是在org.apache.derby.drda.NetworkServerControl类启动的,并且为命令行传入一个参数start。好了,下面就可以以这个类为起点来看Derby的启动部分了。

根据我对Derby源代码的大致理解,Derby的网络服务器方式的启动所涉及的类大致如下图:



下面首先来看看NetworkServerControl的源代码吧,

	public static void main(String args[]) {
		NetworkServerControlImpl server = null;

		boolean printErrors = true;
		try {
			server = new NetworkServerControlImpl();

			int command = server.parseArgs(args);
			if (needsSecurityManager(server, command)) {
				verifySecurityState(server);
				installSecurityManager(server);
			}
			printErrors = false;
			/* 执行命令 */
			server.executeWork(command);
		} catch (Exception e) {
			if ((e.getMessage() == null) || !e.getMessage().equals(NetworkServerControlImpl.UNEXPECTED_ERR) || printErrors) {
				if (server != null)
					server.consoleExceptionPrint(e);
				else
					e.printStackTrace();
			}
			System.exit(1);
		}
		System.exit(0);

	}


这段代码没有什么复杂的,最主要的不服是调用了server的executeWork()方法,其中server是一个NetworkServerControlImpl的实例。
executeWork()方法主要是对各种不同的参数进行不同的调用,由于我们是看的启动部分,所以就只看一部分就可以了。

	public void executeWork(int command) throws Exception {
		if (command == COMMAND_UNKNOWN)
			return;

		if (commandArgs.size() != COMMAND_ARGS[command])
			consolePropertyMessage("DRDA_InvalidNoArgs.U", COMMANDS[command]);
		int min;
		int max;

		switch (command) {
		case COMMAND_START:
			shutdownDatabasesOnShutdown = true;
			/* 开启网络服务 */
			blockingStart(makePrintWriter(System.out));
			break;
		case COMMAND_SHUTDOWN:

		......

		}
	}


这里没什么可说的,主要就是要看这个blockStart()方法了,这个方法比较长,我把一些异常处理的部分去掉了

	public void blockingStart(PrintWriter consoleWriter) throws Exception {
		/* 1. 载入Derby的Driver */
		startNetworkServer();
		setLogWriter(consoleWriter);
		cloudscapeLogWriter = Monitor.getStream().getPrintWriter();
		if (SanityManager.DEBUG && debugOutput) {
			memCheck.showmem();
			mc = new memCheck(200000);
			mc.start();
		}

		/* 2. 打开一个ServerSocket */
		try {
			serverSocket = (ServerSocket) AccessController
					.doPrivileged(new PrivilegedExceptionAction() {
						public Object run() throws IOException {
							return createServerSocket();
						}
					});
		} catch (PrivilegedActionException e) {
			......
		} catch (Exception e) {
			......
		}

		switch (getSSLMode()) {
		default:
		case SSL_OFF:
			consolePropertyMessage("DRDA_Ready.I", new String[] { Integer.toString(portNumber), att_srvclsnm, versionString });
			break;
		case SSL_BASIC:
			consolePropertyMessage("DRDA_SSLReady.I", new String[] { Integer.toString(portNumber), att_srvclsnm, versionString });
			break;
		case SSL_PEER_AUTHENTICATION:
			consolePropertyMessage("DRDA_SSLClientAuthReady.I", new String[] { Integer.toString(portNumber), att_srvclsnm, versionString });
			break;
		}

		/* 3. 新开一个ClientThread去接受用户请求 */
		final ClientThread clientThread = (ClientThread) AccessController
				.doPrivileged(new PrivilegedExceptionAction() {
					public Object run() throws Exception {
						return new ClientThread(thisControl, serverSocket);
					}
				});
		clientThread.start();

		ManagementService mgmtService = ((ManagementService) Monitor.getSystemModule(Module.JMX));

		final Object versionMBean = mgmtService.registerMBean(new Version(getNetProductVersionHolder(), SystemPermission.SERVER), VersionMBean.class, "type=Version,jar=derbynet.jar");
		final Object networkServerMBean = mgmtService.registerMBean(new NetworkServerMBeanImpl(this), NetworkServerMBean.class,"type=NetworkServer");

		/* 直到shutdown或者出现InterruptedException,否则一直wait() */
		synchronized (shutdownSync) {
			try {
				shutdownSync.wait();
			} catch (InterruptedException e) {
				shutdown = true;
			}
		}

		AccessController.doPrivileged(new PrivilegedAction() {
			public Object run() {
				if (mc != null)
					mc.interrupt();

				clientThread.interrupt();
				return null;
			}
		});

		/* 关闭Session连接 */
		synchronized (sessionTable) {
			for (Enumeration e = sessionTable.elements(); e.hasMoreElements();) {
				Session session = (Session) e.nextElement();
				session.close();
			}
		}

		/* 关闭DRDA协议客户端连接 */
		synchronized (threadList) {
			for (int i = 0; i < threadList.size(); i++) {
				final DRDAConnThread threadi = (DRDAConnThread) threadList.get(i);
				threadi.close();
				AccessController.doPrivileged(new PrivilegedAction() {
					public Object run() {
						threadi.interrupt();
						return null;
					}
				});
			}
			threadList.clear();
		}

		/* 关闭ServerSocket */
		try {
			serverSocket.close();
		} catch (IOException e) {
			consolePropertyMessage("DRDA_ListenerClose.S", true);
		}

		/* 唤醒等待中的线程 */
		synchronized (runQueue) {
			runQueue.notifyAll();
		}

		mgmtService.unregisterMBean(versionMBean);
		mgmtService.unregisterMBean(networkServerMBean);

		/* 关闭Derby */
		if (shutdownDatabasesOnShutdown) {
			try {
				if (cloudscapeDriver != null) {
					final Properties p = new Properties();
					if (userArg != null) {
						p.setProperty("user", userArg);
					}
					if (passwordArg != null) {
						p.setProperty("password", passwordArg);
					}
					cloudscapeDriver.connect("jdbc:derby:;shutdown=true", p);
				}
			} catch (SQLException sqle) {
				......
			}
		}

		consolePropertyMessage("DRDA_ShutdownSuccess.I", new String[] { att_srvclsnm, versionString });
	}


这段代码有3个地方需要仔细研究下,分别在上述代码中用注释标注的1,2,3处。

首先来看一下第1处,就是Derby驱动的载入,

	protected void startNetworkServer() throws Exception {
		boolean restartCheck = this.restartFlag;
		synchronized (serverStartSync) {

			if (restartCheck == this.restartFlag) {
				try {
					/* 清理Session队列 */
					if (cleanupOnStart) {
						synchronized (runQueue) {
							for (int i = 0; i < runQueue.size(); i++) {
								Session s = (Session) runQueue.get(i);
								s.close();
								removeFromSessionTable(s.getConnNum());
							}
							runQueue.clear();
						}

						cloudscapeDriver = null; // so it gets collected.
						System.gc();
					}

					/* 先载入org.apache.derby.jdbc.EmbeddedDriver这个驱动,这个是嵌入式方式的驱动 */
					/* 在这里会载入嵌入式方式的驱动备用 */
					Class.forName(CLOUDSCAPE_DRIVER).newInstance();
					cloudscapeDriver = DriverManager.getDriver(Attribute.PROTOCOL);

				} catch (Exception e) {
					this.consoleExceptionPrintTrace(e);
					consolePropertyMessage("DRDA_LoadException.S", e.getMessage());
				}
				cleanupOnStart = true;
				this.restartFlag = !this.restartFlag;
			}
		}
	}


这里主要做的就是驱动的载入,这里还不清楚网络服务器方式载入嵌入式驱动的原因,随着研究的深入会慢慢了解的。

下面来看第二个重要部分,就是ServerSocket的创建,

	private ServerSocket createServerSocket() throws IOException {
		if (hostAddress == null)
			hostAddress = InetAddress.getByName(hostArg);
		// 创建本地地址列表
		buildLocalAddressList(hostAddress);

		// 根据不同的情况来创建Socket
		switch (getSSLMode()) {
		case SSL_OFF:
		default:
			ServerSocketFactory sf = ServerSocketFactory.getDefault();
			return sf.createServerSocket(portNumber, 0, hostAddress);
		case SSL_BASIC:
			SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory
					.getDefault();
			return (SSLServerSocket) ssf.createServerSocket(portNumber, 0,
					hostAddress);
		case SSL_PEER_AUTHENTICATION:
			SSLServerSocketFactory ssf2 = (SSLServerSocketFactory) SSLServerSocketFactory
					.getDefault();
			SSLServerSocket sss2 = (SSLServerSocket) ssf2.createServerSocket(
					portNumber, 0, hostAddress);
			sss2.setNeedClientAuth(true);
			return sss2;
		}
	}


最后一个部分是新开一个ClientThread去接受用户请求,由于ClientThread是一个线程类,可以看下它的#run()的实现。

	public void run() {
		Socket clientSocket = null;

		for (;;) { // 用一个死循环去不断的处理客户端连接

			try { // 捕获所有异常的try

				try { // 捕获InterruptedException,SSLException和IOException

					try { // 捕获PrivilegedActionException
						/* 从ServerSocket获得Socket */
						clientSocket = (Socket) AccessController
								.doPrivileged(new PrivilegedExceptionAction() {
									public Object run() throws IOException {
										return serverSocket.accept();
									}
								});
						/* 判断服务器是否关闭了 */
						if (parent.getShutdown()) {
							clientSocket.close();
							return;
						}
						/* 设定属性 */
						clientSocket.setKeepAlive(parent.getKeepAlive());

						if (timeSlice > 0)
							clientSocket.setSoTimeout(timeSlice);

						/* 加入Session队列 */
						parent.addSession(clientSocket);

					} catch (PrivilegedActionException e) {
						throw e.getException();
					}

				} catch (InterruptedException ie) {
					return;

				} catch (javax.net.ssl.SSLException ssle) {
					parent.consoleExceptionPrintTrace(ssle);
					parent.directShutdownInternal();
					return;

				} catch (IOException ioe) {
					synchronized (parent.getShutdownSync()) {
						if (!parent.getShutdown()) {
							parent.consoleExceptionPrintTrace(ioe);
							if (clientSocket != null)
								clientSocket.close();
						}
					}
					return;
				}
			} catch (Exception e) {
				parent.consoleExceptionPrintTrace(e);
				try {
					if (clientSocket != null)
						clientSocket.close();
				} catch (IOException closeioe) {
					parent.consoleExceptionPrintTrace(closeioe);
				}
			}

		}

	}


这样,当有新的Socket请求到了服务器时,会把这个请求加入到NetworkServerControlImpl的Session队列中等待处理。
  • 大小: 21.7 KB
分享到:
评论
1 楼 zhaojian770627 2012-10-27  
不错,学习中,谢谢

相关推荐

    db-derby-10.11.1.1-bin.zip

    Apache Derby,也被称为Java DB,是一款轻量级、开源的关系型数据库管理系统,完全用Java编写,遵循Apache软件基金会的开放源代码协议。这个名为"db-derby-10.11.1.1-bin.zip"的压缩包包含了Apache Derby 10.11.1.1...

    db-derby-10.11.1.1-src.zip

    在"db-derby-10.11.1.1-src"中,包含了Derby数据库的主要源代码,开发者可以通过阅读源码来学习如何设计和实现一个数据库系统,包括查询解析、存储引擎、事务管理、锁机制等核心部分。此外,"db-derby-10.11.1.1-doc...

    Swing+derby仿QQ聊天软件及源码

    在这个"Swing+derby仿QQ聊天软件及源码"项目中,开发者利用Swing库来设计和实现了一个类似QQ的聊天软件。Swing提供了一系列的组件,如JFrame(主窗口)、JButton(按钮)、JLabel(标签)、JTextArea(文本区域)和...

    derby+myBatis 入门

    在本教程中,读者将了解如何下载、安装并启动Derby数据库服务器,以及如何连接到数据库并执行基本的SQL操作。 2. **MyBatis框架**:MyBatis是一个持久层框架,它允许开发者编写SQL语句,并将这些SQL语句与Java代码...

    使用 Java DB (Derby) 数据库

    - **javadoc 子目录**:包含通过源代码注释生成的 API 文档。 - **docs 子目录**:包含 JavaDB 文档。 - **lib 子目录**:包含 JavaDB jar 文件。 3. **在 NetBeans IDE 中注册数据库**: - 在“服务”窗口中,...

    学习使用jdk1.7中内置数据库Derby(三)

    7. **源码分析**:通过阅读这些示例代码,我们可以理解如何在实际项目中集成Derby,包括设置连接参数、执行SQL语句和处理结果集。 8. **性能与优化**:虽然Derby适合小型应用,但也有一定的性能考虑。例如,可以...

    derby例子

    Apache Derby是一个开源的关系型数据库管理系统,它属于Java平台下的轻量级数据库,由Apache软件基金会维护。这个"derby例子"可能是一个示例项目或教程,用于帮助学习者理解和使用Apache Derby。在本文中,我们将...

    Apache Derby 10.6版手册集

    Apache Derby是一个由Apache软件基金会研发的开源关系数据库管理系统(RDBMS),它的特点在于完全用Java编写,这意味着它具有很好的可移植性。由于其纯Java的特性,Derby可以在任何支持Java虚拟机的操作系统上运行,...

    源代码检查工具SONAR使用经验

    1. **下载源码或发行版**:Sonar的源代码可以通过Git从GitHub仓库克隆,而如果仅需使用Sonar,则可以直接从官网下载最新的发行包。 ```shell git clone git://github.com/SonarSource/sonar.git ``` 2. **解...

    销售信息管理系统v0.3带源代码.zip

    Java Derby,又称为Apache Derby,是一款轻量级的关系型数据库管理系统,它嵌入到Java应用中,无需单独的服务器进程。Derby使用Java编写,完全兼容Java Database Connectivity (JDBC) API,使得开发者可以直接通过...

    MyEclipse 6 Java 开发中文教程

    - 直接粘贴Java源码为类文件:将源代码直接转换为类文件。 - 复制项目中的文件:在项目内部复制文件。 - 断点和调试器:使用断点调试程序。 - 快速加入、删除jar包到BuildPath:管理项目的依赖库。 - 查看当前...

    MyEclipse.6.Java.开发中文教程(1-10章)

    - **查看类定义、层次和源码**:利用IDE的强大功能浏览和分析源代码。 - **查找类文件(Open Type)**:快速定位类文件。 - **源码目录、输出路径、Library和编译器版本设置**:自定义项目的构建设置。 - **生成...

    MyEclipse6Java开发中文教程

    - **CVS团队源代码管理**: 介绍如何使用CVS进行源代码管理。 - **字符编码设置**: 说明如何修改文件的字符编码。 #### 五、数据库管理 - **功能概述**: 概述MyEclipse Database Explorer的主要功能。 - **透视图...

    myeclipse6 开发教程

    - **CVS 团队源代码管理**: 集成 CVS 版本控制系统。 - **修改文件的字符编码**: 设置文件编码格式。 3. **小结**: - 汇总了 Eclipse 常用的操作和配置技巧。 #### 四、使用 MyEclipse Database Explorer 管理...

    MyEclipse 6 java EE 开发中文手册

    - CVS团队源代码管理:集成CVS进行版本控制。 ### 5. 利用MyEclipse Database Explorer进行数据库管理 - **功能一览**:包括连接数据库、浏览数据库结构、执行SQL语句、生成实体关系图等。 - **具体操作**: - ...

    oozie-4.3.1.tar.gz

    oozie-4.3.1目录下包含了Oozie的源代码、构建脚本、文档和配置文件等。主要目录结构如下: - `src/main`:存放主要的源代码,包括Java类和XML配置文件。 - `src/test`:包含单元测试代码。 - `build.xml`:Ant构建...

Global site tag (gtag.js) - Google Analytics