SpringAop @Around执行两次的原因及解决

在使用AOP环绕通知做日志处理的时候,发现@Around方法执行了两次,虽然这里环绕通知本来就会执行两次,但是正常情况下是在切点方法前执行一次,切点方法后执行一次,但是实际情况却是,切点方法前执行两次,切点方法后执行两次。

文字不好理解,还是写一下代码:

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        logger.debug("==========Request log==========");
        long startTime = System.currentTimeMillis();
        Object ob = pjp.proceed();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //JSONObject ipInfo = JSONObject.fromObject(URLDecoder.decode(WebUtils.getCookie(request,"IP_INFO").getValue(),"utf-8"));
        //logger.debug("IP: {}", ipInfo.get("ip"));
        //logger.debug("CITY {}", ipInfo.get("city"));
        logger.debug("IP: {}", BlogUtil.getClientIpAddr(request));
        logger.debug("REQUEST_URL: {}", request.getRequestURL().toString());
        logger.debug("HTTP_METHOD: {}", request.getMethod());
        logger.debug("CLASS_METHOD: {}", pjp.getSignature().getDeclaringTypeName() + "."
                + pjp.getSignature().getName());
        //logger.info("参数 : " + Arrays.toString(pjp.getArgs()));
        logger.debug("USE_TIME: {}", System.currentTimeMillis() - startTime);
        logger.debug("==========Request log end==========");
        return ob;
    }

然后刷新一下页面,得到的日志如下:

可以看到,虽然只刷新了一次,但是却输出了两次日志,是不应该的。然后通过断点调试发现,是因为在Controller中使用了@ModelAttribute

@ModelAttribute
public void counter(Model model) {
    counter.setCount(counter.getCount() + 1);
    model.addAttribute("count", counter.getCount());
}

@ModelAttribute注解的方法会在Controller方法执行之前执行一次,并且我将它放在了Controller中,并且拦截的是所有Controller中的方法,

这样就导致了:

1、首先页面请求到Controller,执行@ModelAttribute标注的方法,此时会被AOP拦截到一次。

2、执行完@ModelAttribute标注的方法后,执行@RequestMapping标注的方法,又被AOP拦截到一次。

所以,会有两次日志输出。

解决办法:

1、将Controller中的@ModelAttribute方法,提取出来,放到@ControllerAdvice中。

2、对AOP拦截规则添加注解匹配,例如:

execution(public * com.blog.controller.*.*(..)) && (@annotation(org.springframework.web.bind.annotation.RequestMapping))
&& (@annotation(org.springframework.web.bind.annotation.RequestMapping

表明这样只会拦截RequestMappping标注的方法。

注意:

如果是一个方法a()调用同一个类中的方法b(),如果对方法a()做拦截的话,AOP只会拦截到a(),而不会拦截到b(),因为啊a()对b()的调用是通过this.b()调用的,而AOP正真执行的是生成的代理类,通过this自然无法拦截到方法b()了。

了解Spring @Around使用及注意

注意:

1、Spring 切面注解的顺序

  • @before
  • @Around( 要代理的方法执行在其中)
  • @AfterReturning
  • @after

2、没有@Around,则 要代理的方法执行 异常才会被@AfterThrowing捕获;

3、在@Around如何执行 要代理的方法执行

@Around("execution(* cn.com.xalead.spring.MeInterface.*(..)) || execution(* cn.com.xalead.spring.KingInterface.*(..))")
public Object test(ProceedingJoinPoint proceeding) {
    Object o = null;
    try {
        //执行
        o = proceeding.proceed(proceeding.getArgs());
    } catch (Throwable e) {
        e.printStackTrace();
    }
    return o;
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring AOP 切面@Around注解的用法说明

    @Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务. 比如我们想在执行controller中方法前打印出请求参数,并在方法执行结束后来打印出响应值,这个时候,我们就可以借助于@Around注解来实现: 再比如我们想在执行方法时动态修改参数值等 类似功能的注解还有@Before等等,用到了Spring AOP切面思想,Spring AOP常用于拦截器.事务.日志.权限验证等方面. 完整演示代码如下: 需要说明的是,在以下例子中,我们即可以只用@Around注解,并设置条件,

  • Spring AOP执行先后顺序实例详解

    这篇文章主要介绍了Spring AOP执行先后顺序实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 众所周知,spring声明式事务是基于AOP实现的,那么,如果我们在同一个方法自定义多个AOP,我们如何指定他们的执行顺序呢? 网上很多答案都是指定order,order越小越是最先执行,这种也不能算是错,但有些片面. 配置AOP执行顺序的三种方式: 通过实现org.springframework.core.Ordered接口 @Compo

  • 分析java 中AspectJ切面执行两次的原因

    分析java 中AspectJ切面执行两次的原因 背景 转眼之间,发现博客已经将近半年没更新了,甚是惭愧.话不多说,正如标题所言,最近在使用AspectJ的时候,发现拦截器(AOP切面)执行了两次了.我们知道,AspectJ是AOP的一种解决方案,本质上是通过代理类在目标方法执行通知(Advice),然后由代理类再去调用目标方法.所以,从这点讲,拦截器应该只会执行一次.但是在测试的时候发现拦截器执行了两次. 问题重现 既然问题已经明了,那么可以通过代码简单重现这个问题,从而更深层次分析到底是什么

  • 聊聊Spring AOP @Before @Around @After等advice的执行顺序

    用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before.@Around和@After等advice. 最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了AOP功能. 我使用到了@Before.@Around这两个advice.但在,使用过程中,却对它们的执行顺序并不清楚. 为了弄清楚在不同情况下,这些advice到底是以怎么样的一个顺序进行执行的,我作了个测试,在此将其记录下来,以供以后查看. 前提 对于AOP相关类(aspect.pointcut

  • spring AOP的Around增强实现方法分析

    本文实例讲述了spring AOP的Around增强实现方法.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml

  • SpringAop @Around执行两次的原因及解决

    在使用AOP环绕通知做日志处理的时候,发现@Around方法执行了两次,虽然这里环绕通知本来就会执行两次,但是正常情况下是在切点方法前执行一次,切点方法后执行一次,但是实际情况却是,切点方法前执行两次,切点方法后执行两次. 文字不好理解,还是写一下代码: @Around("logPointCut()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { logger.debug("======

  • vue监听路由变化时watch方法会执行多次的原因及解决

    目录 需求描述: 需求解析: 解决需求 问题解决 本人前端菜鸟一名,一直致力于不间断的生产管理后台的bug,并以此自勉自励.近几天接到一个需求,网上也搜了很多例子,但是没有从根本上解决.在这里记录一下我自己的解决的过程,这也是第一次在掘金发言,求轻虐. 需求描述: 有A.B两个页面,需要将A页面的orderId用路由传参的方式传入到B页面执行数据关联查询,然后显示在B页面 需求解析: 如果是你,你拿到这个需求,应该很容易想到在B页面对路由变化做watch,然后获取参数执行查询数据的方法完事. 解

  • 关于useEffect执行两次的问题及解决

    目录 useEffect执行两次问题 父组件里面 子组件里面 react使用useEffect及踩坑 useEffect 介绍 重要理解 useEffect常见跳坑 useEffect执行两次问题 在useEffect第二个参数变化的时候,需要在父组件里面更改这个值的地方加一个判断,如果有值则设置为空,else更新这个值.useEffect第二个值可以是表达式 父组件里面 //授权树展示     const handleRoleModalVisible = (RoleModelVisibel:

  • @PostConstruct在项目启动时被执行两次或多次的原因及分析

    @PostConstruct项目启动时被执行两次或多次 原因 是因为文件对@PostConstruct所在类扫描了两次! 首先排查,带有扫描包配置(context:component-scan)的同一spring文件,是否在web.xml配置中,初始化就执行的那种配置(比如context-param,init-param),被重复的配置了两遍. 然后在排查,web.xml中配置了初始化配置的多个spring文件是否都扫描了@PostConstruct所在类的所在包!常见SpringMVC文件的扫

  • jQuery通过ajax方法获取json数据不执行success的原因及解决方法

    1.jquery通过ajax方法获取json数据不执行success回调 问题描述:jquery通过ajax方法获取json数据不执行success回调方法 问题原因:json格式存在问题或不符合标准写法,导致总是执行error回调方法 解决方案:使json格式务必符合下述3个标准写法: 1)键名称:用双引号括起: 2)字符串:用双引号括起: 3)数字,布尔值不需要使用双引号括起 : 注意:一定是双括号! 2.jQuery中ajax使用json数据类型总是跳过success执行error语句 执

  • spring定时任务执行两次及tomcat部署缓慢问题的解决方法

    一.spring定时任务执行两次 问题重现和解析 最近使用quartz定时任务框架,结果发现开发环境执行无任何问题,部署到服务器上后,发现同一时间任务执行了多次.经过搜索发现是服务器上tomcat的配置文件出现了问题. 原来的配置文件--server.xml如下: <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

  • 解决nuxt页面中mounted、created、watch执行两遍的问题

    前言: 在开发中偶然检查Network请求的时候发现,在页面中created钩子函数中请求了一个接口,但是页面这个页面加载的时候,接口会连续请求两边,然后我就排查是否有其他地方调用了同样的接口,检查了好几遍后发现并没有,WTF,然后我在created中打印了一下,惊奇的发现...created会执行两次打印... WTF.WTF.WTF,小朋友你是否有很多问号???,然后试了下,不光created会执行两遍,mounted也行,就连watch里面监听的也会,握草(草是一种植物),此处省略我咔咔排

  • springboot 拦截器执行两次的解决方案

    springboot拦截器执行两次 原因是: org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error 也是一个controller路径为/error @Configuration public class MVCConfig extends WebMvcConfigurationSupport { //自定义的拦截器 @Bean public SecurityInterceptor g

  • Qt槽函数会被执行多次的问题原因及解决方法

    今天在项目中发现发送一次信号,槽函数被执行多次,如下: connect(pBtn, &QAbstractButton::clicked, this, &QtWidgetsApplication2::btnClicked); pBtn为按钮.上述代码在一个循环中被连接信号槽多次 ,单击一次pBtn按钮,槽函数QtWidgetsApplication2::btnClicked被响应了多次.我原以为connect会将上次连接的信号槽覆盖掉,看来这货是每次累加啊,即connect几次就发送几次.解

随机推荐