-
Notifications
You must be signed in to change notification settings - Fork 40.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add @ConditionalOnExposedEndpoint condition
Prior to this commit, Actuator `Endpoint` instantiations would be guarded by `@ConditionalOnEnabledEnpoint` condition annotations. This feature saves resources as disabled endpoints aren't unnecessarily instantiated. By default, only `"health"` and `"info"` endpoints are exposed over the web and all endpoints are exposed over JMX. As of gh-16090, JMX is now disabled by default. This is an opportunity to avoid instantiating endpoints if they won't be exposed at all, which is more likely due to the exposure defaults. This commit adds a new `@ConditionalOnExposedEndpoint` conditional annotation that checks the `Environment` for configuration properties under `"management.endpoints.web.exposure.*"` and `"management.endpoints.jmx.exposure.*"`. In the case of JMX, an additional check is perfomed, checking that JMX is enabled first. The rules implemented in the condition itself are following the ones described in `ExposeExcludePropertyEndpointFilter`. See gh-16093
- Loading branch information
Showing
5 changed files
with
594 additions
and
56 deletions.
There are no files selected for viewing
87 changes: 87 additions & 0 deletions
87
...ingframework/boot/actuate/autoconfigure/endpoint/condition/AbstractEndpointCondition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright 2012-2019 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.actuate.autoconfigure.endpoint.condition; | ||
|
||
import java.util.Map; | ||
|
||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; | ||
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; | ||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.ConditionContext; | ||
import org.springframework.core.annotation.AnnotatedElementUtils; | ||
import org.springframework.core.annotation.AnnotationAttributes; | ||
import org.springframework.core.type.AnnotatedTypeMetadata; | ||
import org.springframework.core.type.MethodMetadata; | ||
import org.springframework.util.Assert; | ||
import org.springframework.util.ClassUtils; | ||
|
||
/** | ||
* Base class for {@link Endpoint} related {@link SpringBootCondition} implementations. | ||
* | ||
* @author Stephane Nicoll | ||
* @author Andy Wilkinson | ||
* @author Phillip Webb | ||
*/ | ||
abstract class AbstractEndpointCondition extends SpringBootCondition { | ||
|
||
AnnotationAttributes getEndpointAttributes(Class<?> annotationClass, | ||
ConditionContext context, AnnotatedTypeMetadata metadata) { | ||
return getEndpointAttributes(getEndpointType(annotationClass, context, metadata)); | ||
} | ||
|
||
Class<?> getEndpointType(Class<?> annotationClass, ConditionContext context, | ||
AnnotatedTypeMetadata metadata) { | ||
Map<String, Object> attributes = metadata | ||
.getAnnotationAttributes(annotationClass.getName()); | ||
if (attributes != null && attributes.containsKey("endpoint")) { | ||
Class<?> target = (Class<?>) attributes.get("endpoint"); | ||
if (target != Void.class) { | ||
return target; | ||
} | ||
} | ||
Assert.state( | ||
metadata instanceof MethodMetadata | ||
&& metadata.isAnnotated(Bean.class.getName()), | ||
"EndpointCondition must be used on @Bean methods when the endpoint is not specified"); | ||
MethodMetadata methodMetadata = (MethodMetadata) metadata; | ||
try { | ||
return ClassUtils.forName(methodMetadata.getReturnTypeName(), | ||
context.getClassLoader()); | ||
} | ||
catch (Throwable ex) { | ||
throw new IllegalStateException("Failed to extract endpoint id for " | ||
+ methodMetadata.getDeclaringClassName() + "." | ||
+ methodMetadata.getMethodName(), ex); | ||
} | ||
} | ||
|
||
AnnotationAttributes getEndpointAttributes(Class<?> type) { | ||
AnnotationAttributes attributes = AnnotatedElementUtils | ||
.findMergedAnnotationAttributes(type, Endpoint.class, true, true); | ||
if (attributes != null) { | ||
return attributes; | ||
} | ||
attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type, | ||
EndpointExtension.class, false, true); | ||
Assert.state(attributes != null, | ||
"No endpoint is specified and the return type of the @Bean method is " | ||
+ "neither an @Endpoint, nor an @EndpointExtension"); | ||
return getEndpointAttributes(attributes.getClass("endpoint")); | ||
} | ||
|
||
} |
115 changes: 115 additions & 0 deletions
115
...framework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnExposedEndpoint.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
* Copyright 2012-2019 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.actuate.autoconfigure.endpoint.condition; | ||
|
||
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.boot.actuate.endpoint.annotation.Endpoint; | ||
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; | ||
import org.springframework.context.annotation.Conditional; | ||
import org.springframework.core.env.Environment; | ||
|
||
/** | ||
* {@link Conditional} that checks whether an endpoint is exposed or not. Matches | ||
* according to the endpoint exposure configuration {@link Environment} properties. This | ||
* is designed as a companion annotation to {@link ConditionalOnEnabledEndpoint}. | ||
* <p> | ||
* For a given {@link Endpoint}, the condition will match if: | ||
* <ul> | ||
* <li>{@code "management.endpoints.web.exposure.*"} expose this endpoint</li> | ||
* <li>or if JMX is enabled and {@code "management.endpoints.jmx.exposure.*"} expose this | ||
* endpoint</li> | ||
* <li>or if the application is running on {@link org.springframework.boot.cloud.CloudPlatform#CLOUD_FOUNDRY}</li> | ||
* </ul> | ||
* | ||
* When placed on a {@code @Bean} method, the endpoint defaults to the return type of the | ||
* factory method: | ||
* | ||
* <pre class="code"> | ||
* @Configuration | ||
* public class MyConfiguration { | ||
* | ||
* @ConditionalOnExposedEndpoint | ||
* @Bean | ||
* public MyEndpoint myEndpoint() { | ||
* ... | ||
* } | ||
* | ||
* }</pre> | ||
* <p> | ||
* It is also possible to use the same mechanism for extensions: | ||
* | ||
* <pre class="code"> | ||
* @Configuration | ||
* public class MyConfiguration { | ||
* | ||
* @ConditionalOnExposedEndpoint | ||
* @Bean | ||
* public MyEndpointWebExtension myEndpointWebExtension() { | ||
* ... | ||
* } | ||
* | ||
* }</pre> | ||
* <p> | ||
* In the sample above, {@code MyEndpointWebExtension} will be created if the endpoint is | ||
* enabled as defined by the rules above. {@code MyEndpointWebExtension} must be a regular | ||
* extension that refers to an endpoint, something like: | ||
* | ||
* <pre class="code"> | ||
* @EndpointWebExtension(endpoint = MyEndpoint.class) | ||
* public class MyEndpointWebExtension { | ||
* | ||
* }</pre> | ||
* <p> | ||
* Alternatively, the target endpoint can be manually specified for components that should | ||
* only be created when a given endpoint is enabled: | ||
* | ||
* <pre class="code"> | ||
* @Configuration | ||
* public class MyConfiguration { | ||
* | ||
* @ConditionalOnExposedEndpoint(endpoint = MyEndpoint.class) | ||
* @Bean | ||
* public MyComponent myComponent() { | ||
* ... | ||
* } | ||
* | ||
* }</pre> | ||
* | ||
* @author Brian Clozel | ||
* @since 2.2.0 | ||
* @see Endpoint | ||
* @see ConditionalOnEnabledEndpoint | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ ElementType.METHOD, ElementType.TYPE }) | ||
@Documented | ||
@Conditional(OnExposedEndpointCondition.class) | ||
public @interface ConditionalOnExposedEndpoint { | ||
|
||
/** | ||
* The endpoint type that should be checked. Inferred when the return type of the | ||
* {@code @Bean} method is either an {@link Endpoint} or an {@link EndpointExtension}. | ||
* @return the endpoint type to check | ||
*/ | ||
Class<?> endpoint() default Void.class; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.