iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringAop日志找不到方法的处理
  • 130
分享到

SpringAop日志找不到方法的处理

2024-04-02 19:04:59 130人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

springaop日志找不到方法 错误截图: 显示没有找到该方法,于是我找到对应的类和对应的方法: 这里我用了反射来获取方法名和参数: 错误打印的结果显示方法名获取没有错误,于

springaop日志找不到方法

错误截图:

在这里插入图片描述

显示没有找到该方法,于是我找到对应的类和对应的方法:

在这里插入图片描述

这里我用了反射来获取方法名和参数:

在这里插入图片描述

错误打印的结果显示方法名获取没有错误,于是我查看参数的类型是否有错

结果一个都对不上…

int类型反射得到的class:

在这里插入图片描述

在这里插入图片描述

Integer反射得到的Class:

在这里插入图片描述

在这里插入图片描述

…终于知道之前错误里的Ljavexxxx是哪里来的了…

由于model是一个接口

在这里插入图片描述

model反射的Class得到的是他的子类org.springframework.validation.support.BindingAwareModelMap:

在这里插入图片描述

所以参数类型对不上号导致了错误的产生

解决方法:

将int类型的参数改为Integer(以后都写Integer,舍弃int!),将参数里的Model删去,将方法返回值改为ModeAndView,一样实现页面的跳转和参数的传递:

在这里插入图片描述

运行代码:

在这里插入图片描述

运行okkkk~

SpringBoot用SpringAOP实现日志记录功能

背景:

我需要在一个SpringBoot的项目中的每个controller加入一个日志记录,记录关于请求的一些信息。

代码类似于:


logger.info(request.getRequestUrl());

之类的。

代码不难,但由于Controller的数量不少,干起来也是体力活。所以想到了用Spring AOP来解决这个问题。

首先,在pom中加入SpringAOP的相关依赖:


<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

上一篇我们说到,如果要直接用@Aspect注解的话,要在spring的配置文件中加入


<aop:aspectj-autoproxy />

那么我们这里要不要在程序的主类中增加@EnableAspectJAutoProxy来启用呢? 实际并不需要,可以看下面关于AOP的默认配置属性,其中spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了


@EnableAspectJAutoProxy

好的也就是说,只要引入SpringAOP相关的jar包依赖,我们就可以开始相关的Aspet的编程了。

这里直接上代码,然后再做解释:

首先是包结构的图:

这里涉及到接收请求的Controller的包有两个,com.stuPayment.controller还有com.stuPayment.uiController

然后看我们的切面类WEBLogAspect类的代码:


package com.stuPayment.util;
import java.util.Arrays;
import javax.servlet.Http.httpservletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class WebLogAspect {    
    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);    
    @Pointcut("execution(public * com.stuPayment.controller..*.*(..))")//切入点描述 这个是controller包的切入点
    public void controllerLog(){}//签名,可以理解成这个切入点的一个名称
    
    @Pointcut("execution(public * com.stuPayment.uiController..*.*(..))")//切入点描述,这个是uiController包的切入点
    public void uiControllerLog(){}
    
    @Before("controllerLog() || uiControllerLog()") //在切入点的方法run之前要干的
    public void logBeforeController(JoinPoint joinPoint) {        
        
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是springMVC提供来获得请求的东西
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        
         // 记录下请求内容
        logger.info("################URL : " + request.getRequestURL().toString());
        logger.info("################HTTP_METHOD : " + request.getMethod());
        logger.info("################IP : " + request.getRemoteAddr());
        logger.info("################THE ARGS OF THE CONTROLLER : " + Arrays.toString(joinPoint.getArgs()));
        
        //下面这个getSignature().getDeclaringTypeName()是获取包+类名的   然后后面的joinPoint.getSignature.getName()获取了方法名
        logger.info("################CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        //logger.info("################TARGET: " + joinPoint.getTarget());//返回的是需要加强的目标类的对象
        //logger.info("################THIS: " + joinPoint.getThis());//返回的是经过加强后的代理类的对象
    }   
}

针对这个切面类,来展开说明@Aspect切面类的编程。

@Aspect和@Component

首先,这个@Aspect注释告诉Spring这是个切面类,然后@Compoment将转换成Spring容器中的bean或者是代理bean。 总之要写切面这两个注解一起用就是了。

既然是切面类,那么肯定是包含PointCut还有Advice两个要素的,下面对几个注解展开讲来看看在@Aspect中是怎么确定切入点(PointCut)和增强通知(Advice)的。

@PointCut

这个注解包含两部分,PointCut表达式和PointCut签名。表达式是拿来确定切入点的位置的,说白了就是通过一些规则来确定,哪些方法是要增强的,也就是要拦截哪些方法。

@PointCut(...........)括号里面那些就是表达式。这里的execution是其中的一种匹配方式,还有:

execution: 匹配连接点

within: 某个类里面

this: 指定AOP代理类的类型

target:指定目标对象的类型

args: 指定参数的类型

bean:指定特定的bean名称,可以使用通配符(Spring自带的)

@target: 带有指定注解的类型

@args: 指定运行时传的参数带有指定的注解

@within: 匹配使用指定注解的类

@annotation:指定方法所应用的注解

注意,由于是动态代理的实现方法,所以不是所有的方法都能拦截得下来,对于jdk代理只有public的方法才能拦截得下来,对于CGLIB只有public和protected的方法才能拦截。

这里我们主要介绍execution的匹配方法,因为大多数时候都会用这个来定义pointcut:


execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
            throws-pattern?)

execution(方法修饰符(可选) 返回类型 类路径 方法名 参数 异常模式(可选))

除了返回类型,方法名还有参数之外,其他都是可选的

ret-type-pattern:可以为*表示任何返回值,全路径的类名等.

name-pattern:指定方法名,*代表所以,set*,代表以set开头的所有方法.

parameters pattern:指定方法参数(声明的类型), ()匹配没有参数; (..)代表任意多个参数; (*)代表一个参数,但可以是任意型; (*,String)代表第一个参数为任何值,第二个为String类型。

下面给几个例子:

1)execution(public * *(..))——表示匹配所有public方法

2)execution(* set*(..))——表示所有以“set”开头的方法

3)execution(* com.xyz.service.AccountService.*(..))——表示匹配所有AccountService接口的方法

4)execution(* com.xyz.service.*.*(..))——表示匹配service包下所有的方法

5)execution(* com.xyz.service..*.*(..))——表示匹配service包和它的子包下的方法

然后其他的匹配法要用的时候再百度吧~

然后是@PointCut的第二个部分,签名signature,也就是代码中的


@Pointcut("execution(public * com.stuPayment.uiController..*.*(..))")//切入点描述,这个是uiController包的切入点
    public void uiControllerLog(){}

像方法定义的这个Public void uiControllerLog(){}这个看起来像是方法定义的东西,就是签名,签名没有实际用处,只是用来标记一个Pointcut,可以理解成这个切入点的一个记号。

@Before

这个是决定advice在切入点方法的什么地方执行的标签,这个注解的意思是在切入点方法执行之前执行我们定义的advice。


@Before("controllerLog() || uiControllerLog()") //在切入点的方法run之前要干的
    public void logBeforeController(JoinPoint joinPoint) {

@Before注解括号里面写的是一个切入点,这里看见切入点表达式可以用逻辑符号&&,||,!来描述。 括号里面也可以内置切点表达式,也就是直接写成:


@Before("execution(public * com.stuPayment.uiController..*.*(..))")

跟写成@Before("uiControllerLog()")的效果是一样的。

然后看到注解下面的方法,就是描述advice的,我们看到有个参数JoinPoint,这个东西代表着织入增强处理的连接点。JoinPoint包含了几个很有用的参数:

  • Object[] getArgs:返回目标方法的参数
  • Signature getSignature:返回目标方法的签名
  • Object getTarget:返回被织入增强处理的目标对象
  • Object getThis:返回AOP框架为目标对象生成的代理对象

除了注解@Around的方法外,其他都可以加这个JoinPoint作参数。@Around注解的方法的参数一定要是ProceedingJoinPoint,下面会介绍。

@After

这个注解就是在切入的方法运行完之后把我们的advice增强加进去。一样方法中可以添加JoinPoint。

@Around

这个注解可以简单地看作@Before和@After的结合。这个注解和其他的比比较特别,它的方法的参数一定要是ProceedingJoinPoint,这个对象是JoinPoint的子类。我们可以把这个看作是切入点的那个方法的替身,这个proceedingJoinPoint有个proceed()方法,相当于就是那切入点的那个方法执行,简单地说就是让目标方法执行,然后这个方法会返回一个对象,这个对象就是那个切入点所在位置的方法所返回的对象。

除了这个Proceed方法(很重要的方法),其他和那几个注解一样。

@AfterReturning

顾名思义,这个注解是在目标方法正常完成后把增强处理织入。这个注解可以指定两个属性(之前的三个注解后面的括号只写一个@PointCut表达式,也就是只有一个属性),一个是和其他注解一样的PointCut表达式,也就是描述该advice在哪个接入点被织入;然后还可以有个returning属性,表明可以在Advice的方法中有目标方法返回值的形参。


@AfterReturning(returning = "returnOb", pointcut = "controllerLog() || uiControllerLog()")
    public void doAfterReturning(JoinPoint joinPoint, Object returnOb) {
        System.out.println("##################### the return of the method is : " + returnOb);
    }

浏览器发出一个请求后,效果截图:

(这里是一个请求登录界面的请求,所以uicontroller返回一个String作为视图。)

@AfterThrowing

异常抛出增强,在异常抛出后织入的增强。有点像上面的@AfterReturning,这个注解也是有两个属性,pointcut和throwing。

用法也和刚刚的那个returning差不多:


@AfterThrowing(pointcut = "controllerLog() || uiControllerLog()", throwing = "ex")
public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",异常为:" + ex);
          
}

好了现在注解都介绍完了,这里还要提到上面用到的一个类:RequestContextHolder

比如说,有个需求需要在service中获得request和response,我们一般会(我就是)直接在controller那把request或response作为参数传到service,这就很不美观。后来知道,原来Springmvc提供了个很强大的类ReqeustContextHolder,通过他你就可以获得request和response什么的。


//下面两个方法在没有使用jsF的项目中是没有区别的
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//                                            RequestContextHolder.getRequestAttributes();
//从session里面获取对应的值
String str = (String) requestAttributes.getAttribute("name",RequestAttributes.SCOPE_SESSION);
 
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)requestAttributes).getResponse();

好了完成了这个切面的编程后,你就成功把日志功能切入到各个controller中了。看个效果图。

最后,再记录一下各个不同的advice的拦截顺序的问题。

情况一,只有一个Aspect类:

无异常:@Around(proceed()之前的部分) → @Before → 方法执行 → @Around(proceed()之后的部分) → @After → @AfterReturning

有异常:@Around(proceed(之前的部分)) → @Before → 扔异常ing → @After → @AfterThrowing (大概是因为方法没有跑完抛了异常,没有正确返回所有@Around的proceed()之后的部分和@AfterReturning两个注解的加强没有能够织入)

情况二,同一个方法有多个@Aspect类拦截:

单个Aspect肯定是和只有一个Aspect的时候的情况是一样的,但不同的Aspect里面的advice的顺序呢??答案是不一定,像是线程一样,没有谁先谁后,除非你给他们分配优先级,同样地,在这里你也可以为@Aspect分配优先级,这样就可以决定谁先谁后了。

优先级有两种方式:

  • 实现org.springframework.core.Ordered接口,实现它的getOrder()方法
  • 给aspect添加@Order注解,该注解全称为:org.springframework.core.annotation.Order

不管是哪种,都是order的值越小越先执行:


@Order(5)
@Component
@Aspect
public class Aspect1 {
    // ...
}
@Order(6)
@Component
@Aspect
public class Aspect2 {
    // ...
}

这样Aspect1就永远比Aspect2先执行了。

注意点:

  • 如果在同一个 aspect 类中,针对同一个 pointcut,定义了两个相同的 advice(比如,定义了两个 @Before),那么这两个 advice 的执行顺序是无法确定的,哪怕你给这两个 advice 添加了 @Order 这个注解,也不行。这点切记。
  • 对于@Around这个advice,不管它有没有返回值,但是必须要方法内部,调用一下 pjp.proceed();否则,Controller 中的接口将没有机会被执行,从而也导致了 @Before这个advice不会被触发。

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

--结束END--

本文标题: SpringAop日志找不到方法的处理

本文链接: https://www.lsjlt.com/news/128734.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringAop日志找不到方法的处理
    SpringAop日志找不到方法 错误截图: 显示没有找到该方法,于是我找到对应的类和对应的方法: 这里我用了反射来获取方法名和参数: 错误打印的结果显示方法名获取没有错误,于...
    99+
    2024-04-02
  • windows7找不到wifi网卡处理方法
    假如咱们在windows7电脑中找不到wifi网卡,可能是连接呈现错误导致的,这时候咱们翻开电脑的控制面板,然后点击网络和同享中心,找到WLAN选项,接着点击确诊,等待系统完结确诊并修复即可,以下便是windows7找不到wifi网卡处理方...
    99+
    2023-07-12
  • Springboot项目处理日志的方法
    本篇内容主要讲解“Springboot项目处理日志的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Springboot项目处理日志的方法”吧!如上图,每天会生成一个新的日志文件,然后日志进行...
    99+
    2023-06-20
  • MySQL binlog日志乱码的处理方法
    这篇文章主要讲解了“MySQL binlog日志乱码的处理方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“MySQL binlog日志乱码的处理方法”吧!...
    99+
    2024-04-02
  • SQL代理错误日志处理方法
    这篇文章主要讲解了“SQL代理错误日志处理方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SQL代理错误日志处理方法”吧!SQL Server代理是所有实时数据库的核心。代理有很多不明显的...
    99+
    2023-06-20
  • ASP日志处理:Spring和Django框架有何不同的方法?
    在Web开发中,日志处理是一个非常重要的环节,因为它可以帮助开发人员快速发现和解决问题。在ASP开发中,日志处理也是必不可少的一环。但是,不同的框架对于日志处理的方式可能会有所不同。在本文中,我们将比较Spring和Django框架对于A...
    99+
    2023-06-27
    日志 spring django
  • SpringBoot找不到映射文件的处理方式
    目录SpringBoot找不到映射文件SpringBoot映射本地文件到URL路径1、使用配置类2、在配置文件yml中配置SpringBoot找不到映射文件 org.apache.i...
    99+
    2024-04-02
  • 找不到mysql.h的解决方法
    小编给大家分享一下找不到mysql.h的解决方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧! 找不...
    99+
    2024-04-02
  • win11找不到gpedit.msc如何处理
    在Windows 11中,gpedit.msc(组策略编辑器)并不直接包含在家庭版或个人版中,只有专业版或企业版中才默认安装。但是,...
    99+
    2023-09-01
    win11
  • rocketmq client 日志的问题处理方式
    目录rocketmq client 日志的问题处理方式一: rocketmq启用slf4j【推荐】方式二: 更改默认rocketmq路劲和级别RocketMQ 自己加载日志,以及特性...
    99+
    2024-04-02
  • 找不到wp config.php的解决方法
    这篇文章主要介绍找不到wp config.php的解决方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!找不到wp config.php的解决办法:1、添加一个“wp-config.php”文件;然后重启一下web服...
    99+
    2023-06-15
  • php domdocument找不到的解决方法
    本篇内容介绍了“php domdocument找不到的解决方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!php domdocument找...
    99+
    2023-06-20
  • Springboot项目优雅地处理日志的方法详解
    如上图,每天会生成一个新的日志文件,然后日志进行分类,我这里只对error和info进行分类。 怎么做呢? 首先,在resource目录创建一个新文件,取名logback-spr...
    99+
    2024-04-02
  • centos修改dhcpd日志实现不记入系统日志的方法
    小编给大家分享一下centos修改dhcpd日志实现不记入系统日志的方法,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!编辑dhcp服务配置文件vim /etc/dhcp/dhcpd.conf   在末尾...
    99+
    2023-06-10
  • windows找不到文件怎么处理
    当Windows找不到文件时,可以尝试以下几种处理方法:1. 检查文件路径:确认文件路径是否正确,包括文件名拼写和大小写字母是否匹配...
    99+
    2023-09-11
    windows
  • SQL Server代理:理解SQL代理错误日志处理方法
    SQL Server代理是所有实时数据库的核心。代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的。这系列文章会通俗介绍它的很多用法。 如我们在这个系列的前几篇...
    99+
    2024-04-02
  • 您是否正在寻找一种更好的方式来处理 HTTP 日志?
    在当今的互联网时代,HTTP 日志已经成为了网站管理员和开发人员必须面对的一个重要问题。然而,由于 HTTP 日志的庞大和复杂,对其进行分析和处理常常是一项耗时且繁琐的工作。今天,我们将介绍一种更好的方式来处理 HTTP 日志,以帮助您更...
    99+
    2023-07-29
    打包 http 日志
  • IDEA找不到Database解决方法
    第一步:在idea中找到View->Tool Windows 然后发现我的idea里面并没有Database这一选项 第二步:找到File->Settings 第三步:找到plugins,然后在...
    99+
    2023-09-05
    intellij-idea 数据库 mysql
  • vps日志清理的方法是什么
    清理VPS日志的方法可以根据不同的操作系统和日志类型而有所不同。以下是一些常见的方法:1. Linux系统:- 使用logrotat...
    99+
    2023-08-19
    vps
  • sqlserver日志清理的方法有哪些
    SQL Server 日志清理方法可以通过以下几种方式来实现: 使用SQL Server Management Studio (...
    99+
    2024-04-15
    sqlserver
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作