[bs-138] Add @OnManagementContext for management beans
User adds @OnManagementContext to a bean or @Configuration and it should be included in the management context (if there is one) whether it is the main context or a child. Makes it easy to secure the management endpoints and keep the rest open (see actuator-ui-sample). [#50721675]pull/2/merge
parent
729cfe813b
commit
3ba5f56808
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.bootstrap.actuate.autoconfigure;
|
||||||
|
|
||||||
|
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.Conditional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bean with this annotation will only be instantiated in the management context,
|
||||||
|
* whether that is the current context or a child context. Using this feature makes it
|
||||||
|
* easy to have a single set of configuration beans for both contexts and be able to
|
||||||
|
* switch the management features to a child context externally. Very useful if (for
|
||||||
|
* instance) you want management endpoints but open, or differently secured public facing
|
||||||
|
* endpoints.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Conditional(OnManagementContextCondition.class)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||||
|
public @interface ConditionalOnManagementContext {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.bootstrap.actuate.autoconfigure;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.bootstrap.actuate.autoconfigure.ManagementAutoConfiguration.RememberManagementConfiguration;
|
||||||
|
import org.springframework.bootstrap.actuate.properties.ManagementServerProperties;
|
||||||
|
import org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration;
|
||||||
|
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||||
|
import org.springframework.bootstrap.properties.ServerProperties;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Condition;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.context.event.ContextClosedEvent;
|
||||||
|
import org.springframework.context.event.ContextRefreshedEvent;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Conditional(RememberManagementConfiguration.class)
|
||||||
|
@Import(ManagementEndpointsRegistration.class)
|
||||||
|
public class ManagementAutoConfiguration implements ApplicationContextAware {
|
||||||
|
|
||||||
|
public static final String MEMO_BEAN_NAME = ManagementAutoConfiguration.class
|
||||||
|
.getName() + ".MEMO";
|
||||||
|
|
||||||
|
private ApplicationContext parent;
|
||||||
|
private ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ServerProperties configuration = new ServerProperties();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ManagementServerProperties management = new ManagementServerProperties();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext)
|
||||||
|
throws BeansException {
|
||||||
|
this.parent = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ApplicationListener<ContextClosedEvent> managementContextClosedListener() {
|
||||||
|
return new ApplicationListener<ContextClosedEvent>() {
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(ContextClosedEvent event) {
|
||||||
|
if (event.getSource() != ManagementAutoConfiguration.this.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ManagementAutoConfiguration.this.context != null) {
|
||||||
|
ManagementAutoConfiguration.this.context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ApplicationListener<ContextRefreshedEvent> managementContextRefeshedListener() {
|
||||||
|
|
||||||
|
return new ApplicationListener<ContextRefreshedEvent>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||||
|
|
||||||
|
if (event.getSource() != ManagementAutoConfiguration.this.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ManagementAutoConfiguration.this.configuration.getPort() != ManagementAutoConfiguration.this.management
|
||||||
|
.getPort()) {
|
||||||
|
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||||
|
context.setParent(ManagementAutoConfiguration.this.parent);
|
||||||
|
context.setEnvironment((ConfigurableEnvironment) ManagementAutoConfiguration.this.parent
|
||||||
|
.getEnvironment());
|
||||||
|
context.register(assembleConfigClasses(ManagementAutoConfiguration.this.parent));
|
||||||
|
context.refresh();
|
||||||
|
ManagementAutoConfiguration.this.context = context;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class RememberManagementConfiguration implements Condition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
Environment environment = context.getEnvironment();
|
||||||
|
int serverPort = environment.getProperty("server.port", Integer.class, 8080);
|
||||||
|
int managementPort = environment.getProperty("management.port",
|
||||||
|
Integer.class, serverPort);
|
||||||
|
if (!context.getBeanFactory().containsSingleton(MEMO_BEAN_NAME)) {
|
||||||
|
context.getBeanFactory().registerSingleton(MEMO_BEAN_NAME,
|
||||||
|
managementPort > 0);
|
||||||
|
}
|
||||||
|
return managementPort > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<?>[] assembleConfigClasses(BeanFactory parent) {
|
||||||
|
|
||||||
|
// Some basic context configuration that all child context need
|
||||||
|
ArrayList<Class<?>> configs = new ArrayList<Class<?>>(Arrays.<Class<?>> asList(
|
||||||
|
EmbeddedContainerCustomizerConfiguration.class,
|
||||||
|
ManagementServerConfiguration.class, ErrorConfiguration.class));
|
||||||
|
|
||||||
|
String managementContextBeanName = OnManagementContextCondition.class.getName();
|
||||||
|
|
||||||
|
// Management context only beans pulled in from the deferred list in the parent
|
||||||
|
// context
|
||||||
|
if (parent.containsBean(managementContextBeanName)) {
|
||||||
|
String[] names = parent.getBean(managementContextBeanName, String[].class);
|
||||||
|
for (String name : names) {
|
||||||
|
try {
|
||||||
|
configs.add(ClassUtils.forName(name,
|
||||||
|
ManagementAutoConfiguration.this.parent.getClassLoader()));
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new BeanCreationException(managementContextBeanName,
|
||||||
|
"Class not found: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return configs.toArray(new Class<?>[configs.size()]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.bootstrap.actuate.autoconfigure;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.bootstrap.actuate.properties.ManagementServerProperties;
|
|
||||||
import org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration;
|
|
||||||
import org.springframework.bootstrap.context.annotation.ConditionalOnExpression;
|
|
||||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
|
||||||
import org.springframework.bootstrap.properties.ServerProperties;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ApplicationContextAware;
|
|
||||||
import org.springframework.context.ApplicationListener;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.context.event.ContextClosedEvent;
|
|
||||||
import org.springframework.context.event.ContextRefreshedEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Dave Syer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnExpression("${management.port:${server.port:8080}}>0")
|
|
||||||
public class ManagementConfiguration implements ApplicationContextAware {
|
|
||||||
|
|
||||||
private ApplicationContext parent;
|
|
||||||
private ConfigurableApplicationContext context;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ServerProperties configuration = new ServerProperties();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ManagementServerProperties management = new ManagementServerProperties();
|
|
||||||
|
|
||||||
@ConditionalOnExpression("${server.port:8080} == ${management.port:${server.port:8080}}")
|
|
||||||
@Configuration
|
|
||||||
@Import({ MetricsConfiguration.class, HealthConfiguration.class,
|
|
||||||
ShutdownConfiguration.class, TraceConfiguration.class })
|
|
||||||
public static class ManagementEndpointsConfiguration {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setApplicationContext(ApplicationContext applicationContext)
|
|
||||||
throws BeansException {
|
|
||||||
this.parent = applicationContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationListener<ContextClosedEvent> managementContextClosedListener() {
|
|
||||||
return new ApplicationListener<ContextClosedEvent>() {
|
|
||||||
@Override
|
|
||||||
public void onApplicationEvent(ContextClosedEvent event) {
|
|
||||||
if (event.getSource() != ManagementConfiguration.this.parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ManagementConfiguration.this.context != null) {
|
|
||||||
ManagementConfiguration.this.context.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationListener<ContextRefreshedEvent> managementContextRefeshedListener() {
|
|
||||||
return new ApplicationListener<ContextRefreshedEvent>() {
|
|
||||||
@Override
|
|
||||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
|
||||||
if (event.getSource() != ManagementConfiguration.this.parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ManagementConfiguration.this.configuration.getPort() != ManagementConfiguration.this.management
|
|
||||||
.getPort()) {
|
|
||||||
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext();
|
|
||||||
context.setParent(ManagementConfiguration.this.parent);
|
|
||||||
context.register(EmbeddedContainerCustomizerConfiguration.class,
|
|
||||||
ManagementServerConfiguration.class,
|
|
||||||
MetricsConfiguration.class, HealthConfiguration.class,
|
|
||||||
ShutdownConfiguration.class, TraceConfiguration.class);
|
|
||||||
context.refresh();
|
|
||||||
ManagementConfiguration.this.context = context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.bootstrap.actuate.autoconfigure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenient collector for all the management endpoints (stuff that goes in the
|
||||||
|
* management context whether it is a child context or not).
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnManagementContext
|
||||||
|
@Import({ MetricsConfiguration.class, HealthConfiguration.class,
|
||||||
|
ShutdownConfiguration.class, TraceConfiguration.class })
|
||||||
|
public class ManagementEndpointsRegistration {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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.bootstrap.actuate.autoconfigure;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.bootstrap.context.annotation.ConditionLogUtils;
|
||||||
|
import org.springframework.context.annotation.Condition;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A condition that can determine if the bean it applies to is in the management context
|
||||||
|
* (the application context with the management endpoints).
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
* @see ConditionalOnManagementContext
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class OnManagementContextCondition implements Condition {
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(OnManagementContextCondition.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
|
||||||
|
String checking = ConditionLogUtils.getPrefix(logger, metadata);
|
||||||
|
|
||||||
|
Environment environment = context.getEnvironment();
|
||||||
|
int serverPort = environment.getProperty("server.port", Integer.class, 8080);
|
||||||
|
int managementPort = environment.getProperty("management.port", Integer.class,
|
||||||
|
serverPort);
|
||||||
|
|
||||||
|
// If there is no management context, the decision is easy (match=false)
|
||||||
|
boolean managementEnabled = managementPort > 0;
|
||||||
|
|
||||||
|
// The management context is the same as the parent context
|
||||||
|
boolean managementContextInParent = serverPort == managementPort;
|
||||||
|
|
||||||
|
// The current context is a child context with a management server
|
||||||
|
boolean managementChildContext = context.getBeanFactory().getBeanNamesForType(
|
||||||
|
ManagementServerConfiguration.class).length > 0;
|
||||||
|
|
||||||
|
// The management auto configuration either hasn't been added yet or has been
|
||||||
|
// added to the context and it is enabled
|
||||||
|
boolean containsManagementBeans = !context.getBeanFactory().containsSingleton(
|
||||||
|
ManagementAutoConfiguration.MEMO_BEAN_NAME)
|
||||||
|
|| (Boolean) context.getBeanFactory().getSingleton(
|
||||||
|
ManagementAutoConfiguration.MEMO_BEAN_NAME);
|
||||||
|
|
||||||
|
boolean result = managementEnabled
|
||||||
|
&& ((managementContextInParent && containsManagementBeans) || managementChildContext);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
if (!managementEnabled) {
|
||||||
|
logger.debug(checking + "Management context is disabled");
|
||||||
|
} else {
|
||||||
|
logger.debug(checking + "Management context is in parent: "
|
||||||
|
+ managementContextInParent + " (management.port="
|
||||||
|
+ managementPort + ", server.port=" + serverPort + ")");
|
||||||
|
logger.debug(checking + "In management child context: "
|
||||||
|
+ managementChildContext);
|
||||||
|
logger.debug(checking + "In management parent context: "
|
||||||
|
+ containsManagementBeans);
|
||||||
|
logger.debug(checking + "Finished matching and result is matches="
|
||||||
|
+ result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result && metadata instanceof AnnotationMetadata) {
|
||||||
|
Collection<String> beanClasses = getManagementContextClasses(context
|
||||||
|
.getBeanFactory());
|
||||||
|
beanClasses.add(((AnnotationMetadata) metadata).getClassName());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<String> getManagementContextClasses(
|
||||||
|
ConfigurableListableBeanFactory beanFactory) {
|
||||||
|
String name = OnManagementContextCondition.class.getName();
|
||||||
|
if (!beanFactory.containsSingleton(name)) {
|
||||||
|
beanFactory.registerSingleton(name, new HashSet<String>());
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Collection<String> result = (Collection<String>) beanFactory.getSingleton(name);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,2 +1,4 @@
|
|||||||
org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\
|
org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\
|
||||||
org.springframework.bootstrap.actuate.autoconfigure.ActuatorAutoConfiguration
|
org.springframework.bootstrap.actuate.autoconfigure.ActuatorAutoConfiguration,\
|
||||||
|
org.springframework.bootstrap.actuate.autoconfigure.SecurityAutoConfiguration,\
|
||||||
|
org.springframework.bootstrap.actuate.autoconfigure.ManagementAutoConfiguration
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
<?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>
|
||||||
|
<groupId>org.springframework.bootstrap</groupId>
|
||||||
|
<artifactId>spring-bootstrap-samples</artifactId>
|
||||||
|
<version>0.5.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-bootstrap-actuator-ui-sample</artifactId>
|
||||||
|
<properties>
|
||||||
|
<m2eclipse.wtp.contextRoot>/</m2eclipse.wtp.contextRoot>
|
||||||
|
<start-class>org.springframework.bootstrap.sample.ui.UiBootstrapApplication</start-class>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>spring-bootstrap</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>spring-bootstrap-actuator</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.thymeleaf</groupId>
|
||||||
|
<artifactId>thymeleaf-spring3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-jdk14</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-javaconfig</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-exec-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,51 @@
|
|||||||
|
package org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.bootstrap.SpringApplication;
|
||||||
|
import org.springframework.bootstrap.actuate.autoconfigure.ConditionalOnManagementContext;
|
||||||
|
import org.springframework.bootstrap.actuate.autoconfigure.ManagementAutoConfiguration;
|
||||||
|
import org.springframework.bootstrap.actuate.autoconfigure.SecurityAutoConfiguration;
|
||||||
|
import org.springframework.bootstrap.context.annotation.ConditionalOnExpression;
|
||||||
|
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
|
||||||
|
ManagementAutoConfiguration.class })
|
||||||
|
@ComponentScan
|
||||||
|
@Controller
|
||||||
|
public class ActuatorUiBootstrapApplication {
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
public String home(Map<String, Object> model) {
|
||||||
|
model.put("message", "Hello World");
|
||||||
|
model.put("title", "Hello Home");
|
||||||
|
model.put("date", new Date());
|
||||||
|
return "home";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
SpringApplication.run(ActuatorUiBootstrapApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnExpression("${server.port:8080} != ${management.port:${server.port:8080}}")
|
||||||
|
@Import(ManagementAutoConfiguration.class)
|
||||||
|
protected static class ManagementConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnExpression("${server.port:8080} != ${management.port:${server.port:8080}}")
|
||||||
|
@ConditionalOnManagementContext
|
||||||
|
@Import(SecurityAutoConfiguration.class)
|
||||||
|
protected static class ManagementSecurityConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<title th:text="${title}">Title</title>
|
||||||
|
<link rel="stylesheet" th:href="@{/resources/css/bootstrap.min.css}"
|
||||||
|
href="../../resources/css/bootstrap.min.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar">
|
||||||
|
<div class="navbar-inner">
|
||||||
|
<a class="brand" href="http://www.thymeleaf.org"> Thymeleaf -
|
||||||
|
Plain </a>
|
||||||
|
<ul class="nav">
|
||||||
|
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 th:text="${title}">Title</h1>
|
||||||
|
<div th:text="${message}">Fake content</div>
|
||||||
|
<div id="created" th:text="${#dates.format(date)}">July 11,
|
||||||
|
2012 2:17:16 PM CDT</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,82 @@
|
|||||||
|
package org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.bootstrap.SpringApplication;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic integration tests for demo application.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ActuatorUiBootstrapApplicationTests {
|
||||||
|
|
||||||
|
private static ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void start() throws Exception {
|
||||||
|
Future<ConfigurableApplicationContext> future = Executors
|
||||||
|
.newSingleThreadExecutor().submit(
|
||||||
|
new Callable<ConfigurableApplicationContext>() {
|
||||||
|
@Override
|
||||||
|
public ConfigurableApplicationContext call() throws Exception {
|
||||||
|
return (ConfigurableApplicationContext) SpringApplication
|
||||||
|
.run(ActuatorUiBootstrapApplication.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
context = future.get(30, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void stop() {
|
||||||
|
if (context != null) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHome() throws Exception {
|
||||||
|
ResponseEntity<String> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:8080", String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertTrue("Wrong body (title doesn't match):\n" + entity.getBody(), entity
|
||||||
|
.getBody().contains("<title>Hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCss() throws Exception {
|
||||||
|
ResponseEntity<String> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:8080/css/bootstrap.min.css", String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody().contains("body"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestTemplate getRestTemplate() {
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleError(ClientHttpResponse response) throws IOException {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return restTemplate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.bootstrap.SpringApplication;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for separate management and main service ports.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ManagementServiceBootstrapApplicationTests {
|
||||||
|
|
||||||
|
private static ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
private static int port = 9000;
|
||||||
|
private static int managementPort = 9001;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void start() throws Exception {
|
||||||
|
final String[] args = new String[] { "--server.port=" + port,
|
||||||
|
"--management.port=" + managementPort, "--management.address=127.0.0.1" };
|
||||||
|
Future<ConfigurableApplicationContext> future = Executors
|
||||||
|
.newSingleThreadExecutor().submit(
|
||||||
|
new Callable<ConfigurableApplicationContext>() {
|
||||||
|
@Override
|
||||||
|
public ConfigurableApplicationContext call() throws Exception {
|
||||||
|
return (ConfigurableApplicationContext) SpringApplication
|
||||||
|
.run(ActuatorUiBootstrapApplication.class, args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
context = future.get(10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void stop() {
|
||||||
|
if (context != null) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHome() throws Exception {
|
||||||
|
ResponseEntity<String> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:" + port, String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMetrics() throws Exception {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
ResponseEntity<Map> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:" + managementPort + "/metrics", Map.class);
|
||||||
|
assertEquals(HttpStatus.UNAUTHORIZED, entity.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHealth() throws Exception {
|
||||||
|
ResponseEntity<String> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:" + managementPort + "/health", String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertEquals("ok", entity.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestTemplate getRestTemplate() {
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleError(ClientHttpResponse response) throws IOException {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return restTemplate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
handlers = java.util.logging.ConsoleHandler
|
||||||
|
.level = INFO
|
||||||
|
|
||||||
|
java.util.logging.ConsoleHandler.level = FINE
|
||||||
|
sun.net.www.protocol.http.HttpURLConnection.level = ALL
|
||||||
|
org.springframework.bootstrap.context.annotation.level = ALL
|
||||||
|
org.springframework.bootstrap.actuate.autoconfigure.level = ALL
|
Loading…
Reference in New Issue