关于Spring AOP使用时的一些问题汇总

 更新时间:2020年10月25日 21:53  点击:1561

在使用AOP的时候遇到了一些问题,特此记录一下

首先写一个常用的AOP切片

切片类AopLog

package com.mantis.aop.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mantis.aop.common.util.DataUtil;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:执行顺序 正常顺序 Around Before Method.invoke Around After AfterReturning
 * 异常顺序 Around Before Method.invoke After AfterThrowing
 * @author: wei.wang
 * @since: 2020/4/4 13:47
 * @history: 1.2020/4/4 created by wei.wang
 */
@Aspect
@Component
public class AopLog {

 private static Logger logger = LoggerFactory.getLogger(AopLog.class);

 /**
  * 定义切点,切点为com.smec.fin.controller包和子包里任意方法的执行和service层所有方法的执行
  */
 @Pointcut("execution(public * com.mantis.aop.controller..*.*(..))")
 public void log() {
  // 定义切点
 }

 /**
  * 定义切点,切点为com.smec.fin.controller包和子包里任意方法的执行和service层所有方法的执行
  */
 @Pointcut("execution(public * com.mantis.aop.service.impl..*.*(..))")
 public void log2() {
  // 定义切点
 }

 /**
  * 环绕通知
  *
  * @param point
  * @return
  * @throws Throwable
  */
 @Around("log2()")
 public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
  logger.info("开始执行环绕操作");
  Object result = point.proceed();
  logger.info("执行环绕操作结束,返回值:{}", result);
  return result;
 }
}

服务类AopServiceImpl

package com.mantis.aop.service.impl;

import com.mantis.aop.service.AopService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/10/24 12:45
 * @history: 1.2020/10/24 created by wei.wang
 */
@Service
public class AopServiceImpl implements AopService {


 @Override
 public void testAop(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
  this.testAop2("testFinalMethod");
 }

 @Override
 public void testAop2(String str) {
  //this.testFinalMethod("testFinalMethod");
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl." + str);
 }

 public final void testFinalMethod(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
 }

 public void testFinalMethod2(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
 }
}

1.同方法运行问题

在使用AOP时我们发现存在同类中调用时切点失效问题,在执行时我们发现只执行了testAop的切点,testAop2的切点没有执行,这是因为经过AOP代理后的对象都已经不是原来的对象了,而是加入了增强方法的代理对象,使用代理对象调用时可以执行增强方法,但是这里是使用this调用的,也就是AopServiceImpl,因为不是代理对象就没有增强方法。

2020-10-24 13:31:06.261 INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController : 方法开始执行
2020-10-24 13:31:06.264 INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod

2020-10-24 13:31:06.274 INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

用@Autowired或Resource引入自身依赖

使用注解方法引入自身代理依赖,注意使用构造的方式会有循环依赖问题

 @Autowired
 AopServiceImpl aopService;

 @Override
 public void testAop(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
  aopService.testAop2("testFinalMethod");
  System.out.println();
 }

2020-10-24 13:36:33.477 INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController : 方法开始执行
2020-10-24 13:36:33.480 INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:36:33.488 INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod
2020-10-24 13:36:33.488 INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

2020-10-24 13:36:33.490 INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

开启暴露代理类,AopContext.currentProxy()方式获取代理类

通过暴露代理类方式,实际原理是把代理类添加到当前请求的ThreadLocal里面,然后在使用时从ThreadLocal中获取代理类,再调用对应的方法

在主方法上加入@EnableAspectJAutoProxy(exposeProxy=true),然后从AOP上下文中获取代理

 @Override
 public void testAop(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
  AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
  service.testAop2("testFinalMethod");
  System.out.println();
 }

2020-10-24 13:38:31.031 INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController : 方法开始执行
2020-10-24 13:38:31.035 INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:38:31.047 INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod
2020-10-24 13:38:31.048 INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

2020-10-24 13:38:31.050 INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

2.final关键字问题

Spring AOP默认使用cglib,会生成目标对象的子类代理对象。调用目标对象的方法,实际上是调用代理对象的方法。由于子类能够继承父类的方法,因此一般情况下目标类的方法,代理对象都会有。但是当目标类中某个方法带有final关键字时,这个方法不能被重写,因此代理对象中没有这个方法,因此会调用目标对象的方法。

带final关键字

因为testFinalMethod方法中存在final关键字,导致无法重写,结果代理对象就无法生成这个方法,因此调用目标对象方法,导致没有被增强

 @Override
 public void testAop(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
  AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
  service.testFinalMethod("testFinalMethod");
  System.out.println();
 }
 
 public final void testFinalMethod(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
 }

2020-10-24 13:47:46.907 INFO 15204 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod

2020-10-24 13:47:46.916 INFO 15204 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

不带final关键字

因为testFinalMethod方法中不存在final关键字,所以正常执行增强。

 @Override
 public void testAop(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
  AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
  service.testFinalMethod2("testFinalMethod");
  System.out.println();
 }
 
 public final void testFinalMethod2(String str) {
  System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
 }

2020-10-24 13:50:51.018 INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.controller.AopController : 方法开始执行
2020-10-24 13:50:51.021 INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:50:51.029 INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog    : 开始执行环绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod
2020-10-24 13:50:51.030 INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

2020-10-24 13:50:51.031 INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog    : 执行环绕操作结束,返回值:null

总结

到此这篇关于Spring AOP使用时的一些问题汇总的文章就介绍到这了,更多相关Spring AOP使用时的问题内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • Spring AOP 对象内部方法间的嵌套调用方式

    这篇文章主要介绍了Spring AOP 对象内部方法间的嵌套调用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-29
  • Spring Cloud 中@FeignClient注解中的contextId属性详解

    这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25
  • Springboot如何实现Web系统License授权认证

    这篇文章主要介绍了Springboot如何实现Web系统License授权认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-28
  • PHP传值到不同页面的三种常见方式及php和html之间传值问题

    在项目开发中经常见到不同页面之间传值在web工作中,本篇文章给大家列出了三种常见的方式。接触PHP也有几个月了,本文总结一下这段日子中,在编程过程里常用的3种不同页面传值方法,希望可以给大家参考。有什么意见也希望大...2015-11-24
  • js修改input的type属性问题探讨

    js修改input的type属性有些限制。当input元素还未插入文档流之前,是可以修改它的值的,在ie和ff下都没问题。但如果input已经存在于页面,其type属性在ie下就成了只读属性了,不可以修改。...2013-10-19
  • Mysql常见问题集锦

    1,utf8_bin跟utf8_general_ci的区别 ci是 case insensitive, 即 "大小写不敏感", a 和 A 会在字符判断中会被当做一样的; bin 是二进制, a 和 A 会别区别对待. 例如你运行: SELECT * FROM table WHERE txt = 'a'...2013-10-04
  • 如何在Spring WebFlux的任何地方获取Request对象

    这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26
  • 详解SpringCloudGateway内存泄漏问题

    这篇文章主要介绍了详解SpringCloudGateway内存泄漏问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-16
  • Mysql大小写敏感的问题

    一、1 CREATE TABLE NAME(name VARCHAR(10)); 对这个表,缺省情况下,下面两个查询的结果是一样的:复制代码 代码如下: SELECT * FROM TABLE NAME WHERE name='clip'; SELECT * FROM TABLE NAME WH...2015-03-15
  • linux mint 下mysql中文支持问题

    一.mysql默认不支持中文,它的server和db默认是latin1编码.所以我们要将其改变为utf-8编码,因为utf-8包含了地球上大部分语言的二进制编码 1.关闭mysql服务 sudo /etc/init.d/mysql stop 2.修改mysql配置文件 mysql配...2015-10-21
  • Spring为什么不推荐使用@Autowired注解详析

    @Autowired 注解的主要功能就是完成自动注入,使用也非常简单,但这篇文章主要给大家介绍了关于Spring为什么不推荐使用@Autowired注解的相关资料,需要的朋友可以参考下...2021-11-03
  • Springboot如何使用mybatis实现拦截SQL分页

    这篇文章主要介绍了Springboot使用mybatis实现拦截SQL分页,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-19
  • SpringMVC文件上传原理及实现过程解析

    这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
  • Spring Data JPA 关键字Exists的用法说明

    这篇文章主要介绍了Spring Data JPA 关键字Exists的用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-10
  • C#使用队列(Queue)解决简单的并发问题

    这篇文章主要介绍了使用队列(Queue)解决简单的并发问题,讲解的很细致,喜欢的朋友们可以了解一下...2020-06-25
  • tomcat启动完成执行 某个方法 定时任务(Spring)操作

    这篇文章主要介绍了tomcat启动完成执行 某个方法 定时任务(Spring)操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程

    这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16
  • Java Spring Cloud 负载均衡详解

    这篇文章主要介绍了Spring Cloud负载均衡及远程调用实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2021-09-18
  • SpringMvc自动装箱及GET请求参数原理解析

    这篇文章主要介绍了SpringMvc自动装箱及GET请求参数原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
  • SpringMvc获取请求头请求体消息过程解析

    这篇文章主要介绍了SpringMvc获取请求头请求体消息过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-17