📄 abstractreflectivembeaninfoassembler.java
字号:
/*
* Copyright 2002-2006 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.export.assembler;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.management.Descriptor;
import javax.management.JMException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.JdkVersion;
import org.springframework.jmx.support.JmxUtils;
/**
* Builds on the {@link AbstractMBeanInfoAssembler} superclass to
* add a basic algorithm for building metadata based on the
* reflective metadata of the MBean class.
*
* <p>The logic for creating MBean metadata from the reflective metadata
* is contained in this class, but this class makes no decisions as to
* which methods and properties are to be exposed. Instead it gives
* subclasses a chance to 'vote' on each property or method through
* the <code>includeXXX</code> methods.
*
* <p>Subclasses are also given the opportunity to populate attribute
* and operation metadata with additional descriptors once the metadata
* is assembled through the <code>populateXXXDescriptor</code> methods.
*
* @author Rob Harrop
* @author Juergen Hoeller
* @since 1.2
* @see #includeOperation
* @see #includeReadAttribute
* @see #includeWriteAttribute
* @see #populateAttributeDescriptor
* @see #populateOperationDescriptor
*/
public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBeanInfoAssembler {
/**
* Identifies a getter method in a JMX {@link Descriptor}.
*/
protected static final String FIELD_GET_METHOD = "getMethod";
/**
* Identifies a setter method in a JMX {@link Descriptor}.
*/
protected static final String FIELD_SET_METHOD = "setMethod";
/**
* Constant identifier for the role field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_ROLE = "role";
/**
* Constant identifier for the getter role field value in a JMX {@link Descriptor}.
*/
protected static final String ROLE_GETTER = "getter";
/**
* Constant identifier for the setter role field value in a JMX {@link Descriptor}.
*/
protected static final String ROLE_SETTER = "setter";
/**
* Identifies an operation (method) in a JMX {@link Descriptor}.
*/
protected static final String ROLE_OPERATION = "operation";
/**
* Constant identifier for the visibility field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_VISIBILITY = "visibility";
/**
* Lowest visibility, used for operations that correspond to
* accessors or mutators for attributes.
* @see #FIELD_VISIBILITY
*/
protected static final Integer ATTRIBUTE_OPERATION_VISIBILITY = new Integer(4);
/**
* Constant identifier for the class field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_CLASS = "class";
/**
* Constant identifier for the log field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_LOG = "log";
/**
* Constant identifier for the logfile field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_LOG_FILE = "logFile";
/**
* Constant identifier for the currency time limit field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_CURRENCY_TIME_LIMIT = "currencyTimeLimit";
/**
* Constant identifier for the default field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_DEFAULT = "default";
/**
* Constant identifier for the persistPolicy field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_PERSIST_POLICY = "persistPolicy";
/**
* Constant identifier for the persistPeriod field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_PERSIST_PERIOD = "persistPeriod";
/**
* Constant identifier for the persistLocation field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_PERSIST_LOCATION = "persistLocation";
/**
* Constant identifier for the persistName field in a JMX {@link Descriptor}.
*/
protected static final String FIELD_PERSIST_NAME = "persistName";
/**
* Default value for the JMX field "currencyTimeLimit".
*/
private Integer defaultCurrencyTimeLimit;
/**
* Indicates whether or not strict casing is being used for attributes.
*/
private boolean useStrictCasing = true;
private boolean exposeClassDescriptor = false;
/**
* Set the default for the JMX field "currencyTimeLimit".
* The default will usually indicate to never cache attribute values.
* <p>Default is none, not explicitly setting that field, as recommended by the
* JMX 1.2 specification. This should result in "never cache" behavior, always
* reading attribute values freshly (which corresponds to a "currencyTimeLimit"
* of <code>-1</code> in JMX 1.2).
* <p>However, some JMX implementations (that do not follow the JMX 1.2 spec
* in that respect) might require an explicit value to be set here to get
* "never cache" behavior: for example, JBoss 3.2.x.
* <p>Note that the "currencyTimeLimit" value can also be specified on a
* managed attribute or operation. The default value will apply if not
* overridden with a "currencyTimeLimit" value <code>>= 0</code> there:
* a metadata "currencyTimeLimit" value of <code>-1</code> indicates
* to use the default; a value of <code>0</code> indicates to "always cache"
* and will be translated to <code>Integer.MAX_VALUE</code>; a positive
* value indicates the number of cache seconds.
* @see org.springframework.jmx.export.metadata.AbstractJmxAttribute#setCurrencyTimeLimit
* @see #applyCurrencyTimeLimit(javax.management.Descriptor, int)
*/
public void setDefaultCurrencyTimeLimit(Integer defaultCurrencyTimeLimit) {
this.defaultCurrencyTimeLimit = defaultCurrencyTimeLimit;
}
/**
* Return default value for the JMX field "currencyTimeLimit", if any.
*/
protected Integer getDefaultCurrencyTimeLimit() {
return this.defaultCurrencyTimeLimit;
}
/**
* 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;
}
/**
* Return whether strict casing for attributes is enabled.
*/
protected boolean isUseStrictCasing() {
return useStrictCasing;
}
/**
* Set whether to expose the JMX descriptor field "class" for managed operations.
* Default is "false", letting the JMX implementation determine the actual class
* through reflection.
* <p>Set this property to <code>true</code> for JMX implementations that
* require the "class" field to be specified, for example WebLogic's.
* In that case, Spring will expose the target class name there, in case of
* a plain bean instance or a CGLIB proxy. When encountering a JDK dynamic
* proxy, the <b>first</b> interface implemented by the proxy will be specified.
* <p><b>WARNING:</b> Review your proxy definitions when exposing a JDK dynamic
* proxy through JMX, in particular with this property turned to <code>true</code>:
* the specified interface list should start with your management interface in
* this case, with all other interfaces following. In general, consider exposing
* your target bean directly or a CGLIB proxy for it instead.
* @see #getClassForDescriptor(Object)
*/
public void setExposeClassDescriptor(boolean exposeClassDescriptor) {
this.exposeClassDescriptor = exposeClassDescriptor;
}
/**
* Return whether to expose the JMX descriptor field "class" for managed operations.
*/
protected boolean isExposeClassDescriptor() {
return exposeClassDescriptor;
}
/**
* Iterate through all properties on the MBean class and gives subclasses
* the chance to vote on the inclusion of both the accessor and mutator.
* If a particular accessor or mutator is voted for inclusion, the appropriate
* metadata is assembled and passed to the subclass for descriptor population.
* @param managedBean the bean instance (might be an AOP proxy)
* @param beanKey the key associated with the MBean in the beans map
* of the <code>MBeanExporter</code>
* @return the attribute metadata
* @throws JMException in case of errors
* @see #populateAttributeDescriptor
*/
protected ModelMBeanAttributeInfo[] getAttributeInfo(Object managedBean, String beanKey) throws JMException {
PropertyDescriptor[] props = BeanUtils.getPropertyDescriptors(getClassToExpose(managedBean));
List infos = new ArrayList();
for (int i = 0; i < props.length; i++) {
Method getter = props[i].getReadMethod();
if (getter != null && getter.getDeclaringClass() == Object.class) {
continue;
}
if (getter != null && !includeReadAttribute(getter, beanKey)) {
getter = null;
}
Method setter = props[i].getWriteMethod();
if (setter != null && !includeWriteAttribute(setter, beanKey)) {
setter = null;
}
if (getter != null || setter != null) {
// If both getter and setter are null, then this does not need exposing.
String attrName = JmxUtils.getAttributeName(props[i], isUseStrictCasing());
String description = getAttributeDescription(props[i], beanKey);
ModelMBeanAttributeInfo info = new ModelMBeanAttributeInfo(attrName, description, getter, setter);
Descriptor desc = info.getDescriptor();
if (getter != null) {
desc.setField(FIELD_GET_METHOD, getter.getName());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -