使用AOP打印日志Controller和DubboService的请求参数和相应参数和响应时间

2023-05-16

撸了今年阿里、网易和美团的面试,我有一个重要发现.......>>> hot3.png

 前言:项目为了方便排查问题都会在请求的接口或者暴露的服务前后都会打上日志。这样就搬出了Spring核心功能AOP,前两天我问一年工作经验的javaer,AOP是干啥用的,他回答面向切面编程,打印日志用的。 其实AOP不仅仅为了只是为了打印日志,在声明式事务注解和缓存注解和锁注解和异步注解或者任务调度注解都是动态代理对象执行的,对于动态代理和静态代理或者没有接口使用cglib的实现原理抽空再写一篇。但是今天我们就用AOP来实现拦截所有Controller和DubboService打印日志,因为springmvc的拦截器不能拿到postBody的值。

package com.xxx.xxxx.common.aop;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Parameter;

/**
 * AOP拦截方法打印参数和返回参数
 *
 * @author wangnian
 */
@Aspect
@Component
public class LoggingAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 拦截所有controller包下的方法
     */
    @Pointcut("execution(* com.xxxx.xxx..controller..*.*(..))")
    private void controllerMethod() {
    }

    /**
     * 拦截dubbo服务所有的方法
     */
    @Pointcut("@within(org.apache.dubbo.config.annotation.Service)")
    public void DubboServiceMethod() {
    }

    @Around("DubboServiceMethod() || controllerMethod()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 所在的类.方法
        String msgInfo = "@AOP日志[" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "]";
        String requestStr = getRequestParam(joinPoint);
        logger.info(msgInfo + "start.输入参数:" + requestStr);
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
            result = joinPoint.proceed();
        } catch (Exception e) {
            //如果有异常继续抛
            throw e;
        } finally {
            long handleTime = System.currentTimeMillis() - startTime;
            String responseStr = result == null ? "无" : JSON.toJSONString(result);
            StringBuffer endString = new StringBuffer(100);
            endString.append(msgInfo).append("end.");
            endString.append("耗时(" + handleTime + "ms)");
            endString.append("输出参数:").append(responseStr);
            logger.info(endString.toString());
        }
        return result;
    }

    /**
     * 获取请求参数
     *
     * @param point
     * @return
     */
    private String getRequestParam(ProceedingJoinPoint point) {
        Object[] methodArgs = point.getArgs();
        Parameter[] parameters = ((MethodSignature) point.getSignature()).getMethod().getParameters();
        String requestStr;
        try {
            requestStr = logParam(parameters, methodArgs);
        } catch (Exception e) {
            requestStr = "获取参数失败";
        }
        return requestStr;
    }

    /**
     * 拼接请求参数
     *
     * @param paramsArgsName
     * @param paramsArgsValue
     * @return
     */
    private String logParam(Parameter[] paramsArgsName, Object[] paramsArgsValue) {
        if (ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)) {
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < paramsArgsValue.length; i++) {
            //参数名
            String name = paramsArgsName[i].getName();
            //参数值
            Object value = paramsArgsValue[i];
            buffer.append(name + "=");
            if (value instanceof String) {
                buffer.append(value + ",");
            } else {
                buffer.append(JSON.toJSONString(value) + ",");
            }
        }
        return buffer.toString();
    }
}

代码在这里了,没空整理理论,先用起来再深入把。

送一个springmvc的拦截器代码


/**
 * springMvc拦截器
 *
 * @author wangnian
 * @date 2019-03-04
 */
public class UrlInterceptor extends HandlerInterceptorAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(UrlInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        try {
            //如果是OPTIONS的请求,不要打印日志
            if (RequestMethod.OPTIONS.toString().equals(request.getMethod())) {
                return true;
            }
            LOGGER.info("请求地址:{},请求方式:{},请求的IP:{},User-Agent:{}", request.getRequestURL(), request.getMethod(), IpUtil.getRemoteIp(request), request.getHeader("User-Agent"));
            return true;
        } catch (Exception e) {
            LOGGER.error("请求拦截异常:{}", e);
            return false;
        }
    }
}  

博客地址:https://my.oschina.net/wangnian

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用AOP打印日志Controller和DubboService的请求参数和相应参数和响应时间 的相关文章

  • Objective-C 中面向方面的 HTTP 身份验证示例

    我正在寻找一些示例 技巧 建议以及一些用于实现 或查找其实现 面向方面的 HTTP 身份验证库的一般方向感 作为一些基础工作 我们构建了一个 iOS 库 该库为 HTTP 服务建立各种形式的身份验证 通过 Web 表单或本机模式窗口请求用户
  • 将 .js 控制器请求渲染为 html

    我有一个before filter在我的 Rails 应用程序中 将用户发送到login url如果他们在提交请求 以 html 或 js 格式 时注销 我想要我的format js产生相同的结果format html 在以下情况下使用 通
  • Symfony2 表单用数据预填充字段

    暂时假设该形式使用了一个虚构的Animal文档对象类来自ZooCollection只有两个属性 名称 和 颜色 symfony2 questions tagged symfony2 我正在寻找一个工作简单愚蠢的解决方案 to pre fil
  • MVC Api Action 和 System.Web.Http.AuthorizeAttribute - 如何获取发布参数?

    我有以下 API 控制器 public class TestController ApiController HttpPost APIAuthorizeAttribute public IQueryable
  • 使用 Spring 和 AspectJ 拦截私有方法

    我正在尝试使用 AspectJ 的加载时编织与 Spring Boot 和基于注释的配置在私有方法之前执行代码 并且我正在抓紧时间试图找出为什么我的方面没有被调用 我的简单方面如下 Aspect public class LoggingAs
  • asp.net mvc 按名称和区域查找控制器

    我的目标是从控制器的名称和区域中找到控制器 如果我当前的httpContext与待找到的控制器位于同一区域内 但是 我无法拨打电话ControllerFactory考虑面积 这是我的代码 public static ControllerBa
  • 我的应用程序中采用 MVVM 设计模式的控制器是什么

    我开发了一个 WPF 应用程序 我有一个继承自 Window 的主窗口 一个选项卡控件以及该选项卡控件中的许多选项卡项 这些选项卡控件继承自 UserControl 每个 tabitem 都有自己的 cs 文件 我在其中使用 C 编写所有业
  • 我如何确保 Spring roo 生成的方面是由依赖项目编织的?

    我有一个春天Roo多模块项目 我注意到在另一个项目中包含包含我的域模型的 jar 模块后 各个方面还没有被编织给我留下了没有任何可用的 getter setter 的域类 如何确保 Spring roo 生成的切面是由依赖项目编织的 EDI
  • Backbone.js 控制器中的默认路由?

    我想为我的backbone js 控制器设置默认路由 目前我是这样做的 class DealSearchController extends Backbone Controller routes list showListView phot
  • 如何在Spring-MVC方法中绑定抽象类的子类?

    给定 Spring MVC 控制器中的 保存 方法 RequestMapping value save public void save ModelAttribute MY KEY final MyModel myModel 拥有位于myM
  • 在 spring3 控制器上返回“ModelAndView”或“String”哪个更好

    ModelAndView的返回方式 RequestMapping value list method RequestMethod GET public ModelAndView list UserAuth UserAuth user Mod
  • 如何删除供应商代码插入的回调?

    我正在使用的 gem 插入了一个我想删除的 after save 回调 在我看来 从数组中删除符号比用猴子补丁解决问题更干净 如何访问回调数组 class UserSession lt Authlogic Session Base Don
  • 运行单元测试时如何禁用 PostSharp?

    我希望我的 nunit 测试不应用任何 PostSharp 方面 这样我就可以单独测试我的方法 这可以在测试夹具设置中以某种方式完成 还是只能在每个项目级别上完成 您可以在测试版本上设置 SkipPostSharp 标志 这样它就不会首先编
  • ASP.NET MVC 2 - POST 后 ViewData 为空

    我真的不知道在哪里寻找错误 情况 我有一个 ASPX 视图 其中包含一个表单和一些输入 当我单击 提交 按钮时 所有内容都会 POST 到我的一个 ASP NET MVC 操作 当我在那里设置断点时 它被正确命中 当我使用 FireBug
  • AOP 使用 around 来避免执行方法

    我在代码中使用 Spring AOP 来拦截某个方法的执行 我正在尝试做的一个简化示例如下 public void someMethod does something Around execution someMethod public v
  • AspectJ - 匹配具有通用参数的方法的切入点

    我有一个接受任何类型作为其参数的通用方法 例如 我想要一个切入点 它与仅以 String 类型作为参数的方法的调用相匹配 最终的要求是将建议执行的范围限制为 字符串 参数 这是我的通用类和方法 public class Param
  • MVC 模型在 OnExecuted 操作过滤器中为 null ...或者设置模型的更优雅的方式?

    我有一个 ActionFilter 它覆盖了 OnActionExecuted 方法 在 POST 操作中 filterContext Controller ViewData Model 始终为 null 我确实发现下面的文章似乎在说它不应
  • HK2 MethodInterceptor 与 Jersey 资源

    如何设置aopMethodInterceptor使用泽西岛资源 这是我尝试过的 如下this https hk2 java net 2 2 0 aop example html文档 第 1 步 拦截服务 public class MyInt
  • 横切关注点示例

    什么是一个很好的例子cross cutting concern 医疗记录示例维基百科 http en wikipedia org wiki Cross cutting concern页面对我来说似乎不完整 具体来说 从这个例子来看 为什么日
  • 有人有 Postsharp 制作经验吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi

随机推荐