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

网友投稿 249 2022-11-16


关于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

总结


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用SpringBoot自定义starter的完整步骤
下一篇:Spring为何要用三级缓存来解决循环依赖问题
相关文章

 发表评论

暂时没有评论,来抢沙发吧~