好的,这是另一个尝试。我不喜欢我最终不得不从两个替代实现中的任何一个复制方法体的事实。我得出的结论是,如果我将“策略”和“汇编程序”自定义类都设为“元数据”版本的子类,我可以减少这种复制。基本思想是,在检查类上是否存在“@ManagedResource”注释后,我可以调用超类方法,或者内联“非元数据”版本,在所有情况下,代码都比“元数据”版本。
在“策略”类的情况下,由于“非元数据”版本中的相关方法是公共的,我仍然可以创建“策略”类的本地实例并调用相关方法,而不是内联方法身体。
对于“汇编程序”类,我发现在“元数据”版本中我不需要复制任何方法的主体,但我发现我必须重写额外的方法,并且我确实必须在方法主体中进行复制“超级超类”中的一种方法,因为我无法直接访问它。结果类比我的第一次尝试要短一些,所以我想它会更好,即使有那些稍微粗糙的部分。
要完全清理它,必须将其集成到 Spring 中以实现最佳重构。它提供的功能似乎是一件好事,所以我会提交一张票至少要求这个,我会在票中发布这些课程。
在这个版本中,我将实现完全重构为“AnnotationOrDefaultMBeanExporter”类,然后我的实际应用程序特定类扩展了它(我不需要在这里展示)。
这是主要的出口商类:
package <package>;
import java.util.logging.Logger;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;
public class AnnotationOrDefaultMBeanExporter extends MBeanExporter {
protected static Logger logger = Logger.getLogger(AnnotationOrDefaultMBeanExporter.class.getName());
private AnnotationJmxAttributeSource annotationSource = new AnnotationJmxAttributeSource();
protected MetadataOrKeyNamingStrategy metadataOrKeyNamingStrategy = new MetadataOrKeyNamingStrategy(annotationSource);
protected MetadataOrSimpleReflectiveMBeanInfoAssembler metadataOrSimpleReflectiveMBeanInfoAssembler = new MetadataOrSimpleReflectiveMBeanInfoAssembler(annotationSource);
public AnnotationOrDefaultMBeanExporter() {
setNamingStrategy(metadataOrKeyNamingStrategy);
setAssembler(metadataOrSimpleReflectiveMBeanInfoAssembler);
setAutodetectMode(AUTODETECT_ALL);
}
/**
* Specify the default domain to be used for generating ObjectNames
* when no source-level metadata has been specified.
* <p>The default is to use the domain specified in the bean name
* (if the bean name follows the JMX ObjectName syntax); else,
* the package name of the managed bean class.
* @see MetadataNamingStrategy#setDefaultDomain
*/
public void setDefaultDomain(String defaultDomain) {
this.metadataOrKeyNamingStrategy.setDefaultDomain(defaultDomain);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
this.annotationSource.setBeanFactory(beanFactory);
}
}
接下来是“策略”类。这里有点棘手的是用抛出一个 RuntimeException() 来包装一个检查的异常。
package <package>;
import java.io.IOException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.springframework.aop.support.AopUtils;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
import org.springframework.jmx.export.naming.KeyNamingStrategy;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;
public class MetadataOrKeyNamingStrategy extends MetadataNamingStrategy {
private KeyNamingStrategy keyNamingStrategy = new KeyNamingStrategy();
public MetadataOrKeyNamingStrategy() { }
public MetadataOrKeyNamingStrategy(JmxAttributeSource attributeSource) {
super(attributeSource);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
try {
keyNamingStrategy.afterPropertiesSet();
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
@Override
public ObjectName getObjectName(Object managedBean, String beanKey)
throws MalformedObjectNameException {
Class<?> managedClass = AopUtils.getTargetClass(managedBean);
if (managedClass.getAnnotation(ManagedResource.class) != null)
return super.getObjectName(managedBean, beanKey);
return keyNamingStrategy.getObjectName(managedBean, beanKey);
}
}
这是“汇编程序”类:
package <package>;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import javax.management.Descriptor;
import org.springframework.aop.support.AopUtils;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
public class MetadataOrSimpleReflectiveMBeanInfoAssembler extends MetadataMBeanInfoAssembler {
public MetadataOrSimpleReflectiveMBeanInfoAssembler() { }
public MetadataOrSimpleReflectiveMBeanInfoAssembler(JmxAttributeSource attributeSource) {
super(attributeSource);
}
@Override
protected boolean includeReadAttribute(Method method, String beanKey) {
if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
return super.includeReadAttribute(method, beanKey);
return true;
}
@Override
protected boolean includeWriteAttribute(Method method, String beanKey) {
if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
return super.includeWriteAttribute(method, beanKey);
return true;
}
@Override
protected boolean includeOperation(Method method, String beanKey) {
if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
return super.includeOperation(method, beanKey);
return true;
}
@Override
protected String getDescription(Object managedBean, String beanKey) {
if (managedBean.getClass().getAnnotation(ManagedResource.class) != null)
return super.getDescription(managedBean, beanKey);
return superSuperGetDescription(managedBean, beanKey);
}
/** Copied from AbstractMBeanInfoAssembler.getDescription(), the super.superclass of this class, which can't be easily called. */
private String superSuperGetDescription(Object managedBean, String beanKey) {
String targetClassName = getTargetClass(managedBean).getName();
if (AopUtils.isAopProxy(managedBean)) {
return "Proxy for " + targetClassName;
}
return targetClassName;
}
@Override
protected String getAttributeDescription(PropertyDescriptor propertyDescriptor, String beanKey) {
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod != null && readMethod.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
return super.getAttributeDescription(propertyDescriptor, beanKey);
return propertyDescriptor.getDisplayName();
}
@Override
protected String getOperationDescription(Method method, String beanKey) {
if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
return super.getOperationDescription(method, beanKey);
return method.getName();
}
@Override
protected void populateAttributeDescriptor(Descriptor desc, Method getter, Method setter, String beanKey) {
Method methodToUse = getter;
if (methodToUse == null)
methodToUse = setter;
if (methodToUse != null) {
if (methodToUse.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
super.populateAttributeDescriptor(desc, getter, setter, beanKey);
else
applyDefaultCurrencyTimeLimit(desc);
}
else
applyDefaultCurrencyTimeLimit(desc);
}
@Override
protected void populateMBeanDescriptor(Descriptor descriptor, Object managedBean, String beanKey) {
if (managedBean.getClass().getAnnotation(ManagedResource.class) != null)
super.populateMBeanDescriptor(descriptor, managedBean, beanKey);
else
applyDefaultCurrencyTimeLimit(descriptor);
}
@Override
protected void populateOperationDescriptor(Descriptor desc, Method method, String beanKey) {
if (method != null) {
if (method.getClass().getAnnotation(ManagedResource.class) != null)
super.populateOperationDescriptor(desc, method, beanKey);
else
applyDefaultCurrencyTimeLimit(desc);
}
else
applyDefaultCurrencyTimeLimit(desc);
}
}