注册 | 登录 忘记密码? 51cto首页 | 博客 | 论坛 | 招聘
热点文章 IB客座主编(四)美国西蒙公..
 帮助

JDBC数据库连接池的实现:第一天:数据源配置解析工具


2008-03-20 18:24:58
版权声明:原创作品,如需转载,请与作者联系。否则将追究法律责任。
JDBC数据库连接池的实现:第一天:数据源配置解析工具
 
 
开源的连接池很多,实现都不错,可是就不知道怎么做的,在研读了javax.sql包中的API规范后,想手动实现一个通用的JDBC数据库连接池。这个工作量比较大,主要目的是为了深入底层学习Java处理数据库的技术。
 
第一天:数据源配置解析工具
 
这个解析工具支持xml配置和properties配置,程序不依赖任何jdk以外的任何第三方包。
 
xml和properties文件的格式对名字有限制,xml还对格式有限制,要求符合sun公司的http://java.sun.com/dtd/properties.dtd规范。
 
解析工具要完成的功能,读取配置文件,并存放到Map中,对于非必须而没有配置的属性,给以默认的属性值。
 
要求:两种配置文件读取方法通用,不进行切换。有导出配置文件的功能。
 
实现代码:
package com.blog51cto.lavasoft.ds;

import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.io.InputStream;

/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2008-3-19 23:22:38
* Company: LavaSoft(http://lavasoft.blog.51cto.com)
* 数据源配置工具
*/

public class DataSourceConfig {
    private static Map<String, String> defcfgmap;

    //初始化默认配置参数
    static {
        defcfgmap = new HashMap<String, String>();
        defcfgmap.put("driverClassName", "");
        defcfgmap.put("url", "");
        defcfgmap.put("user", "");
        defcfgmap.put("password", "");
        defcfgmap.put("type", "javax.sql.DataSource");
        defcfgmap.put("initCreate", "12");
        defcfgmap.put("maxIdle", "8");
        defcfgmap.put("maxWait", "10");
        defcfgmap.put("maxActive", "5");
        defcfgmap.put("validationQuery", "");
    }

    /**
     * 获取数据源配置信息,本方法接受两种配置文件类型,xml和properties类型.
     *
     * @param cfgFilePath 配置文件的名
     * @return 配置参数Map
     * @throws Exception
     */

    public static Map<String, String> getConfigParameter(String cfgFilePath) throws Exception {
        Map<String, String> mcfg = new HashMap<String, String>();
        Pattern pp = Pattern.compile(".+properties");
        Pattern px = Pattern.compile(".+xml");
        Matcher mp = pp.matcher(cfgFilePath);
        Matcher mx = px.matcher(cfgFilePath);
        InputStream in = DataSourceConfig.class.getResourceAsStream(cfgFilePath);
        Properties prop = new Properties();
        if (mp.matches()) {
            prop.load(in);
            Enumeration<String> enu = (Enumeration<String>) prop.propertyNames();
            while (enu.hasMoreElements()) {
                String key = enu.nextElement();
                String value = prop.getProperty(key);
                mcfg.put(key, value);
            }
            in.close();
        } else if (mx.matches()) {
            prop.loadFromXML(in);
            Enumeration<String> enu = (Enumeration<String>) prop.propertyNames();
            while (enu.hasMoreElements()) {
                String key = enu.nextElement();
                String value = prop.getProperty(key);
                mcfg.put(key, value);
            }
            in.close();
        } else {
            throw new Exception("数据源配置文件必须为xml或者properties文件,请检查配置!");
        }
        //检查没有配置的属性,并通过默认的属性值进行设置
        Set<Map.Entry<String, String>> def = defcfgmap.entrySet();
        for (Map.Entry<String, String> d : def) {
            if (!mcfg.containsKey(d.getKey())) {
                mcfg.put(d.getKey(), d.getValue());
            }
        }
        return mcfg;
    }

    /**
     * 获取默认的数据源配置信息
     *
     * @return
     */

    private static String getDefaultConfig() {
        return getConfig(defcfgmap);
    }

    /**
     * 返回数据源配置信息的文本表述
     *
     * @param map 配置信息Map
     * @return 数据源配置信息的文本表述
     */


    private static String getConfig(Map<String, String> map) {
        StringBuffer sb = new StringBuffer("数据源配置参数:\n");
        for (Map.Entry<String, String> ent : map.entrySet()) {
            sb.append(ent.getKey()).append("=").append(ent.getValue()).append("\n");
        }
        return sb.toString();
    }

    /**
     * 测试配置参数获取工具
     *
     * @param args
     * @throws Exception
     */

    public static void main(String args[]) throws Exception {
        Map<String, String> mcfg = getConfigParameter("dscfg.xml");
        String cfg = getConfig(mcfg);
        System.out.println(cfg);
    }
}
 
 
配置文件
dscfg.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mysql
user=root
password=leizhimin
 
dscfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>JDBC数据库连接池实现</comment>
<entry key="user">root</entry>
<entry key="password">leizhimin</entry>
<entry key="url">jdbc:mysql://127.0.0.1:3306/mysql</entry>
<entry key="driverClassName">com.mysql.jdbc.Driver</entry>
</properties>
 
 
现有的方法都测试过了,还没有写导出配置的方法,接下来我会补上。

本文出自 “熔 岩” 博客,转载请与作者联系!





    文章评论
 
2008-04-10 22:35:47
我有个建议:
数据库连接池,应该是作为高度可重用的组件而进行设计的。因此,对于组件的设计者,应该对组件所使用的环境依赖性降低到最小,这样组件才可能最广泛的被使用。
拿数据库连接池这个组件来说,为什么组件要依赖于一个XML或者Properties配置文件呢? 我们为什么要假定这个组件的使用者一定是使用XML或者Properties配置文件呢?
这样带来的直接影响就是,要想用我这个组件,你就得按我的要求,给我弄个配置文件。一个大工程会用很多组件,如果每个组件的设计者都把组件设计成有特定的依赖和假设,那么可想而知,整合在一起的工程会是什么样。简直是个灾难!
现在Java世界组件泛滥,实在是个灾难。

欢迎到我的博客交流。

2008-04-11 13:28:17
to kshark:
首先还是感谢一下你的热心留言.

连接池不是一个工具包,是要与用户的数据库环境相结合的,结合点就是配置信息,这个配置信息必须留给客户,因为开发人员不知道客户要用什么样的数据库,什么样的环境.

把配置暴露给客户,这样也最大限度的方便了使用.

完全可以讲这些配置信息设置为接口,让用户去实现接口,然后通过java编程来设置配置信息,但是这样做太麻烦.

实际中,不管是开源的还是商业的数据库连接池,都需要配置.并且都把配置留给了客户,只是配置的方式有所差别,比如有的是通过web 表单或GUI界面来配置,有的是直接配置.本质是一样的.

纵观现在的J2ee编程,struts/spring/hiberante都充满了配置文件,难道说这些组件不够优秀吗? 是否有配置文件和配置文件多寡不是一个衡量尺度.



2008-04-13 20:34:44
我还是建议你再仔细考虑一下这个问题,因为这个问题不是一个简单的问题。对组件设计的多年工程实践,使我意识到文件配置方式这种依赖关系,不是最佳软件设计实践,尽管在很多常见的组件中都用到,如你所说的Struts、Spring、Hibernate。
Struts、Spring、Hibernate是优秀的组件,但不是从哪个角度来评价,他们都是完美无缺的,都是绝对正确的。这要辩证的理解。
做大项目和做小项目,考虑的问题、采用的技术是完全不同的。因此,在做小项目使用的技术、采用的思路和方法、设计理念,直接拿到大项目中,就会有很多无法适用的地方。
还有一个重要的因素要考虑,那就是组件的替换。也就是说,我在我的项目中使用你的组件,我会封装后提供给上层调用,你的组件只是我的一个内部实现。将来有更好的组件,我会进行替换。这种替换,应该对开发团队其他成员、实施人员、维护人员都是不可见的。如果是文件配置方式,那么对实施人员、维护人员都是可见的,将来替换成新的组件,新的组件又使用了完全不同的配置方式,那么对开发团队其他成员是可见的、也要更新软件实施手册、维护手册,这已经不是透明替换了,增加了额外的工作。

2008-04-15 09:52:23
to kshark:数据源作为一个DataSource接口的实现,完全可以无缝替换为别的数据源。

现在回过头看看现有的各种数据源,有没有不用配置文件的?能否举例一二?

如果你有更好的实现,是否能给出一个模型图。

最近太忙太忙了,实现DataSouce接口的工作量很大,因此还搁置一边。。。希望能尽快补全。


 

发表评论

昵   称:
验证码:  点击图片可刷新验证码  博客过2级,无需填写验证码
内   容: