INT-3330 EnableIntegrationMBeanExport Annotation
JIRA: https://jira.spring.io/browse/INT-3330 INT-3330: Enable SpEL evaluation INT-3330: Polishing for `MBeanExporterHelper` INT-3330: Fix `errorChannel` early access INT-3330: Polishing according PR comments Polishing - copyrights, author, docs
This commit is contained in:
committed by
Gary Russell
parent
1d6e80ecd0
commit
97c270c0e2
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2014 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.integration.jmx.config;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.jmx.support.RegistrationPolicy;
|
||||
|
||||
/**
|
||||
* Enables default exporting for Spring Integration components in an existing application, as
|
||||
* well as well all {@code @ManagedResource} annotated beans.
|
||||
*
|
||||
* <p>The resulting {@link org.springframework.integration.monitor.IntegrationMBeanExporter}
|
||||
* bean is defined under the name {@code integrationMbeanExporter}. Alternatively, consider defining a
|
||||
* custom {@link org.springframework.integration.monitor.IntegrationMBeanExporter} bean explicitly.
|
||||
*
|
||||
* <p>This annotation is modeled after and functionally equivalent to Spring XML's
|
||||
* {@code <int-jmx:mbean-export/>} element.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(IntegrationMBeanExportConfiguration.class)
|
||||
public @interface EnableIntegrationMBeanExport {
|
||||
|
||||
/**
|
||||
* The default domain to use when generating JMX ObjectNames.
|
||||
* Supports property placeholders (e.g. {@code ${project.domain}).
|
||||
*/
|
||||
String defaultDomain() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the MBeanServer to which MBeans should be exported. Default is to
|
||||
* use the platform's default MBeanServer.
|
||||
* Supports property placeholders (e.g. {@code ${project.mbeanServer})
|
||||
* and SpEL expression (e.g. {@code #{mbeanServer}).
|
||||
*/
|
||||
String server() default "";
|
||||
|
||||
/**
|
||||
* The policy to use when attempting to register an MBean under an
|
||||
* {@link javax.management.ObjectName} that already exists. Defaults to
|
||||
* {@link org.springframework.jmx.support.RegistrationPolicy#FAIL_ON_EXISTING}.
|
||||
*/
|
||||
RegistrationPolicy registration() default RegistrationPolicy.FAIL_ON_EXISTING;
|
||||
|
||||
/**
|
||||
* List of simple patterns for component names to register (defaults to '*').
|
||||
* The pattern is applied to all components before they are registered, looking for a match on
|
||||
* the 'name' property of the ObjectName. A MessageChannel and a MessageHandler (for instance)
|
||||
* can share a name because they have a different type, so in that case they would either both
|
||||
* be included or both excluded.
|
||||
* Supports property placeholders (e.g. {@code ${managed.components}). Can be applied for each element.
|
||||
*/
|
||||
String[] managedComponents() default "*";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2014 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.integration.jmx.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.integration.monitor.IntegrationMBeanExporter;
|
||||
import org.springframework.jmx.support.RegistrationPolicy;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@code @Configuration} class that registers a {@link IntegrationMBeanExporter} bean.
|
||||
* <p/>
|
||||
* <p>This configuration class is automatically imported when using the
|
||||
* {@link EnableIntegrationMBeanExport} annotation. See its javadoc for complete usage details.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
@Configuration
|
||||
public class IntegrationMBeanExportConfiguration implements ImportAware, EnvironmentAware, BeanFactoryAware {
|
||||
|
||||
private static final String MBEAN_EXPORTER_NAME = "integrationMbeanExporter";
|
||||
|
||||
private AnnotationAttributes attributes;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private BeanExpressionResolver resolver = new StandardBeanExpressionResolver();
|
||||
|
||||
private BeanExpressionContext expressionContext;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
this.resolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
|
||||
this.expressionContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> map = importMetadata.getAnnotationAttributes(EnableIntegrationMBeanExport.class.getName());
|
||||
this.attributes = AnnotationAttributes.fromMap(map);
|
||||
Assert.notNull(this.attributes,
|
||||
"@EnableIntegrationMBeanExport is not present on importing class " + importMetadata.getClassName());
|
||||
}
|
||||
|
||||
@Bean(name = MBEAN_EXPORTER_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public IntegrationMBeanExporter mbeanExporter() {
|
||||
IntegrationMBeanExporter exporter = new IntegrationMBeanExporter();
|
||||
exporter.setRegistrationPolicy(this.attributes.<RegistrationPolicy>getEnum("registration"));
|
||||
setupDomain(exporter);
|
||||
setupServer(exporter);
|
||||
setupComponentNamePatterns(exporter);
|
||||
return exporter;
|
||||
}
|
||||
|
||||
private void setupDomain(IntegrationMBeanExporter exporter) {
|
||||
String defaultDomain = this.attributes.getString("defaultDomain");
|
||||
if (defaultDomain != null && this.environment != null) {
|
||||
defaultDomain = this.environment.resolvePlaceholders(defaultDomain);
|
||||
}
|
||||
if (StringUtils.hasText(defaultDomain)) {
|
||||
exporter.setDefaultDomain(defaultDomain);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupServer(IntegrationMBeanExporter exporter) {
|
||||
String server = this.attributes.getString("server");
|
||||
if (server != null && this.environment != null) {
|
||||
server = this.environment.resolvePlaceholders(server);
|
||||
}
|
||||
if (StringUtils.hasText(server)) {
|
||||
MBeanServer bean = null;
|
||||
if (server.startsWith("#{") && server.endsWith("}")) {
|
||||
bean = (MBeanServer) this.resolver.evaluate(server, this.expressionContext);
|
||||
}
|
||||
else {
|
||||
bean = this.beanFactory.getBean(server, MBeanServer.class);
|
||||
}
|
||||
exporter.setServer(bean);
|
||||
}
|
||||
else {
|
||||
exporter.setServer(MBeanServerFactory.createMBeanServer());
|
||||
}
|
||||
}
|
||||
|
||||
private void setupComponentNamePatterns(IntegrationMBeanExporter exporter) {
|
||||
List<String> patterns = new ArrayList<String>();
|
||||
String[] managedComponents = this.attributes.getStringArray("managedComponents");
|
||||
for (String managedComponent : managedComponents) {
|
||||
String pattern = this.environment.resolvePlaceholders(managedComponent);
|
||||
patterns.addAll(StringUtils.commaDelimitedListToSet(pattern));
|
||||
}
|
||||
exporter.setComponentNamePatterns(patterns.toArray(new String[patterns.size()]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package org.springframework.integration.jmx.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.integration.config.IntegrationConfigurationInitializer;
|
||||
import org.springframework.integration.monitor.IntegrationMBeanExporter;
|
||||
|
||||
@@ -37,11 +39,9 @@ public class JmxIntegrationConfigurationInitializer implements IntegrationConfig
|
||||
}
|
||||
|
||||
private void registerMBeanExporterHelperIfNecessary(ConfigurableListableBeanFactory beanFactory) {
|
||||
if (!beanFactory.getBeansOfType(IntegrationMBeanExporter.class, false, false).isEmpty()) {
|
||||
MBeanExporterHelper mBeanExporterHelper = new MBeanExporterHelper();
|
||||
mBeanExporterHelper.postProcessBeanFactory(beanFactory);
|
||||
beanFactory.registerSingleton(MBEAN_EXPORTER_HELPER_BEAN_NAME, mBeanExporterHelper);
|
||||
beanFactory.initializeBean(mBeanExporterHelper, MBEAN_EXPORTER_HELPER_BEAN_NAME);
|
||||
if (beanFactory.getBeanNamesForType(IntegrationMBeanExporter.class).length > 0) {
|
||||
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(MBEAN_EXPORTER_HELPER_BEAN_NAME,
|
||||
new RootBeanDefinition(MBeanExporterHelper.class));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -20,42 +20,66 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.type.StandardMethodMetadata;
|
||||
import org.springframework.integration.monitor.IntegrationMBeanExporter;
|
||||
import org.springframework.jmx.export.MBeanExporter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Most likely a temporary class mainly needed to address issue described in INT-2307.
|
||||
* It helps in eliminating conflicts when more than one MBeanExporter is present. It creates a list
|
||||
* of bean names that will be exported by the IntegrationMBeanExporter and merges it with the list
|
||||
* It helps in eliminating conflicts when more than one MBeanExporter is present. It creates a list
|
||||
* of bean names that will be exported by the IntegrationMBeanExporter and merges it with the list
|
||||
* of 'excludedBeans' of MBeanExporter so it will not attempt to export them again.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
class MBeanExporterHelper implements BeanFactoryPostProcessor,
|
||||
BeanPostProcessor, Ordered, BeanFactoryAware {
|
||||
class MBeanExporterHelper implements BeanPostProcessor, Ordered, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final static String EXCLUDED_BEANS_PROPERTY_NAME = "excludedBeans";
|
||||
|
||||
|
||||
private final static String SI_ROOT_PACKAGE = "org.springframework.integration.";
|
||||
|
||||
private final Set<String> siBeanNames = new HashSet<String>();
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
private volatile DefaultListableBeanFactory beanFactory;
|
||||
|
||||
private volatile boolean capturedAutoChannelCandidates;
|
||||
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
Assert.isInstanceOf(DefaultListableBeanFactory.class, beanFactory);
|
||||
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.beanFactory != null) {
|
||||
String[] beanNames = this.beanFactory.getBeanDefinitionNames();
|
||||
for (String beanName : beanNames) {
|
||||
BeanDefinition def = this.beanFactory.getBeanDefinition(beanName);
|
||||
String className = def.getBeanClassName();
|
||||
if (className == null && def.getSource() instanceof StandardMethodMetadata) {
|
||||
className = ((StandardMethodMetadata) def.getSource()).getIntrospectedMethod().getReturnType().getName();
|
||||
}
|
||||
if (StringUtils.hasText(className)){
|
||||
if (className.startsWith(SI_ROOT_PACKAGE) && !(className.endsWith(IntegrationMBeanExporter.class.getName()))){
|
||||
siBeanNames.add(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (!this.capturedAutoChannelCandidates && this.beanFactory != null) {
|
||||
Object autoCreateChannelCandidates = beanFactory.getBean("$autoCreateChannelCandidates");
|
||||
@@ -77,30 +101,18 @@ class MBeanExporterHelper implements BeanFactoryPostProcessor,
|
||||
}
|
||||
mbeDfa.setPropertyValue(EXCLUDED_BEANS_PROPERTY_NAME, siBeanNames);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
|
||||
for (String beanName : beanDefinitionNames) {
|
||||
BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
|
||||
|
||||
String className = bd.getBeanClassName();
|
||||
if (StringUtils.hasText(className)){
|
||||
if (className.startsWith(SI_ROOT_PACKAGE) && !(className.endsWith(IntegrationMBeanExporter.class.getName()))){
|
||||
siBeanNames.add(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user