【JMX】-----JMX管理Spring Bean(二)

前言

    虽然最初的JMX规范提及了通过MBean进行应用的远程管理,但并没有定义实际的远程访问协议或者API。为了有标准方式进行远程访问JMX,JCP(Java community Process)指定了JSR-160,即Java管理扩展远程访问API规范(Java Management Extensions Remote API Specification),该规范定义JMX远程访问的标准,该标准至少需要绑定RMI和可选JMX消息协议(JMX Messaging Protocol,JMXMP)

Spring JMX可以将Spring bean导出为模型MBean,并且能够对MBean导出的方法和属性进行细粒度控制,具体可以查看文章【JMX】-----JMX管理Spring Bean(一)

1.暴露远程MBean

使MBean成为远程对象最简单的方式是配置Spring的ConnectorServerFactoryBeanConnectorServerFactoryBean会创建和启动JSR-160 JMXConnetorServer。默认情况下,服务器使用的是JMXMP协议并监听9875,因此绑定的地址是"service:jmx:jmxmp://localhost:9875"。

 @Bean
  public ConnectorServerFactoryBean connectoryFactoryBean() {
    return new ConnectorServerFactoryBean();
  }

    根据不同的JMX实现,有多种远程访问协议可供选择,如RMI(Remote Method Invocation)SOAPHessian/BurlapIIOP(Internet InterORB Protocol)。为使MBean绑定不同远程访问协议,需要设置ConnectorServerFactoryBeanserviceUrl属性。例如使用RMI远程访问MBean,可以作如下配置:

 @Bean
  public ConnectorServerFactoryBean connectorServerFactoryBean() {
    ConnectorServerFactoryBean csfb = new ConnectorServerFactoryBean();
    csfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
    return csfb;
  }

这里将ConnectorServerFactoryBean绑定到一个RMI注册表,该注册表监听本机的1099端口。这意味着需要一个RMI注册表运行并且监听改该端口,此处通过Spring中声明一个RmiRegistryFactoryBean来启动一个RMI注册表,如下:

 @Bean 
  public RmiRegistryFactoryBean rmiRegistryFB() {
    RmiRegistryFactoryBean rmiRegistryFB = new RmiRegistryFactoryBean();
    rmiRegistryFB.setPort(1099);
    return rmiRegistryFB;
  }

———基于RMI的公开MBean管理接口和访问

下面案例基于RMI暴露一个远程的MBean,客户端就可以基于RMI来远程访问MBean。为了配置简单,使用SpringBoot项目,完整的代码如下:
【步骤一】:使用java配置方式,创建的一个RMI注册表,并将JMX服务器绑定到此注册表上。

@Configuration
public class JavaConfig {

  //1.默认的方式
  /*  @Bean
  public ConnectorServerFactoryBean connectoryFactoryBean() {
    return new ConnectorServerFactoryBean();
  }*/
  
  //启动一个RMI注册表,并监听1099端口
  @Bean 
  public RmiRegistryFactoryBean rmiRegistryFB() {
    RmiRegistryFactoryBean rmiRegistryFB = new RmiRegistryFactoryBean();
    rmiRegistryFB.setPort(1099);
    return rmiRegistryFB;
  }

  //2.基于RMI的远程服务器,需要绑定到RMI注册表上
  @Bean
  public ConnectorServerFactoryBean connectorServerFactoryBean() {
    ConnectorServerFactoryBean csfb = new ConnectorServerFactoryBean();
    csfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
    return csfb;
  }
}

【步骤二】:基于注解方式暴露MBean管理接口。

@Controller
@ManagedResource(objectName = "spitter:name=SpittleController")
// @EnableMBeanExport(registration=RegistrationPolicy.FAIL_ON_EXISTING,)
public class SpittleController {

  public static final int DEFAULT_SPITTLES_PER_PAGE = 25;
  private int spittlesPerPage = DEFAULT_SPITTLES_PER_PAGE;

  @ManagedAttribute
  public int getSpittlesPerPage() {
    return spittlesPerPage;
  }

  @ManagedAttribute
  public void setSpittlesPerPage(int spittlesPerPage) {
    this.spittlesPerPage = spittlesPerPage;
  }

  @ManagedOperation
  public int printSpittlesPerPage() {
    System.out.println("spittlesPerPage--" + spittlesPerPage);
    return spittlesPerPage;
  }

}

【步骤三】:SpringBoot项目启动类。

@SpringBootApplication
@ComponentScan(basePackages = "com.corp")
//@ImportResource("classpath:applicationContext.xml")
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}
2.访问远程MBean
2.1通过jsoncole工具访问

jsoncole的工具的位置在D:\jdk1.8\bin,新建连接->远程进程访问,访问地址是service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter
在这里插入图片描述
在这里插入图片描述
可以修改属性SpittlesPerPage的值,在操作里面操作调用printSpittlesPerPage,后台将打印如下:

spittlesPerPage--30
2.2 基于RMI客户端代码访问

客户端要访问远程MBean服务器,需要在Spring上下文中配置MbeanServerConnectionFactoryBean,它可以创建一个MBeanServerConnection的工厂bean,MBeanServerConnnection用于与MBean服务器端进行通信。

【步骤一】:基于java类配置一个MbeanServerConnectionFactoryBean,并设置serviceUrl属性。

@Configuration
public class JavaConfig {

  @Bean
  @Primary
  public MBeanServerConnectionFactoryBean connectionFactoryBean() throws MalformedURLException {
    MBeanServerConnectionFactoryBean mbscfb = new MBeanServerConnectionFactoryBean();
    mbscfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
    return mbscfb;
  }
}

【步骤二】:将MBeanServerConnectionFactoryBean 生成的MBeanServerConnnection作为远程MBean服务器的本地代理对象,注入到MBeanServerConnection 中,并通过MBeanServerConnection来访问远程MBean服务器信息和MBean属性和方法。

@Controller
public class JMXClient {
  
  private MBeanServerConnection mbsConnection;
  
  @Autowired
  public void setMbsConnection(MBeanServerConnection mbsConnection) {
    this.mbsConnection = mbsConnection;
  }

  @RequestMapping("/request")
  public String getRequest() throws Exception {
    //获取注册到MBeanServer服务器上的MBean数量
    System.out.println("Mbeans count------"+mbsConnection.getMBeanCount());
    //查询MBeanServer上指定条件的实例对象
    ObjectName name = new ObjectName("spitter:name=SpittleController");
    Set<ObjectInstance> objSet = mbsConnection.queryMBeans(name, null);
    for(ObjectInstance obj:objSet) {
      System.out.println(obj);
    }
    Object attribute = mbsConnection.getAttribute(name, "SpittlesPerPage");
    System.out.println("spittlesPerPage value-----"+attribute);
    //修改spittlesPerPage的属性值
    mbsConnection.setAttribute(name, new Attribute("SpittlesPerPage",30));
    //调用MBean操作,使用invoke()方法,执行pringSpittlesPerPage方法
    mbsConnection.invoke(name, "printSpittlesPerPage", null, null);
    //指定setSpittlesPerPage方法,其中int.class.getName()="int"
    mbsConnection.invoke(name, "setSpittlesPerPage", new Object[] {100}, new String[] {int.class.getName()});
    //通过setSpittlesPerPage方法修改属性值后,查看SpittlesPerPage的值
    Object attribute1 = mbsConnection.getAttribute(name, "SpittlesPerPage");
    System.out.println("spittlesPerPage value after change----"+attribute1);
    return "";
  }
}

页面访问http://localhost:8888/request
客户端打印结果:

Mbeans count------56
com.corp.demo.SpittleController[spitter:name=SpittleController]
spittlesPerPage value-----25
spittlesPerPage value after change----100

服务端打印结果:

spittlesPerPage--30
3. 代理MBean

Spring整合RMIHessian或者Spring HTTPInvoker都提供一个了代理来访问远程服务(代理分别是HessianProxyFactoryBeanRmiProxyFactoryBeanHttpInvokerProxyFactoryBean)。同样Spring JMX也提供了代理工厂bean,类名是MeanProxyFactoryBean,用于访问远程的Spring受管理的bean。MBeanProxyFactoryBean可以创建通过MBeanServerConnection可访问的任何MBean的代理,客户端通过此代理与远程的MBean进行交互,如同配置本地的其他bean一样。
在这里插入图片描述

3.1 MBean暴露接口

【步骤一】:编写接口。

public interface SpittleControllerManagedOperations {
  
  public int getSpittlesPerPage();
  public void setSpittlesPerPage(int spittlesPerPage);
  public int printSpittlesPerPage();
}

【步骤二】:使用java注解驱动MBean的方式,其中SpittleController不是必须实现SpittleControllerManagedOperations接口。

@Controller
@ManagedResource(objectName ="spitter:name=SpittleController")
public class SpittleController implements SpittleControllerManagedOperations{

  public static final int DEFAULT_SPITTLES_PER_PAGE = 25;
  private int spittlesPerPage = DEFAULT_SPITTLES_PER_PAGE;

  @ManagedAttribute
  public int getSpittlesPerPage() {
    return spittlesPerPage;
  }

  @ManagedAttribute
  public void setSpittlesPerPage(int spittlesPerPage) {
    this.spittlesPerPage = spittlesPerPage;
  }

  @ManagedOperation
  public int printSpittlesPerPage() {
    System.out.println("spittlesPerPage--" + spittlesPerPage);
    return spittlesPerPage;
  }

}

【步骤三】:SpingBoot项目启动。

@SpringBootApplication
@ComponentScan(basePackages = "com.corp")
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}
3.2 客户端用代理访问MBean

MBeanProxyFactoryBean会创建远程MBean的代理,其中ObjectName属性指定了远程MBean对象名称,server属性设置为MBeanServerConnectionFactoryBean工厂bean类生成的对象,通过它实现MBean所有通信的路由。最后ProxyInterface属性指定了代理需要实现的接口,即SpittleControllerManagedOperations接口。由MBeanProxyFactoryBean产生的代理对象,可以将其注入到SpittleControllerManagedOperations 的bean属性中,将使用它来访问远程MBean
【步骤一】:编写接口

public interface SpittleControllerManagedOperations {
  
  public int getSpittlesPerPage();
  public void setSpittlesPerPage(int spittlesPerPage);
  public int printSpittlesPerPage();
}

【步骤二】:使用java类配置方式,配置MBeanServerConnectionFactoryBean和MBeanProxyFactoryBean。

@Configuration
public class JavaConfig {

  @Bean
  @Primary
  public MBeanServerConnectionFactoryBean connectionFactoryBean() throws MalformedURLException {
    MBeanServerConnectionFactoryBean mbscfb = new MBeanServerConnectionFactoryBean();
    mbscfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
    return mbscfb;
  }
  
  @Bean
  public MBeanProxyFactoryBean spittleController(MBeanServerConnection mbeanServerClient) throws Exception {
    MBeanProxyFactoryBean proxy = new MBeanProxyFactoryBean();
    //设置要访问的MBean的ObjectName
    proxy.setObjectName("spitter:name=SpittleController");
    //设置代理接口
    proxy.setProxyInterface(SpittleControllerManagedOperations.class);
    proxy.setServer(mbeanServerClient);
    return proxy;
  }
}

【步骤三】:将通知MBeanProxyFactoryBean生成的MBean服务代理对象注入到代理接口SpittleControllerManagedOperations中,从而访问MBean的操作 。如下直接可以调用setSpittlesPerPage()和getSpittlesPerPage()方法了。

@Controller
public class MBeanProxyClient {
  
  private SpittleControllerManagedOperations spittleController;
  
  @Autowired
  public void setSpittleController(SpittleControllerManagedOperations spittleController) {
    this.spittleController = spittleController;
  }

  @RequestMapping("/request")
  public String request() {
    spittleController.setSpittlesPerPage(10);
    System.out.println("spittlesPerPage value---"+spittleController.getSpittlesPerPage());
    return "";
  }
}

【步骤四】:SpringBoot项目启动类,由于服务器端tcomat端口是8080,因此为了避免端口冲突,将客户端tomcat端口修改为8888。
在src/main/resource目录下面新建文件,名称为application.properties,配置端口。

Server.port=8888
@SpringBootApplication
@ComponentScan(basePackages = "com.corp")
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

此时页面访问localhost:8888/request,后台打印如下:

spittlesPerPage value---10
4.通知
4.1 发布通知

通过MBean的公开属性和方法获取了资源信息,但当发生有重要的事件时,如果希望能够及时告知用户,较好的方式是MBean发送通知给用户,JMX通知(JMX Notification)是MBean与外部主动通信的一种方式,而不是等待外部应用对MBean进行信息查询。Spring提供了JMX通知的支持,Spring JMX发布通知的关键接口是org.springframework.jmx.export.notification.NotificationPublisher。通过MBeanExporter导出为MBean的任何Spring Bean可以实现NotificationPublisherAware接口,并且重写方法setNotificationPublisher(NotificationPublisher notificationPublisher)来获取一个NotificationPublisher实例。使用NotificationPublisher方式比较简单,需要创建一个Notification实例(或者Notification子类实例)并设置发布通知的相关数据,在NotificationPublisher 实例上面调用sendNotification(Notification notification)来发布通知。

4.2 监听通知

上面说到MBean可以发布通知,那么就需要一个监听器来监听和处理通知,否则发送通知毫无意义。接收MBean通知的标准方法是实现javax.management.NotificationListener接口,并且通过方法handleNotification()来处理通知。通过设置MBeanExporterNotificationListeners属性或者notificationListenerMappings 属性来配置监听器和希望监听的MBean之间建立映射。如果一个监听器需要监听单个或者多个通知时,可以配置notificationListenerMappings属性,此属性是一个映射集,将键配置为统配符(*)表示单个监听器监听所有的MBean通知。相反如果要为一个MBean通知注册多个不同的监听器,可以使用notificationListeners列表属性。notificationListeners列表中需要配置一个NotificationListenerBeanNotificationListenerBean封装了一个notificationListenersOBjectName,同时还包含其他属性,例如在高级通知方案 中使用的NotificationFilterhandback对象。

4.3 单个监听器监听多个MBean通知

通过设置MBeanExporternotificationListenerMappings属性,来实现单个监听器监听单个或者多个MBean通知。
其中notificationListenerMappings是一个MBean的ObjectName名称和监听器对象的映射集。某个监听器对象对应的键为统配符(*),表示该监听器监听所有的MBean通知。如果设置为MBean的ObjectName名称,表示监听的是指定的MBean通知。
【步骤一】:编写一个接口IJmxTestBean。

public interface IJmxTestBean {

    public int add(int x, int y);
    public int getAge();
    public void setAge(int age);
    public void setName(String name);
    public String getName();
}

【步骤二】:编写接口的实现JmxTestBean,用于发送通知。
JmxTestBean类实现了IJmxTestBean接口和NotificationPublisherAware,并且通过方法setNotificationPublisher来获取一个NotificationPublisher对象,在add()方法中调用NotificationPublisher对象的sendNotification()方法来发送通知。当本地或者远程访问MBean中的add()方法时,Spring JMX将会发送通知给监听器。

public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware {

    private String name;
    private int age;
    private NotificationPublisher publisher;

    public String getName() {
      return name;
    }
    public void setName(String name) {
      this.name = name;
    }
    public int getAge() {
      return age;
    }
    public void setAge(int age) {
      this.age = age;
    }

    //发送通知
    public int add(int x, int y) {
        int answer = x + y;
        this.publisher.sendNotification(new Notification("add", this, 0,"invoke add operation,x+y="+answer));
        return answer;
    }

    public void dontExposeMe() {
        throw new RuntimeException();
    }
    
    //获取NotificationPublisher实例
    public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
        this.publisher = notificationPublisher;
    }
}

【步骤三】:编写一个监听器类ConsoleLoggingNotificationListener,为了接收到通知,需要实现NotificationListener接口。此外可以实现NotificationFilter接口,用于过滤出感兴趣的通知。
ConsoleLoggingNotificationListener类实现了NotificationListener接口,重写handleNotification()方法,在此方法中对通知进行处理。实现了NotificationFilter接口,通过isNotificationEnabled()方法来过滤出感兴趣的通知。

@Component
public class ConsoleLoggingNotificationListener implements NotificationListener,NotificationFilter{

  @Override
  public boolean isNotificationEnabled(Notification notification) {
    //return AttributeChangeNotification.class.isAssignableFrom(notification.getClass());
    return true;
  }

  @Override
  public void handleNotification(Notification notification, Object handback) {
    System.out.println("notification---"+notification);
    System.out.println("handback---"+handback);
  }

}

【步骤四】:XML配置方式配置一个MBeanExporter,将Spring bean导出为MBean,并且设置监听类。
MBeanExporter属性notificationListenerMappings设置为map集合,此映射集中对应的键值对分别表示的是一个被监听对象和一个监听器。例如此处为JmxTestBean配置一个监听器ConsoleLoggingNotificationListener,键可以有三种设置方式:

  1. 设置为JmxTestBean的ObjectName名称,此处为bean:name=JmxTestBean
  2. 设置为JmxTestBean的bean的id,此处testBean
  3. 设置为统配符"*",表示监听所有的通知,因此可以监听到JmxTestBean中发出的通知。
<bean id="exporter"
		class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="bean:name=JmxTestBean" value-ref="testBean" />
			</map>
		</property>
		<property name="notificationListenerMappings">
			<map>
				<!-- <entry key="bean:name=testBean1"> -->
				<!-- key配置为JmxTestBean的id,即testBean -->
				<!-- <entry key="testBean"> -->
				<entry key="*">
					<bean
						class="com.corp.notification.ConsoleLoggingNotificationListener" />
				</entry>
			</map>
		</property>
	</bean>
	<bean id="testBean" class="com.corp.notification.JmxTestBean">
		<property name="name" value="test" />
		<property name="age" value="100" />
	</bean>

【步骤五】:SpringBoot项目启动类。

@SpringBootApplication
@ComponentScan(basePackages = "com.corp")
@ImportResource("classpath:applicationContext.xml")
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

通过jconsole工具来访问MBean,点击add操作调用,监听器可以接收到相应的通知。
在这里插入图片描述
后台打印:

notification---javax.management.Notification[source=bean:name=testBean1][type=add][message=invoke add operation,x+y=0]
handback---null
4.3 为单个MBean通知配置多个监听器

当需要针对MBean注册多个不同的监听器时,可以使用MBeanExporter对象的notificationListeners列表属性,notificationListeners列表中的对象是notificationListenerBeannotificationListenerBean封装了要注册的监听器notificationListenerObjectName(或ObjectNames),此外还包含其他属性。
因此可以通过NotificationListenerBean实现单监听器监听单个或者多个MBean通知,也可以实现为单个MBean通知配置多个监听器。
————使用NotificationListenerBean配置单个监听器监听单个MBean通知。

<bean id="exporter"  class="org.springframework.jmx.export.MBeanExporter">
	<property name="beans">
		<map>
			<entry key="bean:name=testBean1" value-ref="testBean" />
		</map>
	</property>
	<property name="notificationListeners">
		<list>
			<bean
				class="org.springframework.jmx.export.NotificationListenerBean">
				<constructor-arg>
					<bean class="com.corp.notification.ConsoleLoggingNotificationListener" />
				</constructor-arg>
				<property name="mappedObjectNames">
					<list>
						<value>bean:name=testBean1</value>
					</list>
				</property>
			</bean>
		</list>
	</property>
</bean>

<bean id="testBean" class="com.corp.notification.JmxTestBean">
	<property name="name" value="TEST" />
	<property name="age" value="100" />
</bean>

通过jconsole工具来访问MBean,点击add操作调用,监听器可以接收到相应的通知。在这里插入图片描述

notification---javax.management.Notification[source=bean:name=testBean1][type=add][message=invoke add operation,x+y=0]
handback---null

————使用NotificationListenerBean配置单个监听器监听多个MBean通知。

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
     <property name="beans">
         <map>
             <entry key="bean:name=testBean1" value-ref="testBean1"/>
             <entry key="bean:name=testBean2" value-ref="testBean2"/>
         </map>
     </property>
     <property name="notificationListeners">
         <list>
             <bean class="org.springframework.jmx.export.NotificationListenerBean">
                 <constructor-arg ref="customerNotificationListener"/>
                 <property name="mappedObjectNames">
                     <list>
                         <!-- handles notifications from two distinct MBeans -->
                         <value>bean:name=testBean1</value>
                         <value>bean:name=testBean2</value>
                     </list>
                 </property>
                 <property name="handback">
                     <bean class="java.lang.String">
                         <constructor-arg value="This could be anything..."/>
                     </bean>
                 </property>
                 <property name="notificationFilter" ref="customerNotificationListener"/>
             </bean>
         </list>
     </property>
 </bean>
 <!-- implements both the NotificationListener and NotificationFilter interfaces -->
 <bean id="customerNotificationListener" class="com.corp.notification.ConsoleLoggingNotificationListener"/>
 <bean id="testBean1" class="com.corp.notification.JmxTestBean">
     <property name="name" value="TEST"/>
     <property name="age" value="100"/>
 </bean>
 <bean id="testBean2" class="com.corp.notification.JmxTestBean">
     <property name="name" value="ANOTHER TEST"/>
     <property name="age" value="200"/>
 </bean>

通过jconsole工具来访问MBean,点击add操作调用,监听器可以接收到相应的通知。
在这里插入图片描述
后台打印结果:

notification---javax.management.Notification[source=bean:name=testBean1][type=add][message=invoke add operation,x+y=0]
handback---This could be anything...
notification---javax.management.Notification[source=bean:name=testBean2][type=add][message=invoke add operation,x+y=0]
handback---This could be anything...

————使用NotificationListenerBean为单个MBean通知配置多个监听器。
此处可以直接复制类ConsoleLoggingNotificationListener,添加第二个监听器,类名为ConsoleLoggingNotificationListener1

@Component
public class ConsoleLoggingNotificationListener1 implements NotificationListener,NotificationFilter{

  @Override
  public boolean isNotificationEnabled(Notification notification) {
    return AttributeChangeNotification.class.isAssignableFrom(notification.getClass());
  }

  @Override
  public void handleNotification(Notification notification, Object handback) {
    System.out.println("notification1---"+notification);
    System.out.println("handback1---"+handback);
  }

}
<bean id="exporter"
	class="org.springframework.jmx.export.MBeanExporter">
	<property name="beans">
		<map>
			<entry key="bean:name=testBean1" value-ref="testBean1" />
		</map>
	</property>
	<property name="notificationListeners">
		<list>
			<bean
				class="org.springframework.jmx.export.NotificationListenerBean">
				<constructor-arg ref="customerNotificationListener" />
				<property name="mappedObjectNames">
					<list>
						<value>bean:name=testBean1</value>
					</list>
				</property>
				<!-- <property name="handback"> <bean class="java.lang.String"> <constructor-arg 
					value="This could be anything..."/> </bean> </property> <property name="notificationFilter" 
					ref="customerNotificationListener"/> -->
			</bean>
			<bean
				class="org.springframework.jmx.export.NotificationListenerBean">
				<constructor-arg
					ref="customerNotificationListener1" />
				<property name="mappedObjectNames">
					<list>
						<value>bean:name=testBean1</value>
					</list>
				</property>
				<!-- <property name="handback"> <bean class="java.lang.String"> <constructor-arg 
					value="This could be anything..."/> </bean> </property> <property name="notificationFilter" 
					ref="customerNotificationListener"/> -->
			</bean>
		</list>
	</property>
</bean>

<!-- implements both the NotificationListener and NotificationFilter interfaces -->
<bean id="customerNotificationListener" class="com.corp.notification.ConsoleLoggingNotificationListener" />
<bean id="customerNotificationListener1" class="com.corp.notification.ConsoleLoggingNotificationListener1" />
<bean id="testBean1" class="com.corp.notification.JmxTestBean">
	<property name="name" value="TEST" />
	<property name="age" value="100" />
</bean>

通过jconsole来访问MBean的操作。
在这里插入图片描述
后台打印:

notification---javax.management.Notification[source=bean:name=testBean1][type=add][message=invoke add operation,x+y=0]
handback---null
notification1---javax.management.Notification[source=bean:name=testBean1][type=add][message=invoke add operation,x+y=0]
handback1---null
5.参考
  1. 《Spring In Action》
  2. Spring官方文档
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值