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

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

阅读更多
2. 嵌入式方式

在开始这部分前,有一些必须的Derby架构的东西需要好好的了解下,可以在Derby的官方网站看一下,地址是http://db.apache.org/derby/papers/derby_arch.html

首先,Derby是由monitor和一系列的module组成的,每个module都代表了一个独立的功能,并且基接口通常是在java.sql包中定义的接口,比如JDBC驱动,锁管理等等。而monitor可以把对module的请求映射到module的具体实现上。比如JDBC驱动,monitor会把来自JDK1.3的请求转给JDBC2.0的实现,而JDK1.4的则转给JDBC3.0的实现。

对Derby的结构的描述就大致说这些吧,有兴趣的可以去官网仔细的了解下。下面转入正题,

一个应用程序和使用嵌入式方式的Derby进行连接代码通常来说是这样的:

		try {
			/* 如果使用的是JDK1.6,那么嵌入式方式是不需要载入驱动的 */
			Class.forName("org.apache.derby.jdbc.EmeddedDriver").newInstance();
		} catch (Exception e) {
			throw new SQLException("初始化数据库连接失败");
		}

		String url = "jdbc:derby:data;create=true";
		conn = DriverManager.getConnection(url, "username", "password");


可以先研究下Class.forName("org.apache.derby.jdbc.EmeddedDriver").newInstance();这句的初始化里都做了什么。

这个在第1部分中网络服务器方式的启动中也是有涉及的,在网络服务器方式下也载入了嵌入式的驱动,这里正好可以一并的来进行了解,

	/* 构造函数 */
	public EmbeddedDriver() {
		EmbeddedDriver.boot();
	}

	static void boot() {
		PrintStream ps = DriverManager.getLogStream();

		if (ps == null)
			ps = System.err;
		/* 交给JDBCBoot去继续执行 */
		new JDBCBoot().boot(Attribute.PROTOCOL, ps);
	}


下边就是JDBCBoot类的boot()方法了,

	public void boot(String protocol, PrintStream logging) {

		if (org.apache.derby.jdbc.InternalDriver.activeDriver() == null) {
			/* InternalDriver(JDBC)和授权服务 */
			addProperty("derby.service.jdbc", "org.apache.derby.jdbc.InternalDriver");
			/* AuthenticationService.MODULE = org.apache.derby.iapi.jdbc.AuthenticationService */
			addProperty("derby.service.authentication", AuthenticationService.MODULE);

			Monitor.startMonitor(bootProperties, logging);

			/* 启动网络模块 */
			if (Boolean.valueOf(PropertyUtil.getSystemProperty(Property.START_DRDA)).booleanValue()) {
				try {
					/* NETWORK_SERVER_AUTOSTART_CLASS_NAME = org.apache.derby.iapi.jdbc.DRDAServerStarter */
					Monitor.startSystemModule(NETWORK_SERVER_AUTOSTART_CLASS_NAME);
				} catch (StandardException se) {
					Monitor.logTextMessage(MessageId.CONN_NETWORK_SERVER_START_EXCEPTION, se.getMessage());
				}
			}
		}
	}


这里就涉及到了Monitor的启动了,

	public class Monitor {

	......

		public static void startMonitor(Properties bootProperties, PrintStream logging) {
			new org.apache.derby.impl.services.monitor.FileMonitor(bootProperties, logging);
		}

	......

	}

	public final class FileMonitor extends BaseMonitor implements java.security.PrivilegedExceptionAction {

	......

		public FileMonitor(java.util.Properties properties, java.io.PrintStream log) {
			runWithState(properties, log);
		}

	......

	}


这里初始化了一个FileMonitor的实例,而在FileMonitor的构造函数里会调用它的父类BaseMonitor中的runWithState()方法,这里就要正式进入重点了。
顺带说下,这个方法我用eclipse是调试不过去了,会报出各种各样的无解错误,有些地方我也不清楚是到底实现什么的。

	protected final void runWithState(Properties properties, PrintStream log) {
		/*
		 * 这里properties有两个属性: 
		 * "derby.service.jdbc", "org.apache.derby.jdbc.InternalDriver"
		 * "derby.service.authentication", "org.apache.derby.iapi.jdbc.AuthenticationService"
		 */
		bootProperties = properties;
		logging = log;

		/*
		 * 这里会读取org/apache/derby/info/DBMS.properties这个配置文件,Derby源代码里没有,可以下一个binary版的看一下
		 * ,就是一些数据库的版本之类的信息
		 * 然后会初始化derby.system.home属性
		 */
		if (!initialize(false))
			return;

		if (!Monitor.setMonitor(this))
			return;

		Object msgService = MessageService.setFinder(this);

		/* 新开一个后台线程引用这个FileMonitor,还有一个Monitor实例和msgService实例,防止GC */
		Object[] keepItems = new Object[3];
		keepItems[0] = this;
		keepItems[1] = new Monitor();
		keepItems[2] = msgService;
		dontGC = new AntiGC(keepItems);

		final Thread dontGCthread = getDaemonThread(dontGC, "antiGC", true);
		try {
			AccessController.doPrivileged(new PrivilegedAction() {
				public Object run() {
					dontGCthread.setContextClassLoader(null);
					return null;
				}
			});
		} catch (SecurityException se1) {
		}
		/* 开启后台线程 */
		dontGCthread.start();

		if (SanityManager.DEBUG) {
			reportOn = Boolean.valueOf(PropertyUtil.getSystemProperty("derby.monitor.verbose")).booleanValue();
		}

		/* 这里要读取derby.system.home目录下的derby.properties文件,这个可以进一步控制Derby数据库引擎的操作 */
		applicationProperties = readApplicationProperties();

		/* 获得系统属性 */
		Properties systemProperties = null;

		if (SanityManager.DEBUG) {
			try {
				systemProperties = System.getProperties();
			} catch (SecurityException se) {
			}
		}

		/* 返回属性中定义的实现类,对于bootProperties中的两个属性,此处返回null */
		Vector bootImplementations = getImplementations(bootProperties, false);

		Vector systemImplementations = null;
		Vector applicationImplementations = null;

		if (true || SanityManager.DEBUG) {
			// Don't allow external code to override our implementations.
			systemImplementations = getImplementations(systemProperties, false);
			applicationImplementations = getImplementations(applicationProperties, false);
		}

		/* 这里要返回org/apache/derby/modules.properties中默认的module实现 */
		/* 可以看看这个文件,基本的模块对应的实现都是在这个文件中定义的 */
		Vector defaultImplementations = getDefaultImplementations();

		int implementationCount = 0;
		if (bootImplementations != null)
			implementationCount++;

		if (true || SanityManager.DEBUG) {
			if (systemImplementations != null)
				implementationCount++;
			if (applicationImplementations != null)
				implementationCount++;
		}

		if (defaultImplementations != null)
			implementationCount++;
		/* Vector数组,这个implementationSets变量很重要,载入模块对应的实现的时候会在这个Vector数组中找 */
		implementationSets = new Vector[implementationCount];

		/* 把前面找到的所有模块实现都放进implementationSets中 */
		implementationCount = 0;
		if (bootImplementations != null)
			implementationSets[implementationCount++] = bootImplementations;

		if (true || SanityManager.DEBUG) {
			if (systemImplementations != null)
				implementationSets[implementationCount++] = systemImplementations;
			if (applicationImplementations != null)
				implementationSets[implementationCount++] = applicationImplementations;
		}

		if (defaultImplementations != null)
			implementationSets[implementationCount++] = defaultImplementations;

		if (SanityManager.DEBUG) {
			if (applicationProperties != null) {
				addDebugFlags(applicationProperties.getProperty(Monitor.DEBUG_FALSE), false);
				addDebugFlags(applicationProperties.getProperty(Monitor.DEBUG_TRUE), true);
			}

			addDebugFlags(PropertyUtil.getSystemProperty(Monitor.DEBUG_FALSE), false);
			addDebugFlags(PropertyUtil.getSystemProperty(Monitor.DEBUG_TRUE), true);
		}

		try {
			/* 这里要启动几个总是要启动的module */
			systemStreams = (InfoStreams) Monitor
					.startSystemModule("org.apache.derby.iapi.services.stream.InfoStreams");

			if (SanityManager.DEBUG) {
				SanityManager.SET_DEBUG_STREAM(systemStreams.stream().getPrintWriter());
			}

			contextService = new ContextService();

			uuidFactory = (UUIDFactory) Monitor.startSystemModule("org.apache.derby.iapi.services.uuid.UUIDFactory");

			timerFactory = (TimerFactory) Monitor
					.startSystemModule("org.apache.derby.iapi.services.timer.TimerFactory");

			Monitor.startSystemModule(Module.JMX);

		} catch (StandardException se) {
			reportException(se);
			dumpTempWriter(true);
			return;
		}

		dumpTempWriter(false);

		if (SanityManager.DEBUG && reportOn) {
			dumpProperties("-- Boot Properties --", bootProperties);
			dumpProperties("-- System Properties --", systemProperties);
			dumpProperties("-- Application Properties --", applicationProperties);
		}

		determineSupportedServiceProviders();

		boolean bootAll = Boolean.valueOf(PropertyUtil.getSystemProperty(Property.BOOT_ALL)).booleanValue();

		/* 开启"derby.service."开头的服务,这个也要仔细看一下 */
		startServices(bootProperties, bootAll);
		startServices(systemProperties, bootAll);
		startServices(applicationProperties, bootAll);

		if (bootAll)
			bootPersistentServices();
	}


这个方法的前半部分主要是找各个module的实现类,然后放到implementationSets这个变量中,后半部分就是module的启动了,有两个方法要重点的关注下,一个是#getImplementations(),一个是#startServices()。

首先来看getImplementations()方法,

	private Vector getImplementations(Properties moduleList, boolean actualModuleList) {
		if (moduleList == null)
			return null;

		Vector implementations = actualModuleList ? new Vector(moduleList.size()) : new Vector(0, 1);

		/* 获得当前的JDK版本信息 */
		int theJDKId = JVMInfo.JDK_ID;
		/* 如果某个module需要最低的JDK版本,记录每个JDK版本的module数量 */
		int[] envModuleCount = new int[theJDKId + 1];

		/* 循环处理传进来的Properties中包括的模块 */
		nextModule: for (Enumeration e = moduleList.propertyNames(); e.hasMoreElements();) {
			/* 键值 */
			String key = (String) e.nextElement();
			/* module名 */
			String tag;

			// derby.module.<modulename>=<class name>
			// derby.subSubProtocol.<modulename>=<classname>
			/* 判断键值是不是以"derby.module."或者"derby.subSubProtocol."开头,如果都不是放弃这次循环 */
			if (key.startsWith(Property.MODULE_PREFIX)) {
				tag = key.substring(Property.MODULE_PREFIX.length());
			} else if (key.startsWith(Property.SUB_SUB_PROTOCOL_PREFIX)) {
				tag = key.substring(Property.MODULE_PREFIX.length());
			} else {
				continue nextModule;
			}

			/* 判断是否还同时存在名字为"derby.env.jdk."+<module name>的属性 */
			/* 这个属性应该是启动这个服务所需要的最低JDK版本 */
			String envKey = Property.MODULE_ENV_JDK_PREFIX.concat(tag);
			String envJDK = moduleList.getProperty(envKey);
			int envJDKId = 0;

			/* 这里会根据版本来确定是否继续启动 */
			if (envJDK != null) {
				envJDKId = Integer.parseInt(envJDK.trim());
				if (envJDKId > theJDKId) {
					continue nextModule;
				}
			}

			/* 判断是否还同时存在名字为"derby.env.classes."+<module name>的属性 */
			/* 这个属性应该是启动这个服务所需要的其他类信息 */
			envKey = Property.MODULE_ENV_CLASSES_PREFIX.concat(tag);
			String envClasses = moduleList.getProperty(envKey);
			if (envClasses != null) {

				StringTokenizer st = new StringTokenizer(envClasses, ",");
				for (; st.hasMoreTokens();) {
					try {
						/* 这里会尝试找这个类或者接口 */
						Class.forName(st.nextToken().trim());
					} catch (ClassNotFoundException cnfe) {
						continue nextModule;
					} catch (LinkageError le) {
						continue nextModule;
					}
				}
			}

			/* 获得module的类名 */
			String className = moduleList.getProperty(key);

			if (SanityManager.DEBUG && reportOn) {
				report("Accessing module " + className + " to run initializers at boot time");
			}

			try {
				/* 尝试载入这个类 */
				Class possibleModule = Class.forName(className);

				/* 判断是否是某些特殊的module:PersistentService和StorageFactory */
				if (getPersistentServiceImplementation(possibleModule))
					continue;

				if (StorageFactory.class.isAssignableFrom(possibleModule)) {
					storageFactories.put(tag, className);
					continue;
				}

				if (envJDKId != 0) {
					/* 这里在Vector中会把需要JDK版本高的模块排在前面 */
					/* 后面在载入模块实现的时候会有用处,比如保证JDK6在启动JDBC服务时会找到JDBC4的实现而不是JDBC3 */
					int offset = 0;
					for (int eji = theJDKId; eji > envJDKId; eji--) {
						offset += envModuleCount[eji];
					}
					/* 插入Vector中 */
					implementations.insertElementAt(possibleModule, offset);
					envModuleCount[envJDKId]++;

				} else {
					/* 插入Vector中 */
					implementations.addElement(possibleModule);
				}

				if (SanityManager.DEBUG) {// DEBUG的先不去关心
					Class[] csParams = { new java.util.Properties().getClass() };
					try {
						possibleModule.getMethod("canSupport", csParams);
						if (!ModuleSupportable.class.isAssignableFrom(possibleModule)) {
							SanityManager
									.THROWASSERT("Module does not implement ModuleSupportable but has canSupport() - "
											+ className);
						}
					} catch (NoSuchMethodException nsme) {/* ok */
					}

					// ModuleControl
					boolean eitherMethod = false;

					Class[] bootParams = { Boolean.TYPE, new java.util.Properties().getClass() };
					try {
						possibleModule.getMethod("boot", bootParams);
						eitherMethod = true;
					} catch (NoSuchMethodException nsme) {/* ok */
					}

					Class[] stopParams = {};
					try {
						possibleModule.getMethod("stop", stopParams);
						eitherMethod = true;
					} catch (NoSuchMethodException nsme) {/* ok */
					}

					if (eitherMethod) {
						if (!ModuleControl.class.isAssignableFrom(possibleModule)) {
							SanityManager.THROWASSERT("Module does not implement ModuleControl but has its methods - "
									+ className);
						}
					}
				}

			} catch (ClassNotFoundException cnfe) {
				report("Class " + className + " " + cnfe.toString() + ", module ignored.");
			} catch (LinkageError le) {
				report("Class " + className + " " + le.toString() + ", module ignored.");
			}
		}

		if (implementations.isEmpty())
			return null;
		implementations.trimToSize();

		return implementations;
	}


通过这个方法,就找到了属性中定义的module实现,为了对属性的内容有个直观的了解,可以看一下modules.properties中的内容。
分享到:
评论

相关推荐

    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.zip" 是Apache Derby的10.11.1.1版本的源代码包,对于开发者来说,这是一个宝贵的资源,可以深入了解Derby的内部工作原理和实现细节。 Apache Derby的核心特性包括: 1. **完全用Java编写...

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

    ### 源代码检查工具SONAR使用经验 #### Sonar概述 Sonar作为一个代码质量管理的开放平台,通过灵活的插件机制集成了多种测试工具、代码分析工具以及持续集成工具。与传统持续集成工具(如Hudson/Jenkins)相比,...

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

    源代码的提供意味着用户可以查看、学习甚至修改系统的内部实现,以适应特定需求或进行二次开发。 Swing是Java的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分,用于构建桌面应用。...

    derby+myBatis 入门

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

    使用 Java DB (Derby) 数据库

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

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

    用户可以直接运行这个文件启动聊天软件,而无需查看或修改源代码。"src"目录包含了项目的源代码,开发者可以研究这些代码来学习Swing和Derby的结合使用,了解如何创建GUI、处理用户输入、连接数据库以及执行数据库...

    myeclipse入门教程

    - **编辑器(Editor)**:用于编写和编辑源代码。 - **常见概念和操作**: - **项目(Project)**:一组相关文件的集合。 - **工作区(Workspace)**:存放项目的文件夹。 - **导入、导出Java项目**:便于项目...

    MyEclipse6Java开发中文教程

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

    MyEclipse 6 Java EE 开发中文手册.pdf

    - **手工和自动编译**:手动或自动编译 Java 源代码。 - **直接粘贴 Java 源码为类文件**:直接粘贴代码生成文件。 - **复制项目中的文件**:复制文件到其他位置。 - **断点和调试器**:设置断点进行调试。 - **快速...

    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