Spring:@Validated和@Async不能一起工作

时间:2022-09-20 20:31:14

I'm trying to use @Validated and @Async in combination.

我正在尝试组合使用@Validated和@Async。

Edited: I want to validate an input object when a method of my service is called. But... nothing happens. My service method is never called. If I remove the @Async annoation from the service method, the validation work fine and the method body is execuded a ValidationContraintException is thrown as expected.

编辑:我想在调用我的服务方法时验证输入对象。但是......没有任何反应。我的服务方法永远不会被调用。如果我从服务方法中删除@Async annoation,验证工作正常并且执行方法体,则会按预期抛出ValidationContraintException。

The (partial) configuration:

(部分)配置:

@Configuration
@ComponentScan
@EnableAsync
public class MyConfiguration {

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }   
}

My service:

@Service
@Validated
public class MyService {

    @Async
    public void doSomethingAsync(@NotNull @Valid final MyBean myBean) {
        // ...
    }

}

A compoment that uses the service:

使用该服务的组件:

@Component
public class MyComponent {

    @Autowired
    protected MyService myService;

    public void doSomething(final MyBean myBean) {
        this.myService.doSomethingAsync(myBean); // returned without error
    }
}

Where is my mistake? What can I do to make it work?

我的错误在哪里?我能做些什么才能让它发挥作用?

Edit #1

At first I've forgotten to describe that I call my method with an invalid bean to force a validation error.

起初我忘了描述我用无效的bean调用我的方法来强制验证错误。

After some debugging I've found out that the AnnotationAsyncExecutionInterceptor is executed before the MethodValidationInterceptor. This explains the behaviour. If I call my method with an invalid bean, the bean validation is executed within the executor thread. The ValidationConstraintException never reaches my error handler in the main thread and the call of the method myService.doSomethingAsync(myBean) is leaved without any error.

经过一些调试后,我发现AnnotationAsyncExecutionInterceptor在MethodValidationInterceptor之前执行。这解释了这种行为。如果我使用无效的bean调用我的方法,则在执行程序线程中执行bean验证。 ValidationConstraintException永远不会到达主线程中的错误处理程序,并且方法调用myService.doSomethingAsync(myBean)没有任何错误。

But I'm confused about this. The apidocs of @EnableAsync decribes that the AsyncAnnotationBeanPostProcessor is executed after all other post processors:

但我对此感到困惑。 @EnableAsync的apidocs描述AsyncAnnotationBeanPostProcessor在所有其他后处理器之后执行:

Indicate the order in which the {@link org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor} should be applied. The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run after all other post-processors, so that it can add an advisor to existing proxies rather than double-proxy.

指示应该应用{@link org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor}的顺序。默认值为{@link Ordered#LOWEST_PRECEDENCE},以便在所有其他后处理器之后运行,以便它可以将顾问程序添加到现有代理而不是双代理。

So I would expect that the AnnotationAsyncExecutionInterceptor is executed after all other interceptors for my method.

所以我希望在我的方法的所有其他拦截器之后执行AnnotationAsyncExecutionInterceptor。

Edit #2

The dependency cglib:cglib:3.1 is already added as project dependency and @EnableAsync(proxyTargetClass = true) seem to have no effect.

依赖项cglib:cglib:3.1已作为项目依赖项添加,而@EnableAsync(proxyTargetClass = true)似乎无效。

Edit #3

I've played around with the order attribute of @EnableAsync and the MethodValidationPostProcessor.

我玩过@EnableAsync和MethodValidationPostProcessor的order属性。

If I set an order of Ordered.HIGHEST_PRECEDENCE to the MethodValidationPostProcessor, my service bean cannot be found for autowiring (for some reason), Ordered.HIGHEST_PRECEDENCE + 1 works.

如果我将Ordered.HIGHEST_PRECEDENCE的顺序设置为MethodValidationPostProcessor,则无法找到我的服务bean进行自动装配(由于某种原因),Ordered.HIGHEST_PRECEDENCE + 1有效。

@Configuration
@ComponentScan
@EnableAsync
public class MyConfiguration {

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        final MethodValidationPostProcessor processor = new MethodValidationPostProcessor();

        processor.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
        return processor;
    }   
}

With a debugger I can see, that the order of the post processors is as expected. The MethodValidationPostProcessor is now ordered before the AsyncAnnotationBeanPostProcessor. But this has absolutely no effect to the order of the method incerceptors of my method doSomethingAsync.

使用调试器,我可以看到,后处理器的顺序是预期的。现在,在AsyncAnnotationBeanPostProcessor之前对MethodValidationPostProcessor进行排序。但这对我的方法doSomethingAsync的方法incerceptors的顺序完全没有影响。

Edit #4

For the moment I just removed any @Async annoations from my code. Until now I don't have a solution. The problem still exists... :(

目前我刚从代码中删除了任何@Async annoations。直到现在我还没有解决方案。问题仍然存在...... :(

1 个解决方案

#1


0  

Both interceptors have the same order default value so the order in which they are invoked is not deterministic. In your case, the async annotation is processed first.

两个拦截器都具有相同的默认值,因此调用它们的顺序不确定。在您的情况下,首先处理异步注释。

You can fix that easily by providing an explicit order for your validation method, based on other interceptors you might have on your services, something like

您可以根据您的服务可能具有的其他拦截器,为您的验证方法提供明确的订单,从而轻松解决这个问题。

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
    processor.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
    return processor;
}   

You can also provide an order to @EnableAsync to make it explicit that you are relying to a certain order.

您还可以向@EnableAsync提供订单,以明确表示您依赖于某个订单。

#1


0  

Both interceptors have the same order default value so the order in which they are invoked is not deterministic. In your case, the async annotation is processed first.

两个拦截器都具有相同的默认值,因此调用它们的顺序不确定。在您的情况下,首先处理异步注释。

You can fix that easily by providing an explicit order for your validation method, based on other interceptors you might have on your services, something like

您可以根据您的服务可能具有的其他拦截器,为您的验证方法提供明确的订单,从而轻松解决这个问题。

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
    processor.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
    return processor;
}   

You can also provide an order to @EnableAsync to make it explicit that you are relying to a certain order.

您还可以向@EnableAsync提供订单,以明确表示您依赖于某个订单。