写点什么

druid 源码学习六

作者:Nick
  • 2022 年 5 月 17 日
  • 本文字数:3165 字

    阅读完需:约 10 分钟

druid源码学习六

一、registerMbean 探索


上一篇我们提到 AccessController,该类用于访问控制操作和决策的。

若 mbeanRegistered 为 false 则 mbean 的注册,如下段代码。执行 run 方法,最为核心的一句:

ObjectName objectName = DruidDataSourceStatManager.

addDataSource(DruidDataSource.this,DruidDataSource.this.name);

可见,ObjectName 为 javax.management 下一个类。jdk 解释如下:


ObjectName 表示 MBean 的对象名称,或可匹配多个 MBean 名称的模式。 这个类的实例是不可变的。

这个类的一个实例可以用来表示:

<li>对象名称</li>

<li>在查询的上下文中的对象名称模式 </li>

if (!mbeanRegistered) {            AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override public Object run() { ObjectName objectName = DruidDataSourceStatManager.addDataSource(DruidDataSource.this, DruidDataSource.this.name);
DruidDataSource.this.setObjectName(objectName); DruidDataSource.this.mbeanRegistered = true;
return null; } }); }
复制代码

DruidDataSourceStatManager 定义了一个 addDataSource 的静态方法.



public synchronized static ObjectName addDataSource(Object dataSource, String name) { final Map<Object, ObjectName> instances = getInstances();
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); synchronized (instances) { if (instances.size() == 0) { try { ObjectName objectName = new ObjectName(MBEAN_NAME); if (!mbeanServer.isRegistered(objectName)) { mbeanServer.registerMBean(instance, objectName); } } catch (JMException ex) { LOG.error("register mbean error", ex); }
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 ex) { LOG.error("register mbean error", ex); 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 ex) { LOG.error("register mbean error", ex); objectName = null; } }
instances.put(dataSource, objectName); return objectName; }
复制代码

二、Collections.synchronizedMap

进入 getInstances()方法,该方法使用了一个临时变量 tmp 用于获取 dataSource.另外还使用了 Collections.synchronizedMap(new IdentityHashMap<Object, ObjectName>()).关于 Collections.synchronizedMap,看了下 jdk 的翻译,几乎看不懂。


返回由指定地图支持的同步(线程安全)映射。 为了保证串行访问,重要的是通过返回的映射完成对后台映射的所有访问。在迭代其任何集合视图时,用户必须在返回的映射上手动同步。


通过网上搜索这段代码其实就是用来获取一个线程安全的 IdentityHashMap 集合。


再看 IdentityHashMap,jdk 对 IdentityHashMap 的解释


此类实现 Map 接口利用哈希表,比较键(和值)时使用引用相等代替对象相等的。 换句话说,在 IdentityHashMap 中 ,当且仅当(k1==k2)时,两个键 k1 和 k2 被认为是相等的。 (正常 Map 实现(如 HashMap )当两个键 k1 和 k2 被认为是相等的当且仅当(k1==null ? k2==null : k1.equals(k2))。 )这个类不是通用的 Map 实现! 虽然这个类实现了 Map 接口,但是它有意违反了 Map's 通用合同,当对比比较时,它要求使用 equals 方法。 该类仅在需要引用相等语义的罕见情况下才能使用。


这段翻译确实也做到了让人无法理解。


再看下网友的解释


IdentityHashMap 实现了 Map 接口,用法与 HashMap 差不多,都是用 Hash 表实现数据的存储,比较 key 的值是否相等,如果相等就替换原有的值。但是和 hashmap 最大的区别就是 IdentityHash 在比较 key 的时候使用的是”==“,也就是比较的是地址,而普通的 hashmap 在比较 key 的时候使用的是 equals,如下方法:k1==null ? k2==null : k1.equals(k2)


是不是清晰多了,简言之 IdentityHashMap 基本上和我们常用的 HashMap 差不多,区别就是 key 值比较的时候 IdentityHashMap 用"=="比较的是地址,另一个用"equals"。所以,当我要求定义 key 值需比较地址的时候可以使用 IdentityHashMap,按 jdk 作者的意思这个类使用的并不多。


    public static Map<Object, ObjectName> getInstances() {        Map<Object, ObjectName> tmp = dataSources;        if (tmp == null) {            staticLock.lock();            try {                if (isRegisterToSystemProperty()) {                    dataSources = getInstances0();                } else {                    tmp = dataSources;                    if (null == tmp) {                        dataSources = tmp = Collections.synchronizedMap(new IdentityHashMap<Object, ObjectName>());                    }                }            } finally {                staticLock.unlock();            }        }
return dataSources; }
复制代码

三、JMX 是什么?

接下来注意到 这段代码:

MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

进入 MBeanServer 类,同样我们先看看 jdk 的解释:


这是代理方面的 MBean 操作界面。它包含创建,注册和删除 MBean 所需的方法以及注册的 MBean 的访问方法。这是 JMX 基础架构的核心组件。用户代码通常不会实现此接口。相反,使用 MBeanServerFactory 类中的一种方法获取实现此接口的对象。添加到 MBean 服务器中的每个 MBean 变得可管理:通过连接到该 MBean 服务器的连接器/适配器,其属性和操作可以远程访问。 除非是符合 JMX 的 MBean,否则无法在 MBean 服务器中注册 Java 对象。


这里提到该类是 JMX 基础架构的核心组件。了解到,JMX 是 Java Management Extensions,它是一个 Java 平台的管理和监控接口。为什么要搞 JMX 呢?因为在所有的应用程序中,对运行中的程序进行监控都是非常重要的,Java 应用程序也不例外。我们肯定希望知道 Java 应用程序当前的状态,例如,占用了多少内存,分配了多少内存,当前有多少活动线程,有多少休眠线程等等。如何获取这些信息呢?为了标准化管理和监控,Java 平台使用 JMX 作为管理和监控的标准接口,任何程序,只要按 JMX 规范访问这个接口,就可以获取所有管理与监控信息。

实际上,常用的运维监控如 Zabbix、Nagios 等工具对 JVM 本身的监控都是通过 JMX 获取的信息。

四、总结

这篇,我们通过对 registerMbean 方法的探索,学习了 Collections.synchronizedMap、IdentityHashMap 的使用,紧接着,我们通过 MBeanServer 类了解到 JDK 的一个扩展基础架构 JMX。


发布于: 49 分钟前阅读数: 4
用户头像

Nick

关注

终身学习,向死而生 2020.03.18 加入

得到、极客时间重度学习者,来infoQ 是为了输出倒逼输入

评论

发布
暂无评论
druid源码学习六_jdk_Nick_InfoQ写作社区