写在前面

本文来看先jmx相关内容。

1:jmx介绍

jvm在运行的过程中有很多的信息,比如堆内存,线程数,加载的类信息,CPU的使用量等,如果我们想要将这些信息暴漏让外界获取,该怎么做呢?此时就需要用到jmx技术了,jmx技术的全称时Java management extension,即,Java管理扩展。那么首先,Java作为面向对象的语言,自然要先将需要暴漏的信息以某种形式组织起来了,组织的形式也比较简单,就是定义bean,只不过因为其用于管理用途,所以叫做management bean,即MBean,看似神秘,其实比较纯粹,和普通的Java bean没有任何区别,也是封装了一组属性(如可能CPU使用率属性等)和操作(如可能执行gc的操作,以及自定义的其他方法等)。MBean不止一个,有很多很多,为了方便MBean的管理,Java定义MbeanServer来完成MBean的统一管理工作,但是此时还不能暴漏到外界,暴漏到外界还需要用到rmi连接器,之后诸如jconsole,jvisualvm等工具就可以通过rmi连接到jvm获取各种MBean,并从中读取信息来展示,供用户进行管理和查看工作了,架构图如下:

java xms xmx xmn java xms xmx xmn全称_System

2:自定义MBean

想要自定义MBean,我们首先需要创建接口,接口名称要以MBean结尾,如下:

public interface UserMBean {

    String getName();

    String getPassword();

    String getPhone();

    void say();
    void changeUrl(String url);
}

然后我们就可以定义一个实现类作为MBean,如下:

public class User implements UserMBean {
    private static String url = "https://zhuanlan.zhihu.com/p/166530442";

    @Override
    public String getName() {
        return "风筝";
    }

    @Override
    public String getPassword() {
        return "密码不可见";
    }

    @Override
    public String getPhone() {
        return "18900000000";
    }

    @Override
    public void say() {
        System.out.println("Hello JMX");
    }

    @Override
    public void changeUrl(String url) {
        System.out.println("url值修改前为:" + User.url);
        User.url = url;
        System.out.println("url值修改后为:" + User.url);
    }
}

定义完毕之后,还必须将MBean注册到MbeanServer中,以及设置rmi地址等,具体如下:

public class Main {
    public static void main(String[] args) throws Exception {
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        // ObjectName 是 MBean 的唯一标示,一个 MBeanServer 不能有重复。完整的格式「自定义命名空间:type=自定义类型,name=自定义名称」
        ObjectName userName = new ObjectName("FengZheng:type=customer,name=customerUserBean");
        // 注册MBean到mbeanserver中,并指定唯一名称
        server.registerMBean(new User(), userName);
        try {
            //这个步骤很重要,注册一个端口,绑定url后用于客户端通过rmi方式连接JMXConnectorServer
            LocateRegistry.createRegistry(8999);
            //URL路径的结尾可以随意指定,但如果需要用Jconsole来进行连接,则必须使用jmxrmi
            JMXServiceURL url = new JMXServiceURL
                    ("service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi");
            JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
            System.out.println("begin rmi start");
            jcs.start();
            System.out.println("rmi start");
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Thread.sleep(60 * 60 * 1000);
    }

}

这样运行之后,我们就可以通过jconsole工具中的mbean tab前看到我们自定义的MBean相关的属性信息,以及方法信息了,如下:

java xms xmx xmn java xms xmx xmn全称_开发语言_02

除了直接查看属性的值之外,还可以直接执行方法,如下执行say方法:

java xms xmx xmn java xms xmx xmn全称_System_03

执行changeUrl方法,可以录入参数,如下:

java xms xmx xmn java xms xmx xmn全称_开发语言_04

当然我们也可以通过rmi来连接到jmx,实现自己的jconsole,如下:

public class Client {
    public static void main(String[] args) throws IOException, Exception, NullPointerException {
        String jmxUrl = "service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi";
        monitor(jmxUrl);
    }

    public static void monitor(String url) throws Exception{
        JMXServiceURL jmxServiceURL = new JMXServiceURL
                (url);
        JMXConnector jmxc = JMXConnectorFactory.connect(jmxServiceURL, null);

        MBeanServerConnection msc = jmxc.getMBeanServerConnection();
        String[] domains = msc.getDomains();
        for (String domain : domains) {
            System.out.println(domain);
        }
    }
}

运行如下:

JMImplementation
java.util.logging
java.lang
com.sun.management
java.nio
FengZheng

3:jdk自带MBean

jdk自带的MBean在java.lang.management包下,如下:

java xms xmx xmn java xms xmx xmn全称_System_05

这些MBean都可以通过MBean的工厂类ManagementFactory获取,如下图:

java xms xmx xmn java xms xmx xmn全称_java xms xmx xmn_06

我们来看下其中的RuntimeMBean,如下:

public class JdkMBeanTest {
    public static void main(String[] args) {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        System.out.println("jvm名称:" + runtimeMXBean.getName());
        System.out.println("启动类加载器加载路径:" + runtimeMXBean.getBootClassPath());
        System.out.println("classpath: " + runtimeMXBean.getClassPath());
        System.out.println("启动时间(ms):" + runtimeMXBean.getStartTime());
        System.out.println("运行时长(ms):" + runtimeMXBean.getUptime());
        System.out.println("vm厂家:" + runtimeMXBean.getSpecVendor());
        System.out.println("vm版本:" + runtimeMXBean.getSpecVersion());
        System.out.println("系统属性:" + runtimeMXBean.getSystemProperties());

    }
}

运行如下:

java xms xmx xmn java xms xmx xmn全称_jvm_07

这些信息在jsoncole的mbean中也是可以获取的,其实获取的方式和我们是一样的如下:

java xms xmx xmn java xms xmx xmn全称_java_08

通过MemoryMXBean查看堆内存:

java xms xmx xmn java xms xmx xmn全称_java xms xmx xmn_09

通过ClassLoadingMXBean查看类加载和卸载信息:

java xms xmx xmn java xms xmx xmn全称_jvm_10

通过GarbageCollectorMXBean查看GC信息:

java xms xmx xmn java xms xmx xmn全称_jvm_11

写在后面