Polish "Add AOT support for actuator"

See gh-31671
This commit is contained in:
Stephane Nicoll
2022-07-19 11:52:39 +02:00
parent 584b7d1343
commit 51cba6ec72
56 changed files with 387 additions and 939 deletions

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2012-2022 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
*
* https://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.aot;
import java.util.stream.Stream;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.support.RuntimeHintsUtils;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.core.annotation.SynthesizedAnnotation;
/**
* Registrar which registers the annotations needed for actuator support.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
public class ActuatorAnnotationsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
Stream.of(Endpoint.class, ReadOperation.class, WriteOperation.class, DeleteOperation.class,
EndpointExtension.class)
.forEach((annotationType) -> RuntimeHintsUtils.registerAnnotation(hints, annotationType));
// TODO: See https://github.com/spring-projects/spring-framework/issues/28767
Stream.of(Endpoint.class, EndpointExtension.class).forEach(
(annotationType) -> hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class));
}
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 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
*
* https://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.
*/
/**
* Support classes for actuator in AOT mode.
*/
package org.springframework.boot.actuate.aot;

View File

@@ -16,52 +16,43 @@
package org.springframework.boot.actuate.endpoint.annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.annotation.ReflectiveProcessor;
import org.springframework.aot.hint.annotation.SimpleReflectiveProcessor;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.Resource;
/**
* Processor which registers the annotated operation method and its return type for
* reflection.
* {@link ReflectiveProcessor} that registers the annotated operation method and its
* return type for reflection.
*
* @author Moritz Halbritter
* @author Stephane Nicoll
*/
class OperationReflectiveProcessor implements ReflectiveProcessor {
class OperationReflectiveProcessor extends SimpleReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
if (!(element instanceof Method method)) {
throw new IllegalArgumentException("This processor can only be invoked for annotated methods");
protected void registerMethodHint(ReflectionHints hints, Method method) {
super.registerMethodHint(hints, method);
Type returnType = extractReturnType(method);
if (returnType != null) {
registerReflectionHints(hints, returnType);
}
hints.registerMethod(method, (hint) -> hint.setModes(ExecutableMode.INVOKE));
registerReturnValueHints(hints, method);
}
private void registerReturnValueHints(ReflectionHints hints, Method method) {
private Type extractReturnType(Method method) {
ResolvableType returnType = ResolvableType.forMethodReturnType(method);
if (WebEndpointResponse.class.isAssignableFrom(method.getReturnType())) {
registerWebEndpointResponse(hints, returnType);
}
else {
registerReflectionHints(hints, returnType.getType());
}
}
private void registerWebEndpointResponse(ReflectionHints hints, ResolvableType returnType) {
ResolvableType genericParameter = returnType.getGeneric(0);
if (genericParameter.getRawClass() != null) {
registerReflectionHints(hints, genericParameter.getType());
return returnType.as(WebEndpointResponse.class).getGeneric(0).getType();
}
return returnType.getType();
}
private void registerReflectionHints(ReflectionHints hints, Type type) {

View File

@@ -22,8 +22,8 @@ import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
@@ -31,10 +31,8 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationArgumentResolver;
@@ -496,13 +494,11 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(WriteOperationHandler.class,
(hint) -> hint.withMethod("handle",
List.of(TypeReference.of(ServerWebExchange.class), TypeReference.of(Map.class)),
(method) -> method.withMode(ExecutableMode.INVOKE)));
hints.reflection().registerType(ReadOperationHandler.class,
(hint) -> hint.withMethod("handle", List.of(TypeReference.of(ServerWebExchange.class)),
(method) -> method.withMode(ExecutableMode.INVOKE)));
hints.reflection()
.registerMethod(Objects.requireNonNull(ReflectionUtils.findMethod(WriteOperationHandler.class,
"handle", ServerWebExchange.class, Map.class)))
.registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(ReadOperationHandler.class, "handle", ServerWebExchange.class)));
}
}

View File

@@ -18,13 +18,11 @@ package org.springframework.boot.actuate.endpoint.web.reactive;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
@@ -34,6 +32,7 @@ import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.reactive.HandlerMapping;
@@ -104,10 +103,8 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(WebFluxLinksHandler.class,
(hint) -> hint.onReachableType(TypeReference.of(WebFluxLinksHandler.class)).withMethod("links",
List.of(TypeReference.of(ServerWebExchange.class)),
(method) -> method.setModes(ExecutableMode.INVOKE)));
hints.reflection().registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(WebFluxLinksHandler.class, "links", ServerWebExchange.class)));
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}

View File

@@ -26,16 +26,15 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import reactor.core.publisher.Flux;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext;
@@ -487,10 +486,8 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(OperationHandler.class,
(hint) -> hint.withMethod("handle",
List.of(TypeReference.of(HttpServletRequest.class), TypeReference.of(Map.class)),
(method) -> method.withMode(ExecutableMode.INVOKE)));
hints.reflection().registerMethod(Objects.requireNonNull(
ReflectionUtils.findMethod(OperationHandler.class, "handle", HttpServletRequest.class, Map.class)));
}
}

View File

@@ -18,16 +18,14 @@ package org.springframework.boot.actuate.endpoint.web.servlet;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@@ -36,6 +34,7 @@ import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.aot.BindingReflectionHintsRegistrar;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.HandlerMapping;
@@ -101,11 +100,9 @@ public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerM
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(WebMvcLinksHandler.class,
(hint) -> hint.onReachableType(TypeReference.of(WebMvcLinksHandler.class)).withMethod("links",
List.of(TypeReference.of(HttpServletRequest.class),
TypeReference.of(HttpServletResponse.class)),
(method) -> method.setModes(ExecutableMode.INVOKE)));
hints.reflection()
.registerMethod(Objects.requireNonNull(ReflectionUtils.findMethod(WebMvcLinksHandler.class, "links",
HttpServletRequest.class, HttpServletResponse.class)));
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}

View File

@@ -17,17 +17,15 @@
package org.springframework.boot.actuate.metrics.cache;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import com.hazelcast.spring.cache.HazelcastCache;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.boot.actuate.metrics.cache.HazelcastCacheMeterBinderProvider.HazelcastCacheMeterBinderProviderRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.util.ReflectionUtils;
@@ -68,12 +66,16 @@ public class HazelcastCacheMeterBinderProvider implements CacheMeterBinderProvid
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(HazelcastCache.class, (hint) -> hint.withMethod("getNativeCache", List.of(),
(method) -> method.withMode(ExecutableMode.INVOKE)));
hints.reflection().registerType(HazelcastCacheMetrics.class,
(hint) -> hint.withConstructor(
List.of(TypeReference.of(Object.class), TypeReference.of(Iterable.class)),
(ctor) -> ctor.withMode(ExecutableMode.INVOKE)));
try {
hints.reflection()
.registerMethod(Objects
.requireNonNull(ReflectionUtils.findMethod(HazelcastCache.class, "getNativeCache")))
.registerConstructor(HazelcastCacheMetrics.class.getConstructor(Object.class, Iterable.class));
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException(ex);
}
}
}