Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import javax.management.MBeanServer;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
Expand All @@ -26,7 +28,13 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.MBeanExportConfiguration;
import org.springframework.core.env.Environment;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
import org.springframework.jmx.export.annotation.AnnotationMBeanExporter;
import org.springframework.jmx.export.naming.ObjectNamingStrategy;
import org.springframework.jmx.support.MBeanServerFactoryBean;

/**
Expand All @@ -42,10 +50,33 @@
@ConditionalOnExpression("${spring.jmx.enabled:true}")
public class JmxAutoConfiguration {

@Configuration
@Autowired
private Environment environment;

@Autowired
private BeanFactory beanFactory;

@Autowired
private ObjectNamingStrategy namingStrategy;

@Bean
@ConditionalOnMissingBean(value = MBeanExporter.class, search = SearchStrategy.CURRENT)
@EnableMBeanExport(defaultDomain = "${spring.jmx.default_domain:}", server = "${spring.jmx.server:mbeanServer}")
public static class MBeanExport {
public AnnotationMBeanExporter mbeanExporter() {
// Re-use the @EnableMBeanExport configuration
MBeanExportConfiguration config = new MBeanExportConfiguration();
config.setEnvironment(this.environment);
config.setBeanFactory(this.beanFactory);
config.setImportMetadata(new StandardAnnotationMetadata(Empty.class));
// But add a custom naming strategy
AnnotationMBeanExporter exporter = config.mbeanExporter();
exporter.setNamingStrategy(this.namingStrategy);
return exporter;
}

@Bean
@ConditionalOnMissingBean(ObjectNamingStrategy.class)
public ParentAwareNamingStrategy objectNamingStrategy() {
return new ParentAwareNamingStrategy(new AnnotationJmxAttributeSource());
}

@Bean
Expand All @@ -56,4 +87,9 @@ public MBeanServerFactoryBean mbeanServer() {
return factory;
}

@EnableMBeanExport(defaultDomain = "${spring.jmx.default_domain:}", server = "${spring.jmx.server:mbeanServer}")
private static class Empty {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2012-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.boot.autoconfigure.jmx;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;
import org.springframework.util.ObjectUtils;

/**
* @author Dave Syer
* @since 1.1.1
*/
public class ParentAwareNamingStrategy extends MetadataNamingStrategy implements
ApplicationContextAware {

private ApplicationContext applicationContext;
private boolean ensureUniqueRuntimeObjectNames = false;

public ParentAwareNamingStrategy(JmxAttributeSource attributeSource) {
super(attributeSource);
}

/**
* @param ensureUniqueRuntimeObjectNames the ensureUniqueRuntimeObjectNames to set
*/
public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
}

@Override
public ObjectName getObjectName(Object managedBean, String beanKey)
throws MalformedObjectNameException {
StringBuilder builder = new StringBuilder(beanKey);
if (parentContextContainsSameBean(this.applicationContext, beanKey)) {
builder.append(",context="
+ ObjectUtils.getIdentityHexString(this.applicationContext));
}
if (this.ensureUniqueRuntimeObjectNames) {
builder.append(",identity=" + ObjectUtils.getIdentityHexString(managedBean));
}
ObjectName name = super.getObjectName(managedBean, beanKey);
return name;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}

private boolean parentContextContainsSameBean(ApplicationContext applicationContext,
String beanKey) {
if (applicationContext.getParent() != null) {
try {
this.applicationContext.getParent().getBean(beanKey);
return true;
}
catch (BeansException ex) {
return parentContextContainsSameBean(applicationContext.getParent(),
beanKey);
}
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.junit.Test;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.integration.support.channel.HeaderChannelRegistry;

Expand All @@ -29,15 +30,37 @@
*/
public class IntegrationAutoConfigurationTests {

private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

@Test
public void integrationIsAvailable() {
this.context.register(IntegrationAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(HeaderChannelRegistry.class));
this.context.close();
}

@Test
public void addJmxAuto() {
this.context.register(JmxAutoConfiguration.class,
IntegrationAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(HeaderChannelRegistry.class));
this.context.close();
}

@Test
public void parentContext() {
this.context.register(IntegrationAutoConfiguration.class);
this.context.refresh();
AnnotationConfigApplicationContext parent = this.context;
this.context = new AnnotationConfigApplicationContext();
this.context.setParent(parent);
this.context.register(IntegrationAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(HeaderChannelRegistry.class));
((ConfigurableApplicationContext) this.context.getParent()).close();
this.context.close();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -51,6 +52,9 @@ public class JmxAutoConfigurationTests {
public void tearDown() {
if (this.context != null) {
this.context.close();
if (this.context.getParent() != null) {
((ConfigurableApplicationContext) this.context.getParent()).close();
}
}
}

Expand Down Expand Up @@ -104,6 +108,18 @@ public void testDefaultDomainConfiguredOnMBeanExport() {
ReflectionTestUtils.getField(naming, "defaultDomain"));
}

@Test
public void testParentContext() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(JmxAutoConfiguration.class);
this.context.refresh();
AnnotationConfigApplicationContext parent = this.context;
this.context = new AnnotationConfigApplicationContext();
this.context.setParent(parent);
this.context.register(JmxAutoConfiguration.class);
this.context.refresh();
}

@Configuration
public static class TestConfiguration {

Expand Down
1 change: 1 addition & 0 deletions spring-boot-samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<module>spring-boot-sample-integration</module>
<module>spring-boot-sample-jetty</module>
<module>spring-boot-sample-liquibase</module>
<module>spring-boot-sample-parent-context</module>
<module>spring-boot-sample-profile</module>
<module>spring-boot-sample-secure</module>
<module>spring-boot-sample-servlet</module>
Expand Down
4 changes: 4 additions & 0 deletions spring-boot-samples/spring-boot-sample-integration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
package sample.integration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;

@ConfigurationProperties(prefix = "service", ignoreUnknownFields = false)
@ManagedResource
public class ServiceProperties {

private String greeting = "Hello";

@ManagedAttribute
public String getGreeting() {
return this.greeting;
}
Expand Down
48 changes: 48 additions & 0 deletions spring-boot-samples/spring-boot-sample-parent-context/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>1.1.1.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-parent-context</artifactId>
<name>spring-boot-sample-parent-context</name>
<description>Spring Boot Integration Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2012-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 sample.parent;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HelloWorldService {

@Autowired
private ServiceProperties configuration;

public String getHelloMessage(String name) {
return this.configuration.getGreeting() + " " + name;
}

}
Loading