对于MBean,存在于动态MBean和静态MBean。
静态:顾名思义,即对象设置好后,聚焦到JAVA的类对象上,则不能进行增加类的属性和方法。
动态:顾名思义,即在程序运行过程中,可以对MBean进行动态的增加属性和方法。
但大多数场景中,使用静态已经足够满足我们的需求。示例代码:
package com.zte.sunquan.demo.jms;
import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.management.AttributeChangeNotification;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Created by sunquan on 2017/9/18.
*/
public class JSMBeanTest {
String jmxServerName = "SQTestBean";
private Person person;
private ObjectName path;
@Before
public void init() throws MalformedObjectNameException {
person = new Person("sunquan", 28, PersonMBean.Gender.boy,
Lists.newArrayList("Java8", "Netty"),
new long[]{1L, 2L},
new Integer[]{3, 4},
new byte[]{5, 6},
Lists.newArrayList(new Hobby("running")));
//eg.SQTestBean:type=Person,name=sunquan
path = new ObjectName(jmxServerName + ":type=" + Person.class.getSimpleName()
+ ",name=" + person.getName());
}
@Test
public void testMBean() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
//将mbean绑定到指定path上
server.registerMBean(person, path);
TimeUnit.SECONDS.sleep(2);
//取数据
MBeanInfo mBeanInfo = server.getMBeanInfo(path);
Assert.assertEquals(mBeanInfo.getClassName(), Person.class.getName());
Assert.assertEquals("sunquan", server.getAttribute(path, "Name"));
Assert.assertEquals(28, server.getAttribute(path, "Age"));
Assert.assertEquals(PersonMBean.Gender.boy, server.getAttribute(path, "Gender"));
Assert.assertTrue(((List<String>) server.getAttribute(path, "Hobby")).size() == 1);
// latch.await();
}
@Test
public void dynamicMBean()throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName helloName = new ObjectName("jmx:name=dynamicBeanHello");
server.registerMBean(new BillInfo(), helloName);
latch.await();
// HtmlAdaptorServer adaptor = new HtmlAdaptorServer();
// ObjectName adaptorName = new ObjectName("jmxAdaptor:name=adaptor,port=5050");
// server.registerMBean(adaptor, adaptorName);
// adaptor.setPort(9999);
// adaptor.start();
System.out.println("....................jmx server start....................");
}
@Test
public void dynamicMBean2()throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName helloName = new ObjectName("jmx:name=dynamicBeanHello");
Bill bill = new Bill();
server.registerMBean(bill, helloName);
Thread.sleep(10000);
bill.addAttribute();
latch.await();
}
@Test
public void notifyMBean()throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName helloName = new ObjectName("jmx:name=notifyBeanHello");
Account account = new Account();
server.registerMBean(account, helloName);
server.addNotificationListener(helloName,(notification,b)->{
System.out.println("SequenceNumber:" + notification.getSequenceNumber());
System.out.println("Type:" + notification.getType());
System.out.println("Message:" + notification.getMessage());
System.out.println("Source:" + notification.getSource());
System.out.println("TimeStamp:" + notification.getTimeStamp());
System.out.println("userData:"+notification.getUserData());
System.out.println("bach:"+b);
if(notification instanceof AttributeChangeNotification){
AttributeChangeNotification no = (AttributeChangeNotification) notification;
System.out.println("OldValue:"+no.getOldValue());
System.out.println("NewValue:"+no.getNewValue());
}
},null,null);
latch.await();
}
}
package com.zte.sunquan.demo.jms;
import java.util.List;
/**
* Created by sunquan on 2017/9/29.
*/
public interface PersonMBean {
String getName();
void setName(String name);
int getAge();
Gender getGender();
List<String> getBooks();
long[] getLongs();
Integer[] getIntegers();
byte[] getBytes();
List<Hobby> getHobby();
void printHello();
void printHello(String whoName);
enum Gender {
boy, girl;
}
}
package com.zte.sunquan.demo.jms;
import java.util.List;
/**
* Created by sunquan on 2017/9/29.
*/
public class Person implements PersonMBean {
private String name;
private int age;
private Gender gender;
private List<String> books;
private long[] longs;
private Integer[] integers;
private byte[] bytes;
private List<Hobby> hobbies;
public Person(){
}
public Person(String name, int age, Gender gender){
this.name = name;
this.age = age;
this.gender = gender;
}
public Person(String name, int age, Gender gender, List<String> books, long[] longs, Integer[] integers, byte[] bytes, List<Hobby> hobbies) {
this.name = name;
this.age = age;
this.gender = gender;
this.books = books;
this.longs = longs;
this.integers = integers;
this.bytes = bytes;
this.hobbies = hobbies;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public int getAge() {
return age;
}
@Override
public Gender getGender() {
return gender;
}
@Override
public List<String> getBooks() {
return books;
}
@Override
public long[] getLongs() {
return longs;
}
@Override
public Integer[] getIntegers() {
return integers;
}
@Override
public byte[] getBytes() {
return bytes;
}
@Override
public List<Hobby> getHobby() {
return hobbies;
}
@Override
public void printHello() {
System.out.println("hello,world");
}
@Override
public void printHello(String whoName) {
System.out.println("hello,world-" + whoName);
}
}
package com.zte.sunquan.demo.jms;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.DynamicMBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;
import java.lang.reflect.Constructor;
import java.util.Iterator;
/**
* Created by sunquan on 2017/9/29.
*/
public class BillInfo implements DynamicMBean {
//attributes
private String name;
private MBeanInfo mBeanInfo = null;
private String className;
private String description;
private MBeanAttributeInfo[] attributes;
private MBeanConstructorInfo[] constructors;
private MBeanOperationInfo[] operations;
MBeanNotificationInfo[] mBeanNotificationInfoArray;
public BillInfo() {
init();
buildDynamicMBean();
}
private void init() {
className = this.getClass().getName();
description = "Simple implementation of a MBean.";
//initial attributes
attributes = new MBeanAttributeInfo[1];
//initial constructors
constructors = new MBeanConstructorInfo[1];
//initial method
operations = new MBeanOperationInfo[1];
mBeanNotificationInfoArray = new MBeanNotificationInfo[0];
}
private void buildDynamicMBean() {
//create constructor
Constructor[] thisconstructors = this.getClass().getConstructors();
constructors[0] = new MBeanConstructorInfo("HelloDynamic(): Constructs a HelloDynamic object", thisconstructors[0]);
//create attribute
attributes[0] = new MBeanAttributeInfo("Name", "java.lang.String", "Name: name string.", true, true, false);
//create operate method
MBeanParameterInfo[] params = null;//no parameter
operations[0] = new MBeanOperationInfo("print", "print(): print the name", params, "void", MBeanOperationInfo.INFO);
//create mbean
mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
}
//dynamically add a print1 method
private void dynamicAddOperation() {
init();
operations = new MBeanOperationInfo[2];
buildDynamicMBean();
operations[1] = new MBeanOperationInfo("print1", "print1(): print the name", null, "void", MBeanOperationInfo.INFO);
mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
}
@Override
public Object getAttribute(String attribute_name) {
if (attribute_name == null) {
return null;
}
if (attribute_name.equals("Name")) {
return name;
}
return null;
}
@Override
public void setAttribute(Attribute attribute) {
if (attribute == null) {
return;
}
String Name = attribute.getName();
Object value = attribute.getValue();
try {
if (Name.equals("Name")) {
// if null value, try and if the setter returns any exception
if (value == null) {
name = null;
// if non null value, make sure it is assignable to the attribute
} else if ((Class.forName("java.lang.String")).isAssignableFrom(value.getClass())) {
name = (String) value;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public AttributeList getAttributes(String[] attributeNames) {
if (attributeNames == null) {
return null;
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, return anempty result list
if (attributeNames.length == 0) {
return resultList;
}
for (int i = 0; i < attributeNames.length; i++) {
try {
Object value = getAttribute(attributeNames[i]);
resultList.add(new Attribute(attributeNames[i], value));
} catch (Exception e) {
e.printStackTrace();
}
}
return resultList;
}
@Override
public AttributeList setAttributes(AttributeList attributes) {
if (attributes == null) {
return null;
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, nothing more to do
if (attributes.isEmpty()) {
return resultList;
}
// for each attribute, try to set it and add to the result list if successfull
for (Iterator i = attributes.iterator(); i.hasNext(); ) {
Attribute attr = (Attribute) i.next();
try {
setAttribute(attr);
String name = attr.getName();
Object value = getAttribute(name);
resultList.add(new Attribute(name, value));
} catch (Exception e) {
e.printStackTrace();
}
}
return resultList;
}
@Override
public Object invoke(String operationName, Object params[], String signature[]) throws MBeanException, ReflectionException {
// Check for a recognized operationname and call the corresponding operation
if (operationName.equals("print")) {
System.out.println("Hello, " + name + ", this is HelloDynamic!");
//dynamic add a method
dynamicAddOperation();
return null;
} else if (operationName.equals("print1")) {
System.out.println("dynamically add a print1 method");
return null;
} else {
// unrecognized operation name:
throw new ReflectionException(new NoSuchMethodException(operationName), "Cannot find the operation " + operationName + " in " + className);
}
}
public MBeanInfo getMBeanInfo() {
return mBeanInfo;
}
}
package com.zte.sunquan.demo.jms;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.ReflectionException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
/**
* Created by sunquan on 2017/9/30.
* 新增属性
*/
public class Bill implements DynamicMBean {
private Map<String, Long> prices = new HashMap<>();
private MBeanInfo mBeanInfo;
private MBeanAttributeInfo[] attributes;
private MBeanConstructorInfo[] mBeanConstructorInfos;
public Bill() {
Constructor[] constructors = this.getClass().getConstructors();
MBeanConstructorInfo mBeanConstructorInfo = new MBeanConstructorInfo("constructors", constructors[0]);
mBeanConstructorInfos = new MBeanConstructorInfo[1];
mBeanConstructorInfos[0] = mBeanConstructorInfo;
mBeanInfo = new MBeanInfo(this.getClass().getName(),
"description", attributes, mBeanConstructorInfos,
null, null);
}
/**
* 方法 动态新增属性,需要重新实例化mBeanInfo
*/
public void addAttribute() {
attributes = new MBeanAttributeInfo[1];
attributes[0] = new MBeanAttributeInfo("price1", "java.lang.String", "price11", true, true, false);
prices.put("price1", 100L);
mBeanInfo = new MBeanInfo(this.getClass().getName(),
"description", attributes, mBeanConstructorInfos,
null, null);
}
@Override
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
System.out.println("getAttribute");
return Optional.ofNullable(prices.get(attribute)).orElse(0L);
}
@Override
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
System.out.println("setAttribute");
prices.put(attribute.getName(), Long.parseLong(attribute.getValue().toString()));
}
@Override
public AttributeList getAttributes(String[] attributes) {
//通过该方法获取属性名与值
System.out.println("getAttributes");
AttributeList resultList = new AttributeList();
for (String attr : attributes) {
try {
resultList.add(new Attribute(attr, getAttribute(attr)));
} catch (AttributeNotFoundException e) {
e.printStackTrace();
} catch (MBeanException e) {
e.printStackTrace();
} catch (ReflectionException e) {
e.printStackTrace();
}
}
return resultList;
}
@Override
public AttributeList setAttributes(AttributeList attributes) {
AttributeList resultList = new AttributeList();
for (Iterator i = attributes.iterator(); i.hasNext(); ) {
Attribute attr = (Attribute) i.next();
try {
setAttribute(attr);
String name = attr.getName();
Object value = getAttribute(name);
resultList.add(new Attribute(name, value));
} catch (Exception e) {
e.printStackTrace();
}
}
return resultList;
}
@Override
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
return null;
}
@Override
public MBeanInfo getMBeanInfo() {
return mBeanInfo;
}
}
package com.zte.sunquan.demo.jms;
import javax.management.AttributeChangeNotification;
import javax.management.NotificationBroadcasterSupport;
import java.util.concurrent.atomic.AtomicLong;
/**
* Created by sunquan on 2017/9/30.
*/
public class Account extends NotificationBroadcasterSupport implements AccountMBean {
private AtomicLong sequenceNumber = new AtomicLong(1);
private String name;
@Override
public void setName(String name) {
AttributeChangeNotification notification = new AttributeChangeNotification(
this, sequenceNumber.getAndIncrement(),
System.currentTimeMillis(),
AttributeChangeNotification.ATTRIBUTE_CHANGE,
"name",
"java.lang.String",
this.name,
name
);
this.name = name;
super.sendNotification(notification);
}
@Override
public String getName() {
return name;
}
}
package com.zte.sunquan.demo.jms;
/**
* Created by sunquan on 2017/9/30.
*/
public interface AccountMBean {
void setName(String name);
String getName();
}
为使MBEAN可以远程访问,需要增加程序的启动参数
-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.port=911 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
代码中远程获取Bean 关于jmxUrl 如
service:jmx:rmi:///jndi/rmi://0.0.0.0:1099/jmxrmi
public static MBeanServerConnection getMBeanServerConnection(final String rmiJmxUrl, final String user, final String password) {
try {
if (rmiJmxUrl == null) {
MBeanServerConnection mbeanServer = ManagementFactory.getPlatformMBeanServer();
return mbeanServer;
} else {
HashMap<String, String[]> environment = new HashMap<String, String[]>();
if ((user == null) || (password == null)) {
String[] creds = {"karaf", "karaf"};
environment.put(JMXConnector.CREDENTIALS, creds);
} else {
String[] creds = {user, password};
environment.put(JMXConnector.CREDENTIALS, creds);
}
if (rmiJmxUrl != null) {
JMXServiceURL url = new JMXServiceURL(rmiJmxUrl);
JMXConnector connector = JMXConnectorFactory.connect(url, environment);
MBeanServerConnection mbeanServer = connector.getMBeanServerConnection();
return mbeanServer;
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
测试用例:Path SQTestBean:type=Person,name=sunquan
@Test
public void testRemoteMBean() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
//将mbean绑定到指定path上
server.registerMBean(person, path);
TimeUnit.SECONDS.sleep(2);
//取数据
MBeanServerConnection mBeanServerConnection =
getMBeanServerConnection("service:jmx:rmi:///jndi/rmi://10.42.197.153:1099/jmxrmi", "a", "b");
MBeanInfo mBeanInfo = mBeanServerConnection.getMBeanInfo(path);
Assert.assertEquals(mBeanInfo.getClassName(), Person.class.getName());
Assert.assertEquals("sunquan", server.getAttribute(path, "Name"));
Assert.assertEquals(28, server.getAttribute(path, "Age"));
Assert.assertEquals(PersonMBean.Gender.boy, server.getAttribute(path, "Gender"));
Assert.assertTrue(((List<String>) server.getAttribute(path, "Hobby")).size() == 1);
// latch.await();
}