mbeanclientinterceptor.java

来自「spring framework 2.5.4源代码」· Java 代码 · 共 514 行 · 第 1/2 页

JAVA
514
字号
/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.jmx.access;

import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.management.Attribute;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.JMException;
import javax.management.JMX;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.ReflectionException;
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import javax.management.remote.JMXServiceURL;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.JdkVersion;
import org.springframework.jmx.support.JmxUtils;
import org.springframework.jmx.support.ObjectNameManager;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
 * {@link org.aopalliance.intercept.MethodInterceptor} that routes calls to an
 * MBean running on the supplied <code>MBeanServerConnection</code>.
 * Works for both local and remote <code>MBeanServerConnection</code>s.
 *
 * <p>By default, the <code>MBeanClientInterceptor</code> will connect to the
 * <code>MBeanServer</code> and cache MBean metadata at startup. This can
 * be undesirable when running against a remote <code>MBeanServer</code>
 * that may not be running when the application starts. Through setting the
 * {@link #setConnectOnStartup(boolean) connectOnStartup} property to "false",
 * you can defer this process until the first invocation against the proxy.
 *
 * <p>Requires JMX 1.2's <code>MBeanServerConnection</code> feature.
 * As a consequence, this class will not work on JMX 1.0.
 *
 * <p>This functionality is usually used through {@link MBeanProxyFactoryBean}.
 * See the javadoc of that class for more information.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @since 1.2
 * @see MBeanProxyFactoryBean
 * @see #setConnectOnStartup
 */
public class MBeanClientInterceptor
		implements MethodInterceptor, BeanClassLoaderAware, InitializingBean, DisposableBean {

	/** Logger available to subclasses */
	protected final Log logger = LogFactory.getLog(getClass());

	private MBeanServerConnection server;

	private JMXServiceURL serviceUrl;

	private String agentId;

	private boolean connectOnStartup = true;

	private ObjectName objectName;

	private boolean useStrictCasing = true;

	private Class managementInterface;

	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	private final ConnectorDelegate connector = new ConnectorDelegate();

	private MBeanServerInvocationHandler invocationHandler;

	private Map allowedAttributes;

	private Map allowedOperations;

	private final Map signatureCache = new HashMap();

	private final Object preparationMonitor = new Object();


	/**
	 * Set the <code>MBeanServerConnection</code> used to connect to the
	 * MBean which all invocations are routed to.
	 */
	public void setServer(MBeanServerConnection server) {
		this.server = server;
	}

	/**
	 * Set the service URL of the remote <code>MBeanServer</code>.
	 */
	public void setServiceUrl(String url) throws MalformedURLException {
		this.serviceUrl = new JMXServiceURL(url);
	}

	/**
	 * Set the agent id of the <code>MBeanServer</code> to locate.
	 * <p>Default is none. If specified, this will result in an
	 * attempt being made to locate the attendant MBeanServer, unless
	 * the {@link #setServiceUrl "serviceUrl"} property has been set.
	 * @see javax.management.MBeanServerFactory#findMBeanServer(String)
	 */
	public void setAgentId(String agentId) {
		this.agentId = agentId;
	}

	/**
	 * Set whether or not the proxy should connect to the <code>MBeanServer</code>
	 * at creation time ("true") or the first time it is invoked ("false").
	 * Default is "true".
	 */
	public void setConnectOnStartup(boolean connectOnStartup) {
		this.connectOnStartup = connectOnStartup;
	}

	/**
	 * Set the <code>ObjectName</code> of the MBean which calls are routed to,
	 * as <code>ObjectName</code> instance or as <code>String</code>.
	 */
	public void setObjectName(Object objectName) throws MalformedObjectNameException {
		this.objectName = ObjectNameManager.getInstance(objectName);
	}

	/**
	 * Set whether to use strict casing for attributes. Enabled by default.
	 * <p>When using strict casing, a JavaBean property with a getter such as
	 * <code>getFoo()</code> translates to an attribute called <code>Foo</code>.
	 * With strict casing disabled, <code>getFoo()</code> would translate to just
	 * <code>foo</code>.
	 */
	public void setUseStrictCasing(boolean useStrictCasing) {
		this.useStrictCasing = useStrictCasing;
	}

	/**
	 * Set the management interface of the target MBean, exposing bean property
	 * setters and getters for MBean attributes and conventional Java methods
	 * for MBean operations.
	 */
	public void setManagementInterface(Class managementInterface) {
		this.managementInterface = managementInterface;
	}

	/**
	 * Return the management interface of the target MBean,
	 * or <code>null</code> if none specified.
	 */
	protected final Class getManagementInterface() {
		return this.managementInterface;
	}

	public void setBeanClassLoader(ClassLoader beanClassLoader) {
		this.beanClassLoader = beanClassLoader;
	}


	/**
	 * Prepares the <code>MBeanServerConnection</code> if the "connectOnStartup"
	 * is turned on (which it is by default).
	 */
	public void afterPropertiesSet() {
		if (this.connectOnStartup) {
			prepare();
		}
	}

	/**
	 * Ensures that an <code>MBeanServerConnection</code> is configured and attempts
	 * to detect a local connection if one is not supplied.
	 */
	public void prepare() {
		synchronized (this.preparationMonitor) {
			if (this.server == null) {
				this.server = this.connector.connect(this.serviceUrl, this.agentId);
			}
			this.invocationHandler = null;
			if (this.useStrictCasing) {
				// Use the JDK's own MBeanServerInvocationHandler,
				// in particular for native MXBean support on Java 6.
				if (JdkVersion.isAtLeastJava16()) {
					this.invocationHandler =
							new MBeanServerInvocationHandler(this.server, this.objectName,
									(this.managementInterface != null && JMX.isMXBeanInterface(this.managementInterface)));
				}
				else {
					this.invocationHandler = new MBeanServerInvocationHandler(this.server, this.objectName);
				}
			}
			else {
				// Non-strict asing can only be achieved through custom
				// invocation handling. Only partial MXBean support available!
				retrieveMBeanInfo();
			}
		}
	}
	/**
	 * Loads the management interface info for the configured MBean into the caches.
	 * This information is used by the proxy when determining whether an invocation matches
	 * a valid operation or attribute on the management interface of the managed resource.
	 */
	private void retrieveMBeanInfo() throws MBeanInfoRetrievalException {
		try {
			MBeanInfo info = this.server.getMBeanInfo(this.objectName);

			MBeanAttributeInfo[] attributeInfo = info.getAttributes();
			this.allowedAttributes = new HashMap(attributeInfo.length);
			for (int x = 0; x < attributeInfo.length; x++) {
				this.allowedAttributes.put(attributeInfo[x].getName(), attributeInfo[x]);
			}

			MBeanOperationInfo[] operationInfo = info.getOperations();
			this.allowedOperations = new HashMap(operationInfo.length);
			for (int x = 0; x < operationInfo.length; x++) {
				MBeanOperationInfo opInfo = operationInfo[x];
				Class[] paramTypes = JmxUtils.parameterInfoToTypes(opInfo.getSignature(), this.beanClassLoader);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?