Java约束验证不适用于参数

我想使用java bean验证注释作为spring服务的参数。考虑以下服务:

public interface MyService {

    void methodA();


    void methodB(@NotBlank String param)
}

具有实现:

@Validated
public class MyServiceImpl implements MyService {

    @Override
    public void methodA() {
        String param = "";
        methodB(param)
    }

    @Override
    public void methodB(@NotBlank String param) {
        // some logic
    }
}

您能告诉我当传递的字符串为空时如何触发验证并引发约束异常吗?当我以这种方式致电服务时:

@Autowired
MyService myService;

myService.methodB("");

从另一个类调用 methodB 时,将按预期引发约束异常。

但是,当相同的 methodB 调用形式为 MethodA 时,不会引发异常。如果调用具有相同参数的相同方法,为什么不引发异常?

djdz123 回答:Java约束验证不适用于参数

除了其他答案以及您知道AOP代理存在的事实之外,让我仅指向the relevant chapter in Spring documentation,其中提到了您遇到的AOP代理的自调用问题:

public class Main {

    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());

        Pojo pojo = (Pojo) factory.getProxy();
        // this is a method call on the proxy!
        pojo.foo();
    }
}

fun main() {
    val factory = ProxyFactory(SimplePojo())
    factory.addInterface(Pojo::class.java)
    factory.addAdvice(RetryAdvice())

    val pojo = factory.proxy as Pojo
    // this is a method call on the proxy!
    pojo.foo()
}

这里要理解的关键是main(..)类的Main方法内部的客户端代码具有对代理的引用。这意味着该对象引用上的方法调用是代理上的调用。结果,代理可以委派给与该特定方法调用相关的所有拦截器(建议)。 但是,一旦调用最终到达目标对象(在这种情况下为引用SimplePojo),它可能对其自身进行的任何方法调用,例如this.bar()或{{1} },将针对this.foo()引用而不是代理进行调用。这具有重要意义。这意味着自调用不会导致与方法调用相关的建议得到执行的机会。

-https://docs.spring.io/spring/docs/5.2.3.RELEASE/spring-framework-reference/core.html#aop-understanding-aop-proxies

在下一段中,提出了两种解决方案(或者实际上是三种,但是在这种特殊情况下切换到AspectJ可能会很麻烦):

好的,那该怎么办?最佳方法(在这里宽松地使用术语“最佳”)是重构代码,以免发生自调用。这确实需要您做一些工作,但这是最好的,侵入性最小的方法。下一种方法绝对可怕,我们正要指出这一点,恰恰是因为它是如此可怕。您可以(对我们来说是痛苦的)将类中的逻辑完全绑定到Spring AOP,如以下示例所示:

this

这完全将您的代码耦合到Spring AOP,并且使类本身意识到在AOP上下文中使用它的事实,而AOP却无济于事。创建代理时,还需要一些其他配置,如以下示例所示:

public class SimplePojo implements Pojo {

    public void foo() {
        // this works,but... gah!
        ((Pojo) AopContext.currentProxy()).bar();
    }

    public void bar() {
        // some logic...
    }
}

class SimplePojo : Pojo {

    fun foo() {
        // this works,but... gah!
        (AopContext.currentProxy() as Pojo).bar()
    }

    fun bar() {
        // some logic...
    }
}

最后,必须注意,AspectJ并不是自调用问题,因为它不是基于代理的AOP框架。

-https://docs.spring.io/spring/docs/5.2.3.RELEASE/spring-framework-reference/core.html#aop-understanding-aop-proxies

,

当托管Bean调用另一个托管Bean时,将调用Spring验证。

但是,spring上下文没有意识到同一bean(即,内部bean而非内部bean)中的方法之间的调用,因此@Validation没有影响。

一个简单的解决方案是将包装器方法从类中移到实用程序方法中,例如:

public static void methodA(MyService myService) {
    myService.methodB("");
}
,

Spring中没有注释 @Validation 。我认为您的意思是 @Validated

为了验证参数,Spring使用CGLIB创建了一种代理。这是类似于Spring用于事务处理的机制。仅当从另一个类中调用您的类 MyServiceImpl 时,Spring才添加此代码,即,控制流跨越两个类之间的边界。当您从另一个类调用 methodB 时,Spring会添加验证代码。当您从同一类调用它时,Spring不会添加任何代码,因此不会触发任何验证。

本文链接:https://www.f2er.com/2711987.html

大家都在问