druid 源码解析 (9)

基于昨天的demo,我们这里再进行进一步的一些探索: 首先我们再编写两个测试类,以完成动态数据源抽取的部分功能:

public void init() {
    try {
        DruidDataSource druidDataSource = DataSourceToolsUtils.getDataSource("dynamic", "com.mysql.jdbc.Driver",
                "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC", "root", "root");
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

public Map<String,Object>  getDataSourceStat(String name) {

    return DataSourceToolsUtils.getDataSourceStat(name);

}
复制代码

上面的方法初始化连接池,下面的方法用于根据刚刚初始化的连接池名称拿到连接池具体信息, 执行的结果如下:

屏幕快照 2021-11-19 下午9.02.38.png

然后我们就可以根据取到的连接池去做业务了。 由我们刚刚的代码可以得知;DruidDataSourceStatManager就是druid用于管理已经初始化连接池的方法.

public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBean {
    private static final Lock staticLock = new ReentrantLock();
    public static final String SYS_PROP_INSTANCES = "druid.dataSources";
    public static final String SYS_PROP_REGISTER_SYS_PROPERTY = "druid.registerToSysProperty";
    private static final Log LOG = LogFactory.getLog(DruidDataSourceStatManager.class);
    private static final DruidDataSourceStatManager instance = new DruidDataSourceStatManager();
    private final AtomicLong resetCount = new AtomicLong();
    private static volatile Map dataSources;
    private static final String MBEAN_NAME = "com.alibaba.druid:type=DruidDataSourceStat";
    private static CompositeType COMPOSITE_TYPE = null;
复制代码

在DruidDataSourceStatManager里面我们可以看到 private static volatile Map dataSources; 这个map就是 statManager用来在缓存中保存dataSources的信息的 map, 我们在 getInstance方法中打上断点来看执行的情况: 首先初始化一个名字叫dyamic1的连接池,这里可以看到tmp获得的结果是空的,判断逻辑上可重入锁,然后去系统配置中查看有没有初始化已经完成的连接池,如果没有就把tmp和datasources都赋值。

屏幕快照 2021-11-19 下午9.28.35.png 然后我们再创建一个一个名字叫dyamic3的连接池

屏幕快照 2021-11-19 下午9.40.13.png 然后我们可以看到这里调用了addDataSources方法添加了一个实例。

这些添加实例,初始化整个连接池 信息map类,都是线程安全的。

这里的代码有很多可以借鉴的地方。

public static synchronized ObjectName addDataSource(Object dataSource, String name) {
    Map<Object, ObjectName> instances = getInstances();
    MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
    synchronized(instances) {
        if (instances.size() == 0) {
            try {
                ObjectName objectName = new ObjectName("com.alibaba.druid:type=DruidDataSourceStat");
                if (!mbeanServer.isRegistered(objectName)) {
                    mbeanServer.registerMBean(instance, objectName);
                }
            } catch (JMException var9) {
                LOG.error("register mbean error", var9);
            }

            DruidStatService.registerMBean();
        }
    }

    ObjectName objectName = null;
    if (name != null) {
        try {
            objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + name);
            mbeanServer.registerMBean(dataSource, objectName);
        } catch (Throwable var8) {
            LOG.error("register mbean error", var8);
            objectName = null;
        }
    }

    if (objectName == null) {
        try {
            int id = System.identityHashCode(dataSource);
            objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + id);
            mbeanServer.registerMBean(dataSource, objectName);
        } catch (Throwable var7) {
            LOG.error("register mbean error", var7);
            objectName = null;
        }
    }

    instances.put(dataSource, objectName);
    return objectName;
}
复制代码

这里看到之前不理解的方法就可以理解了,通过初始化时候传入的名称在stat管理map中添加实例,如果没有传入名称生成一个id来标示这个连接池资源,同时druid可以提供多个相互隔离的连接池资源,这样大大加强了druid的能力。

猜你喜欢

转载自juejin.im/post/7032276735018139685