Java Spring AOP自定义注释

Java Spring AOP自定义注释,java,spring,annotations,aop,Java,Spring,Annotations,Aop,我正在尝试实现自定义注释和方面,它将在验证之前将path变量插入请求体。 现在看起来是这样的… 验证不起作用的控制器示例 @PostMapping("/{domainCode}") @AddParameterToForm(pathVariable = "domainCode", form = "userAddForm") public ResponseEntity<UserDto> saveUserForDomain(@PathVariable(name="domainCode")

我正在尝试实现自定义注释和方面,它将在验证之前将path变量插入请求体。 现在看起来是这样的…

验证不起作用的控制器示例

@PostMapping("/{domainCode}")
@AddParameterToForm(pathVariable = "domainCode", form = "userAddForm")
public ResponseEntity<UserDto> saveUserForDomain(@PathVariable(name="domainCode") String domainCode, @RequestBody @Valid  final UserAddForm userAddForm, BindingResult results) {...}
@PostMapping(“/{domainCode}”)
@AddParameterToForm(pathVariable=“domainCode”,form=“userAddForm”)
公共响应属性saveUserForDomain(@PathVariable(name=“domainCode”)字符串domainCode,@RequestBody@Valid final UserAddForm UserAddForm,BindingResult结果){…}

将path变量添加到表单中起作用,但@Valid似乎不再起作用,问题可能在连接点表达式中。。。如何在验证之前执行建议,然后再进行验证?

在建议之前更改
@中的方法参数是行不通的。在调用
thisJoinPoint.continue()
之前,您应该使用
@Around
建议来更改参数。这是因为当调用
thisJoinPoint.getArgs()
时,您会得到基元类型参数的副本,您无法在before通知中操作原始参数。幸运的是,您希望在这种情况下操作对象类型,这就是它工作的原因。使用around建议将使您能够将全新的参数传递给方法,或者只操作原始对象,您可以自由选择

此外,您应该尽可能使用
args()
,以便将您感兴趣的方法参数绑定到通知参数,以便能够以非加密和类型安全的方式与它们交互。创建一个局部变量并给它赋值将不会影响同一类型的方法参数。为什么要这样做

如果这个解释对您来说不够全面,请随时提出后续问题。然后我也可以为您添加一些示例代码


问题编辑后更新:

在更仔细地检查了您的代码之后,除了我今天早些时候在您的问题下的评论中的评论之外,不考虑方面代码的内容,您的实际问题是在执行方法之前执行了由
@Valid
注释引起的验证检查。即,验证的不是方面完成其工作后的状态(填充目标对象中的成员字段),而是方面运行前的状态。这实际上与中讨论的问题相同,另请参见M.Deinum和我的建议如何解决:

  • 也许您想试试full,看看Spring AOP使用的
    call()
    切入点而不是隐式
    execution()
    切入点是否能解决问题。您将编织到调用代码(方法调用)中,而不是被调用方(方法执行)本身。这种情况很可能发生在执行验证之前

  • 一种更像Spring的解决方法是使用Spring拦截器(M.Deinum提到
    HandlerInterceptor
    )而不是方面。还有一个链接指向由其他人创建的


尽管如此,我仍然建议重构代码,以免在方法参数名或类成员名上使用反射和匹配字符串。我认为您还可以通过将方法参数上的切入点与
@RequestBody
@PathVariable
注释相匹配来摆脱自定义注释。

我更新了该特性(请参阅原始帖子),因此现在它适用于任何方法。。。我已经试过使用Around,但我的注释甚至不起作用,这与以前使用时不同。你能把示例添加到我的代码中,让我看看应该如何实现Around吗?我还尝试了大多数解决方案,比如添加EnableSpectJautoProxy(proxyTargetClass=true),更改为公共对象AddParameterToForm。。。然后返回proceedingJoinPoint.continue(),但似乎都不起作用…我已经用
@Valid
问题和可能的解决方案的信息更新了我的答案。天哪,我刚刚看了你的代码。您是否认真地通过反射匹配注释中编码的方法参数名称?这是缓慢的,不是类型安全的,而且在不破坏应用程序并且只在运行时注意到的情况下肯定不能安全地重构。除了最初的AOP问题,这个设计被打破了。别这样!请解释一下你到底想达到什么目的。我百分之百确信一定有更好的解决办法。这段代码太做作了,3个月后没有人会理解它,甚至你也不会。更糟糕的是:你还将注释参数与类中的字段名相匹配,例如
User
AddParameterToForm
。这是一场维护噩梦。不要依赖参数或字段名和反射。我还有一个问题:如果你已经在做反射了,匹配参数注释(如
@RequestBody
@PathVariable
)不是更好,而不是使用您自己的自定义注释对相同的信息进行冗余编码吗?是的,现在我想起来,这真的很糟糕,但至少是有效的。无论如何,我会尝试在没有自定义注释的情况下,使用过滤器或拦截器来解决这个问题。谢谢你的帮助:)
@PostMapping("/test/{username}")
@AddParameterToForm(pathVariable = "username", form = "user")
public String test(@PathVariable String username, @RequestBody User user) {
    return user.getUsername();
}
@PostMapping("/{domainCode}")
@AddParameterToForm(pathVariable = "domainCode", form = "userAddForm")
public ResponseEntity<UserDto> saveUserForDomain(@PathVariable(name="domainCode") String domainCode, @RequestBody @Valid  final UserAddForm userAddForm, BindingResult results) {...}