spring boot 3 本机 graalvm - HandlerMethodArgumentResolver 不工作

问题描述 投票:0回答:1

我配置了一个自定义 HandlerMethodArgumentResolver,用于从请求标头获取一些参数,并将它们包装在自定义对象中,以作为参数注入到我的控制器中。

自定义的HandlerMethodArgumentResolver不在主项目中,而是在主应用程序导入的库中。 Pom 和组件扫描都可以,因为其他 Bean 和配置正在处理,没有问题。

在 JVM 上运行它一切正常,但是使用 GraalVM 将其编译为本机应用程序给我带来了麻烦,因为当我运行应用程序时,不会考虑自定义参数解析器,并且注入的自定义对象为 null在运行时。

这是代码。

public class HeaderMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(MyHeader.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        MyHeader header = MyHeaderExtractor.generateFrom(webRequest);

        // Makes Validated annotation working on my custom argument
        if (parameter.hasParameterAnnotation(Validated.class) || parameter.hasParameterAnnotation(Valid.class)) {
            // Validate header
            WebDataBinder binder = binderFactory.createBinder(webRequest, header, parameter.getParameterName());
            validateIfApplicable(binder, parameter);
            if (binder.getBindingResult().hasErrors()) {
                throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
            }
        }
        return header;
    }

    /**
     * Validate the model attribute if applicable.
     * <p>The default implementation checks for {@code @jakarta.validation.Valid},
     * Spring's {@link org.springframework.validation.annotation.Validated},
     * and custom annotations whose name starts with "Valid".
     * @param binder the DataBinder to be used
     * @param parameter the method parameter declaration
     * @see WebDataBinder#validate(Object...)
     * @see SmartValidator#validate(Object, Errors, Object...)
     */
    protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
        for (Annotation ann : parameter.getParameterAnnotations()) {
            Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
            if (validationHints != null) {
                binder.validate(validationHints);
                break;
            }
        }
    }
}

然后是让 Spring MVC 了解我的参数解析器的配置类。

@EnableWebMvc // Tried with and without EnableWebMvc
@Configuration(proxyBeanMethods = false)
public class HeaderMethodArgumentResolverConfiguration implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        // tried this
        resolvers.add(new HeaderMethodArgumentResolver());
        // and also this when created as a Bean
        resolvers.add(headerMethodArgumentResolver());
    }

    @Bean   // Tried with and without this method
    public HeaderMethodArgumentResolver headerMethodArgumentResolver() {
        return new HeaderMethodArgumentResolver();
    }

}

还有一个示例控制器。

@RestController
@RequestMapping("/api/my-resource")
@Slf4j
public class MyController {

    @PostMapping("/example")
    public MyResponseObject doSomething(
            @Validated({HeaderAsIWant.class}) MyHeader myHeader,
            @Validated @RequestBody MyRequestObject request) {
    }

}

我是否做错了什么,缺少某些配置,或者是与本机构建的错误/不兼容?

非常感谢大家的回复。

注 1:我从 /actuator/beans 调用中进行了检查,并且我确信 bean 已正确实例化。问题似乎是当请求到来时 Spring 不会调用方法解析器。

注 2:将自定义参数解析器从库移动到主项目可以解决问题。但这对我来说不是一个解决方案,因为我需要在多个微服务中使用此参数解析器,可能不需要复制粘贴它。

java spring-boot native graalvm
1个回答
0
投票

我终于弄清楚了如何让它工作,只需在配置 bean 上添加以下内容:

@RegisterReflectionForBinding({HeaderMethodArgumentResolverConfiguration.class})

这是完整的课程:

@Configuration(proxyBeanMethods = false)
@RegisterReflectionForBinding({HeaderMethodArgumentResolverConfiguration.class})
public class HeaderMethodArgumentResolverConfiguration implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new HeaderMethodArgumentResolver());
    }

}

可能,鉴于配置 bean 在库中,它需要注册反射信息以发现 addArgumentResolvers 方法或者它实现 WebMvcConfigurer (现在不能确定,但它可以工作!)

© www.soinside.com 2019 - 2024. All rights reserved.