zddava 发表于 2013-1-30 02:17:35

Derby源代码分析 -

谈起JDBC的实现,还是从获取Connection开始吧。

下面这句就是一般的获取Connection的代码了,

DriverManager.getConnection(url, "username", "password");

当每个Driver初始化的时候,都会在DriverManager中注册下自己,就是调用这个registerDriver(java.sql.Driver driver)静态方法,然后当想获得Connnection的时候DriverManager就可以通过注册的驱动来从特定的数据库获得了。如果有兴趣可以看一下JDK中DriverManager的#getConnection()的实现,这里就不再列出代码了。而这里需要说明的是在#gertConnection()方法中会调用到先前注册的Driver的#connect(String url, Properties info)方法,其中info里保存了用户名和密码。下面就从这里开始分析吧。

1. 网络服务器方式

网络服务器方式对应的Driver是org.apache.derby.jdbc.ClientDriver,它的#connect()方法如下所示:


public java.sql.Connection connect(String url, java.util.Properties properties) throws java.sql.SQLException {org.apache.derby.client.net.NetConnection conn;try {if (exceptionsOnLoadDriver__ != null) {throw exceptionsOnLoadDriver__;}if (properties == null) {properties = new java.util.Properties();}/* URL的格式类似于jdbc:derby://127.0.0.1:1527/database;create=true这种 *//* URL格式分析 */java.util.StringTokenizer urlTokenizer = new java.util.StringTokenizer(url, "/:= \t\n\r\f", true);int protocol = tokenizeProtocol(url, urlTokenizer);if (protocol == 0) {// 错误的URL前缀return null;}String slashOrNull = null;if (protocol == DERBY_REMOTE_PROTOCOL) {// 如果是网络方式的URLtry {slashOrNull = urlTokenizer.nextToken(":/");} catch (java.util.NoSuchElementException e) {throw new SqlException(null, new ClientMessageId(SQLState.MALFORMED_URL), url, e);}}/* 地址 */String server = tokenizeServerName(urlTokenizer, url); // "/server"/* 端口 */int port = tokenizeOptionalPortNumber(urlTokenizer, url); // "[:port]/"if (port == 0) {// port没有的话就设为默认的1527port = ClientDataSource.propertyDefault_portNumber;}/* 数据库名 */String database = tokenizeDatabase(urlTokenizer, url); // "database"/* 这里还要加上一些URL中的参数进去,比如create=true这种 */java.util.Properties augmentedProperties = tokenizeURLProperties(url, properties);database = appendDatabaseAttributes(database, augmentedProperties);int traceLevel;try {traceLevel = ClientDataSource.getTraceLevel(augmentedProperties);} catch (java.lang.NumberFormatException e) {throw new SqlException(null, new ClientMessageId(SQLState.TRACELEVEL_FORMAT_INVALID), e);}org.apache.derby.client.am.LogWriter dncLogWriter = ClientDataSource.computeDncLogWriterForNewConnection(java.sql.DriverManager.getLogWriter(), ClientDataSource.getTraceDirectory(augmentedProperties),ClientDataSource.getTraceFile(augmentedProperties), ClientDataSource.getTraceFileAppend(augmentedProperties), traceLevel, "_driver", traceFileSuffixIndex_++);/* 这步是获得连接的过程,下面要重点看一下 */conn = (org.apache.derby.client.net.NetConnection) getFactory().newNetConnection((org.apache.derby.client.net.NetLogWriter) dncLogWriter, java.sql.DriverManager.getLoginTimeout(),server, port, database, augmentedProperties);} catch (SqlException se) {throw se.getSQLException();}if (conn.isConnectionNull())return null;return conn;}


这里的#getFactory()方法就是首先要关注的地方之一,

public static ClientJDBCObjectFactory getFactory() {if (factoryObject != null)return factoryObject;if (Configuration.supportsJDBC40()) {// 由于我的JDK是1.6的,只关注JDBC4.0的部分factoryObject = createJDBC40FactoryImpl();} else {factoryObject = createDefaultFactoryImpl();}return factoryObject;}private static ClientJDBCObjectFactory createJDBC40FactoryImpl() {final String factoryName = "org.apache.derby.client.net.ClientJDBCObjectFactoryImpl40";try {return (ClientJDBCObjectFactory) Class.forName(factoryName).newInstance();} catch (ClassNotFoundException cnfe) {return createDefaultFactoryImpl();} catch (InstantiationException ie) {return createDefaultFactoryImpl();} catch (IllegalAccessException iae) {return createDefaultFactoryImpl();}}

通过这里获得了一个org.apache.derby.client.net.ClientJDBCObjectFactoryImpl40的实例,它就是用来最后获取Connection实例的,回到之前的#connect()方法,这里调用了ClientJDBCObjectFactory的#newNetConnection()去获得Connection实例,


public org.apache.derby.client.am.Connection newNetConnection(org.apache.derby.client.am.LogWriter netLogWriter,String user, String password, org.apache.derby.jdbc.ClientBaseDataSource dataSource, int rmId,boolean isXAConn) throws SqlException {return (org.apache.derby.client.am.Connection) (new NetConnection40((NetLogWriter) netLogWriter, user,password, dataSource, rmId, isXAConn));}


这里可以看出,其实是实例化了一个NetConnection40的实例返回给调用端,也就是说以后进一步的讨论都可以从NetConnection40开始了。


2. 嵌入式方式

下面就要看看嵌入式方式了,JDBC4.0的嵌入式Driver是Driver40这个类,不过这个类并没有重写#connect()方法,可以沿着继承树向上,在它的父类InternalDriver中看到这个方法


public Connection connect(String url, Properties info) throws SQLException {if (!acceptsURL(url)) {return null;}/* 如果内存过低,那么不要尝试获取连接,直接抛出异常 */if (EmbedConnection.memoryState.isLowMemory()) {throw EmbedConnection.NO_MEM;}/* 是否要提供一个默认链接,URL是"jdbc:default:connection" */boolean current = url.equals(Attribute.SQLJ_NESTED);if (current) {ConnectionContext connContext = getConnectionContext();if (connContext != null) {return connContext.getNestedConnection(false);}return null;}FormatableProperties finfo = null;try {/* 获得URL中的属性,还包括了用户名和密码 */finfo = getAttributes(url, info);info = null; // ensure we don't use this reference directly again./* 如果参数中包括了"shutdown",那么是要通知服务器关闭的 */boolean shutdown = Boolean.valueOf(finfo.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue();if (shutdown) {// 关闭操作if (InternalDriver.getDatabaseName(url, finfo).length() == 0) {if (this.getAuthenticationService() == null)throw Util.generateCsSQLException(SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_NO_SERVICE_FOR_SYSTEM));if (!this.getAuthenticationService().authenticate((String) null, finfo)) {throw Util.generateCsSQLException(SQLState.NET_CONNECT_AUTH_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID));}Monitor.getMonitor().shutdown();throw Util.generateCsSQLException(SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN);}}/* 获得嵌入式方式的连接 */EmbedConnection conn = getNewEmbedConnection(url, finfo);if (conn.isClosed()) {return null;}return conn;} catch (OutOfMemoryError noMemory) {// 这个好像不能捕捉到吧??EmbedConnection.memoryState.setLowMemory();throw EmbedConnection.NO_MEM;} finally {if (finfo != null)finfo.clearDefaults();}}

这段代码还是很好理解的,后边的#getNewEmbedConnection()方法各个不同JDBC版本的Driver就不尽相同了,我们来看一下JDBC4.0的好了,就是在Driver4里定义的那个,

protected EmbedConnection getNewEmbedConnection(String url, Properties info) throws SQLException {return new EmbedConnection40(this, url, info);}

非常简单,返回了一个EmbedConnection40作为Connection的实现。

至此,网络服务器方式和嵌入式方式的连接获取就都分析完了,对于JDBC4.0,分别是NetConnection40和EmbedConnection40类。
页: [1]
查看完整版本: Derby源代码分析 -