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

 更新时间:2020年10月25日 15:15:04   作者:zero  
这篇文章主要给大家汇总介绍了关于Spring AOP使用时的一些问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在使用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使用时的问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文搞懂Java ScheduledExecutorService的使用

    一文搞懂Java ScheduledExecutorService的使用

    JUC包(java.util.concurrent)中提供了对定时任务的支持,即ScheduledExecutorService接口。本文主要对ScheduledExecutorService的使用进行简单的介绍,需要的可以参考一下
    2022-11-11
  • Spring boot + LayIM + t-io 实现文件上传、 监听用户状态的实例代码

    Spring boot + LayIM + t-io 实现文件上传、 监听用户状态的实例代码

    这篇文章主要介绍了Spring boot + LayIM + t-io 实现文件上传、 监听用户状态的实例代码,需要的朋友可以参考下
    2017-12-12
  • Java的String类中的startsWith方法和endsWith方法示例详解

    Java的String类中的startsWith方法和endsWith方法示例详解

    大家应该都知道startsWith()方法用于检测字符串是否以指定的前缀开始,endsWith()方法用于测试字符串是否以指定的后缀结束,本文就Java的String类中的startsWith方法和endsWith方法给大家详细讲解,感兴趣的朋友一起看看吧
    2023-11-11
  • java的Object里wait()实现原理讲解

    java的Object里wait()实现原理讲解

    这篇文章主要介绍了java的Object里wait()实现原理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • SpringBoot MDC全局链路最新完美解决方案

    SpringBoot MDC全局链路最新完美解决方案

    MDC 在 Spring Boot 中的作用是为日志事件提供上下文信息,并将其与特定的请求、线程或操作关联起来,通过使用 MDC,可以更好地理解和分析日志,并在多线程环境中确保日志的准确性和一致性,这篇文章主要介绍了SpringBoot MDC全局链路解决方案,需要的朋友可以参考下
    2023-08-08
  • Java读取xml文件的五种方式

    Java读取xml文件的五种方式

    在编写与 XML 数据交互的现代软件应用时,有效地读取和解析 XML 文件是至关重要的,本文旨在探讨 Java 中处理 XML 文件的五种主要方法:DOM、SAX、StAX、JAXB 和 JDOM,我们将详细介绍每种方法的工作原理、典型用途以及如何在 Java 程序中实现它们
    2024-05-05
  • Springboot 如何实现filter拦截token验证和跨域

    Springboot 如何实现filter拦截token验证和跨域

    这篇文章主要介绍了Springboot 如何实现filter拦截token验证和跨域操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java中的CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)详解

    Java中的CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)详解

    这篇文章主要介绍了Java中的CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)详解,CAS算法的作用是解决多线程条件下使用锁造成性能损耗问题的算法,保证了原子性,这个原子操作是由CPU来完成的,需要的朋友可以参考下
    2024-01-01
  • SpringMVC中Controller层获取前端请求参数的方式汇总

    SpringMVC中Controller层获取前端请求参数的方式汇总

    这篇文章主要介绍了SpringMVC中Controller层获取前端请求参数的几种方式,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • Java SimpleDateFormat线程不安全问题

    Java SimpleDateFormat线程不安全问题

    这篇文章详细介绍了如可解决impleDateFormat线程不安全的问题,对多线程问题感兴趣的同学可以参考阅读本文
    2023-03-03

最新评论