001/* 002 * Copyright 2012-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.actuate.autoconfigure; 018 019import javax.management.MBeanServer; 020 021import com.fasterxml.jackson.databind.ObjectMapper; 022 023import org.springframework.beans.factory.ObjectProvider; 024import org.springframework.boot.actuate.audit.AuditEventRepository; 025import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration.JmxEnabledCondition; 026import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint; 027import org.springframework.boot.actuate.endpoint.Endpoint; 028import org.springframework.boot.actuate.endpoint.jmx.AuditEventsJmxEndpoint; 029import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter; 030import org.springframework.boot.autoconfigure.AutoConfigureAfter; 031import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 032import org.springframework.boot.autoconfigure.condition.ConditionMessage; 033import org.springframework.boot.autoconfigure.condition.ConditionOutcome; 034import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 035import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 036import org.springframework.boot.autoconfigure.condition.SpringBootCondition; 037import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; 038import org.springframework.boot.bind.RelaxedPropertyResolver; 039import org.springframework.boot.context.properties.EnableConfigurationProperties; 040import org.springframework.context.annotation.Bean; 041import org.springframework.context.annotation.ConditionContext; 042import org.springframework.context.annotation.Conditional; 043import org.springframework.context.annotation.Configuration; 044import org.springframework.core.type.AnnotatedTypeMetadata; 045import org.springframework.util.StringUtils; 046 047/** 048 * {@link EnableAutoConfiguration Auto-configuration} to enable JMX export for 049 * {@link Endpoint}s. 050 * 051 * @author Christian Dupuis 052 * @author Andy Wilkinson 053 */ 054@Configuration 055@Conditional(JmxEnabledCondition.class) 056@AutoConfigureAfter({ EndpointAutoConfiguration.class, JmxAutoConfiguration.class }) 057@EnableConfigurationProperties(EndpointMBeanExportProperties.class) 058public class EndpointMBeanExportAutoConfiguration { 059 060 private final EndpointMBeanExportProperties properties; 061 062 private final ObjectMapper objectMapper; 063 064 public EndpointMBeanExportAutoConfiguration(EndpointMBeanExportProperties properties, 065 ObjectProvider<ObjectMapper> objectMapper) { 066 this.properties = properties; 067 this.objectMapper = objectMapper.getIfAvailable(); 068 } 069 070 @Bean 071 public EndpointMBeanExporter endpointMBeanExporter(MBeanServer server) { 072 EndpointMBeanExporter mbeanExporter = new EndpointMBeanExporter( 073 this.objectMapper); 074 String domain = this.properties.getDomain(); 075 if (StringUtils.hasText(domain)) { 076 mbeanExporter.setDomain(domain); 077 } 078 mbeanExporter.setServer(server); 079 mbeanExporter.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames()); 080 mbeanExporter.setObjectNameStaticProperties(this.properties.getStaticNames()); 081 return mbeanExporter; 082 } 083 084 @Bean 085 @ConditionalOnMissingBean(MBeanServer.class) 086 public MBeanServer mbeanServer() { 087 return new JmxAutoConfiguration().mbeanServer(); 088 } 089 090 @Bean 091 @ConditionalOnBean(AuditEventRepository.class) 092 @ConditionalOnEnabledEndpoint("auditevents") 093 public AuditEventsJmxEndpoint auditEventsEndpoint( 094 AuditEventRepository auditEventRepository) { 095 return new AuditEventsJmxEndpoint(this.objectMapper, auditEventRepository); 096 } 097 098 /** 099 * Condition to check that spring.jmx and endpoints.jmx are enabled. 100 */ 101 static class JmxEnabledCondition extends SpringBootCondition { 102 103 @Override 104 public ConditionOutcome getMatchOutcome(ConditionContext context, 105 AnnotatedTypeMetadata metadata) { 106 boolean jmxEnabled = isEnabled(context, "spring.jmx."); 107 boolean jmxEndpointsEnabled = isEnabled(context, "endpoints.jmx."); 108 if (jmxEnabled && jmxEndpointsEnabled) { 109 return ConditionOutcome.match( 110 ConditionMessage.forCondition("JMX Enabled").found("properties") 111 .items("spring.jmx.enabled", "endpoints.jmx.enabled")); 112 } 113 return ConditionOutcome.noMatch(ConditionMessage.forCondition("JMX Enabled") 114 .because("spring.jmx.enabled or endpoints.jmx.enabled is not set")); 115 } 116 117 private boolean isEnabled(ConditionContext context, String prefix) { 118 RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( 119 context.getEnvironment(), prefix); 120 return resolver.getProperty("enabled", Boolean.class, true); 121 } 122 123 } 124 125}