spring 基于aop 实现日志输出 定义在controller层无效

发布于 2022-09-01 19:31:19 字数 2636 浏览 33 评论 0

业务场景:
目前在开发一个web后端的程序,提供基于spring mvc的restful的接口给手机端调用。由于接口对性能和效率的要求比较高,为了更好的分析问题,这边决定输出日志对接口调用情况,以及频率,做记录。
这边考虑基于spring的aop来实现日志切面编程,下面看代码:
切面类

@Aspect
public class CxxxAspect {

    /**
     * 定义一个切入点
     */
    @Pointcut("execution(* com..controller.*Controller.*Auth(..))")
    private void pointCutMethod() {
    }

    /**
     *  声明前置通知
     */
    @Before("pointCutMethod()")
    public void doBefore() {
        System.out.println("前置通知");
    }

    /**
     *  声明后置通知
     * @param result
     */
    @AfterReturning(pointcut = "pointCutMethod()", returning = "result")
    public void doAfterReturning(String result) {
        System.out.println("后置通知");
        System.out.println("---" + result + "---");
    }

    /**
     *  声明例外通知
     */
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        System.out.println("例外通知");
        System.out.println(e.getMessage());
    }

    /**
     *  声明最终通知
     */
    @After("pointCutMethod()")
    public void doAfter() {
        System.out.println("最终通知");
    }

    /**
     *  声明环绕通知
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("进入方法---环绕通知");
        Object o = pjp.proceed();
        System.out.println("退出方法---环绕通知");
        return o;
    }
}

目标类

@Controller
@RequestMapping(value="xxxx")
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CXXXController{

      
       @ResponseBody
       @RequestMapping(value="/xxxx",method=RequestMethod.POST)
       public void xxxAuth(HttpServletRequest request){
           
           //省略实际业务代码
           return result;
       }
}
       

配置文件信息(保护个人隐私类名全路径以xxxx代替)

<aop:aspectj-autoproxy proxy-target-class="true"/>  
    <bean id="caFaceAuthAspect" class="com.xxxxx.aspect.CxxxAspect"/>

通过main方法测试代码:

     ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
          context.start();
          CAAuthController con=(CXXXController)context.getBean(CXXXController.class);
          con.xxxAuth(null, null);

日志输出:

进入方法---环绕通知
前置通知
最终通知
例外通知
null

证明当前配置已经ok,测试效果达到预期。但是用tomcat启动时,通过http访问到controll时,并没有进入切面类,更别说通知方法了,请问这是什么情况。
我有一个模糊的假设就是,我在main方法里面是手动实实在在的用controll类去调用了方法,所以触发了通知的连接点条件,但是http访问时,通过spring的mvc分发,反射调用所以并没有触发连接点的条件。
不知道我的假设是否正确,或者有相关的大神还请不吝赐教。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝礼 2022-09-08 19:31:19

好了,经过各大论坛发帖,各大技术群求大神,终于找到了问题的原因:
1.是父子容器的问题
2.我的切面代码和连接点,通知都没有问题,问题出在了我的配置信息上面。
3.我将配置信息如下:

<aop:aspectj-autoproxy proxy-target-class="true"/>  
    <bean id="caFaceAuthAspect" class="com..aspect.CxxxAuthAspect"/>

将其配置在了spring-context.xml 核心配置文件中,该配置文件会被ContextLoaderListenerclass加在,Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在 ServletContext中,keyWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

而spring-mvc.xml是DispatcherServlet,可以同时配置多个,每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称

当spring加在父容器的时候就会去找切入点,但是这个时候切入的controller是在子容器中的,父容器是无法访问子容器,所以就拦截不到。
如果将上述的配置文件放到spring-mvc.xml中,那么问题就解决了。我已经测试通过啦。

邮友 2022-09-08 19:31:19

right 同样的问题解决了 谢谢。

別甾虛僞 2022-09-08 19:31:19

找了好久答案,原来在这里,赞

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文