INT-2628 Add ObjectNamingStrategy to IMBE

Allow customization of the generated ObjectName for the
Integration components.

JIRA: https://jira.springsource.org/browse/INT-2628

INT-2628 Polishing

- Address PR comments
- Rename `naming-strategy` to `object-naming-strategy` for consistency with `object-name-static-properties`
This commit is contained in:
Gary Russell
2013-11-01 16:46:08 +02:00
committed by Artem Bilan
parent 01ab48d664
commit 9849e2087d
9 changed files with 194 additions and 17 deletions

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Copyright 2002-2013 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.
@@ -33,7 +33,7 @@ import org.springframework.util.StringUtils;
/**
* Parser for the 'mbean-export' element of the integration JMX namespace.
*
*
* @author Mark Fisher
* @author Gary Russell
* @since 2.0
@@ -61,7 +61,8 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-name-static-properties");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "managed-components", "componentNamePatterns");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "shutdown-executor");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-naming-strategy", "namingStrategy");
builder.addPropertyValue("server", mbeanServer);
this.registerMBeanExporterHelper(parserContext.getRegistry());
}
@@ -70,7 +71,7 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser {
BeanDefinitionBuilder mBeanExporterHelperBuilder = BeanDefinitionBuilder.rootBeanDefinition(MBeanExporterHelper.class);
BeanDefinitionReaderUtils.registerWithGeneratedName(mBeanExporterHelperBuilder.getBeanDefinition(), registry);
}
private Object getMBeanServer(Element element, ParserContext parserContext) {
String mbeanServer = element.getAttribute("server");
if (StringUtils.hasText(mbeanServer)) {

View File

@@ -167,7 +167,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP
private final MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler(attributeSource);
private final MetadataNamingStrategy namingStrategy = new MetadataNamingStrategy(attributeSource);
private final MetadataNamingStrategy defaultNamingStrategy = new MetadataNamingStrategy(attributeSource);
private String[] componentNamePatterns = { "*" };
@@ -183,7 +183,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP
super();
// Shouldn't be necessary, but to be on the safe side...
setAutodetect(false);
setNamingStrategy(namingStrategy);
setNamingStrategy(defaultNamingStrategy);
setAssembler(assembler);
}
@@ -210,7 +210,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP
*/
public void setDefaultDomain(String domain) {
this.domain = domain;
this.namingStrategy.setDefaultDomain(domain);
this.defaultNamingStrategy.setDefaultDomain(domain);
}
public void setComponentNamePatterns(String[] componentNamePatterns) {

View File

@@ -204,6 +204,19 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="object-naming-strategy" use="optional">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.jmx.export.naming.ObjectNamingStrategy" />
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
An ObjectNamingStrategy to generate the MBean's ObjectName. See the reference documentation
for details of the default ObjectName. Also see 'object-name-static-properties'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

View File

@@ -18,11 +18,14 @@
<jmx:mbean-export id="integratioMbeanExporter"
server="mbs"
default-domain="tests.MBeanExpoerterParser"
object-name-static-properties="appProperties"/>
object-name-static-properties="appProperties"
object-naming-strategy="keyNamer"/>
<util:properties id="appProperties">
<prop key="foo">foo</prop>
<prop key="bar">bar</prop>
</util:properties>
<bean id="keyNamer" class="org.springframework.jmx.export.naming.KeyNamingStrategy" />
</beans>

View File

@@ -18,6 +18,7 @@ package org.springframework.integration.jmx.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Properties;
@@ -57,6 +58,7 @@ public class MBeanExporterParserTests {
assertTrue(properties.containsKey("foo"));
assertTrue(properties.containsKey("bar"));
assertEquals(server, exporter.getServer());
assertSame(context.getBean("keyNamer"), TestUtils.getPropertyValue(exporter, "namingStrategy"));
exporter.destroy();
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:jmx="http://www.springframework.org/schema/integration/jmx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jmx
http://www.springframework.org/schema/integration/jmx/spring-integration-jmx.xsd">
<jmx:mbean-export id="integrationMbeanExporter" server="mbs" default-domain="test.MBeanRegistration"
object-naming-strategy="namer" />
<bean id="namer" class="org.springframework.integration.jmx.config.MBeanRegistrationCustomNamingTests$Namer" />
<context:mbean-server id="mbs" />
<int:channel id="testChannel" />
<int:service-activator id="service" input-channel="testChannel" method="get">
<bean class="org.springframework.integration.jmx.config.MBeanRegistrationCustomNamingTests$Source"/>
</int:service-activator>
<int:logging-channel-adapter id="logger" channel="testChannel"/>
<int:chain id="chain" input-channel="chainin">
<int:transformer id="t1" expression="'foo'"/>
<int:filter id="f1" expression="true"/>
</int:chain>
</beans>

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2013 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Set;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jmx.export.naming.KeyNamingStrategy;
import org.springframework.jmx.export.naming.ObjectNamingStrategy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Dave Syer
* @author Gary Russell
* @since 3.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class MBeanRegistrationCustomNamingTests {
@Autowired
private MBeanServer server;
@Test
public void testHandlerMBeanRegistration() throws Exception {
Set<ObjectName> names = server.queryNames(new ObjectName("test.MBeanRegistration:type=Integration,componentType=MessageHandler,*"), null);
assertEquals(6, names.size());
assertTrue(names.contains(new ObjectName("test.MBeanRegistration:type=Integration,componentType=MessageHandler,name=chain,bean=endpoint")));
assertTrue(names.contains(new ObjectName("test.MBeanRegistration:type=Integration,componentType=MessageHandler,name=chain$child.t1,bean=handler")));
assertTrue(names.contains(new ObjectName("test.MBeanRegistration:type=Integration,componentType=MessageHandler,name=chain$child.f1,bean=handler")));
}
public static class Source {
public String get() {
return "foo";
}
}
public static class Namer implements ObjectNamingStrategy {
private final ObjectNamingStrategy realNamer = new KeyNamingStrategy();
@Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
String actualBeanKey = beanKey.replace("type=", "type=Integration,componentType=");
return realNamer.getObjectName(managedBean, actualBeanKey);
}
}
}

View File

@@ -366,6 +366,46 @@
</tbody>
</tgroup>
</table>
<para>
Custom elements can be appended to the object name by providing a reference to a
<classname>Properties</classname> object in the <code>object-name-static-properties</code> attribute.
</para>
<para>
Also, since <emphasis>Spring Integration 3.0</emphasis>, you can use a custom
<ulink url="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jmx/export/naming/ObjectNamingStrategy.html"
>ObjectNamingStrategy</ulink>
using the <code>object-naming-strategy</code> attribute. This permits greater control over the naming of the
MBeans. For example, to group all Integration MBeans under
an 'Integration' type. A simple custom naming strategy implementation might be:
</para>
<programlisting language="java"><![CDATA[public class Namer implements ObjectNamingStrategy {
private final ObjectNamingStrategy realNamer = new KeyNamingStrategy();
@Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
String actualBeanKey = beanKey.replace("type=", "type=Integration,componentType=");
return realNamer.getObjectName(managedBean, actualBeanKey);
}
}]]></programlisting>
<para>
The <code>beanKey</code> argument is a String containing the standard object name beginning with
the <code>default-domain</code> and including any additional static properties.
This example simply moves the standard <code>type</code> part to <code>componentType</code> and
sets the <code>type</code> to 'Integration',
enabling selection of all Integration MBeans in one query:
<code>"my.domain:type=Integration,*</code>. This also groups the beans under one tree entry under the
domain in tools like VisualVM.
</para>
<note>
The default naming strategy is a
<ulink url="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jmx/export/naming/MetadataNamingStrategy.html"
>MetadataNamingStrategy</ulink>. The exporter propagates the <code>default-domain</code> to that object to allow it
to generate a fallback object name if parsing of the bean key fails. If your custom naming strategy is a
<classname>MetadataNamingStrategy</classname> (or subclass), the exporter will <emphasis role="bold">not</emphasis>
propagate the <code>default-domain</code>; you will need to configure it on your strategy bean.
</note>
</section>
<section id="jmx-channel-features">

View File

@@ -63,12 +63,23 @@
<section id="3.0-jmx">
<title>JMX Support</title>
<para>
A new <code>&lt;int-jmx:tree-polling-channel-adapter/&gt;</code> is provided; this
adapter queries the JMX MBean tree and sends a message with a payload that is the
graph of objects that matches the query. By default the MBeans are mapped to
primitives and simple Objects like Map, List and arrays - permitting simple
transformation, for example, to JSON
<xref linkend="jmx"/>.
<itemizedlist>
<listitem>
A new <code>&lt;int-jmx:tree-polling-channel-adapter/&gt;</code> is provided; this
adapter queries the JMX MBean tree and sends a message with a payload that is the
graph of objects that matches the query. By default the MBeans are mapped to
primitives and simple Objects like Map, List and arrays - permitting simple
transformation, for example, to JSON.
</listitem>
<listitem>
The <classname>IntegrationMBeanExporter</classname> now allows the configuration of
a custom <classname>ObjectNamingStrategy</classname> using the <code>naming-strategy</code>
attribute.
</listitem>
</itemizedlist>
</para>
<para>
For more information, see <xref linkend="jmx"/>.
</para>
</section>
<section id="3.0-tail">