首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring和AOP:@Pointcuts只适用于Rest控制器,而不适用于普通Web控制器

Spring和AOP:@Pointcuts只适用于Rest控制器,而不适用于普通Web控制器
EN

Stack Overflow用户
提问于 2016-09-26 16:59:48
回答 1查看 2K关注 0票数 1

我正在web环境中使用Spring Framework 4.3.3。

我有一个@Controller,它通过一个Web Browser用于Web请求,该Web Browser使用如何依赖其他@Controller,但用于Rest目的。后来提到使用@Service等..。

这种关于“Web”使用“Rest”的方法是如何在使用Spring的内容协商中为Combining Data and Presentation Formats部分解释依赖关系的。在此之前,开发/测试和生产都很好。这是一种很有价值的方法。

注意到 Rest类被注释为@Controller,因为我使用ResponseEntity<?>@ResponseBody

问题在于AOP

关于它的基础设施我有:

代码语言:javascript
复制
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {

}

关于@Controller,我有以下两个类:

  • PersonaDeleteOneController with:
    • deleteOne(@PathVariable String id, Model model) for @GetMapping
    • deleteOne(@PathVariable String id, RedirectAttributes redirectAttributes) for @DeleteMapping

  • PersonaRestController
    • deleteOne(@PathVariable String id) for @DeleteMapping

这两个类在名为:

  • com.manuel.jordan.controller.persona

我有下面的@Pointcut

代码语言:javascript
复制
@Pointcut(value=
"execution(* com.manuel.jordan.controller.*.*Controller.deleteOne(String, ..)) 
&& args(id) && target(object)")
public void deleteOnePointcut(String id, Object object){}

@Pointcut用于以下建议:

代码语言:javascript
复制
@Before(value="ControllerPointcut.deleteOnePointcut(id, object)")
public void beforeAdviceDeleteOne(String id, Object object){
    logger.info("beforeAdviceDeleteOne - @Controller: {} - Method: deleteOne - id: {}", object.getClass().getSimpleName(), id);
}

当我执行Rest测试时,我可以通过打印以下模式的AOP + logging进行确认:

  • @Controller (Rest) -> @Service -> @Repository

在此之前,所有的工作都是如何期待的

当我执行Web测试时,我可以通过打印以下模式的AOP + logging进行确认:

  • @Controller (Rest) -> @Service -> @Repository

我需要或期望的是:

  • @Controller (Web) -> @Controller (Rest) -> @Service -> @Repository

有什么不对的吗?deleteOne签名对于它们的参数并不含糊。

同样的生产情况。

α

在这里,控制员:

代码语言:javascript
复制
@Controller
@RequestMapping(value="/personas")
public class PersonaDeleteOneController {

    private final PersonaRestController personaRestController;

    @Autowired
    public PersonaDeleteOneController(PersonaRestController personaRestController){
        this.personaRestController = personaRestController;
    }

    @GetMapping(value="/delete/{id}",
                produces=MediaType.TEXT_HTML_VALUE)
    public String deleteOne(@PathVariable String id, Model model){
        model.addAttribute(personaRestController.findOneById(id));
        model.addAttribute("root", "/personas/delete");
        return "persona/deleteOne";
    }

    @DeleteMapping(value="/delete/{id}",
                   produces=MediaType.TEXT_HTML_VALUE)
    public String deleteOne(@PathVariable String id, RedirectAttributes redirectAttributes){
        personaRestController.deleteOne(id);
        redirectAttributes.addFlashAttribute("message", "process.successful");
        return "redirect:/message";
    }

}

代码语言:javascript
复制
@Controller
@RequestMapping(value="/personas")
public class PersonaRestController {

    private final PersonaService personaService;

    @Autowired
    public PersonaRestController(PersonaService personaService){
        this.personaService = personaService;
    }

    @DeleteMapping(value="/{id}")
    public ResponseEntity<Void> deleteOne(@PathVariable String id){
        personaService.deleteOne(id);
        return ResponseEntity.noContent().build();
    }

    ....

如何看到,我没有使用this.来执行方法调用。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-29 03:51:46

似乎问题在您的pointcut定义中。您可能会注意到,您的通知方法只对具有一个参数的方法执行,因此这是因为您在切入点声明中指定了args(id)。如果删除args(id),它必须按照您的预期工作,但在这种情况下,必须使用一些解决方法来公开参数值。

我认为这是AspectJ的奇怪行为,因为像execution(* *.*(String, ..)) && args(arg) && target(t))这样的构造具有清晰的语义意义,可以捕获所有带有String第一个参数的方法,并将其公开给args。至少对于AspectJ开发人员来说,它可以是一个bug或特性。

要得到您想要的东西,可以使用joinPoint.getArgs()内部通知方法,如下所示:

代码语言:javascript
复制
@Pointcut(value=
"execution(* com.manuel.jordan.controller.*.*Controller.deleteOne(..)) && target(object)")
public void deleteOnePointcut(Object object){}

@Before(value="ControllerPointcut.deleteOnePointcut(object)")
public void beforeAdviceDeleteOne(JoinPoint jp, Object object){
    Object id = jp.getArgs()[0];
    logger.info("beforeAdviceDeleteOne - @Controller: {} - Method: deleteOne - id: {}", object.getClass().getSimpleName(), id);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39708410

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档