• Spring Aop


    目录

    一、AOP学习

    1、AOP

    2、AOP示例

    1、方法执行时间

    2、Log信息通用


    一、AOP学习

    1. 面试题:
    2. 1、你肯定知道spring,那说说aop的全部通知顺序?
    3. 2.springboot或springboot2对aop的执行顺序影响?
    4. 3.说说你使用aop中碰到的坑?

    1、AOP

    Aop的常用注解:

    @Before:前置通知:目标方法之前执行

    @After:后置通知:目标方法之后执行(始终执行

    @AfterReturning:返回后通知:执行方法结束前执行(异常不执行

    @AfterThrowing:异常通知:出现异常时执行

    @Around:环绕通知:环绕目标方法执行

    创建springboot项目

    pom--->切换springboot版本:Spring4+springboot1.5.9/Spring5+springboot2.3.3

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <groupId>com.lwzgroupId>
    7. <artifactId>springboot_aopartifactId>
    8. <version>1.0-SNAPSHOTversion>
    9. <parent>
    10. <groupId>org.springframework.bootgroupId>
    11. <artifactId>spring-boot-starter-parentartifactId>
    12. <version>1.5.9.RELEASEversion>
    13. parent>
    14. <properties>
    15. <java.version>1.8java.version>
    16. properties>
    17. <dependencies>
    18. <dependency>
    19. <groupId>org.springframework.bootgroupId>
    20. <artifactId>spring-boot-starterartifactId>
    21. dependency>
    22. <dependency>
    23. <groupId>org.aspectjgroupId>
    24. <artifactId>aspectjweaverartifactId>
    25. dependency>
    26. <dependency>
    27. <groupId>org.springframework.bootgroupId>
    28. <artifactId>spring-boot-starter-testartifactId>
    29. <scope>testscope>
    30. dependency>
    31. dependencies>
    32. <build>
    33. <plugins>
    34. <plugin>
    35. <groupId>org.springframework.bootgroupId>
    36. <artifactId>spring-boot-maven-pluginartifactId>
    37. plugin>
    38. plugins>
    39. build>
    40. project>

    切面编程,切面类

    1. package com.lwz.aop;
    2. import org.aspectj.lang.ProceedingJoinPoint;
    3. import org.aspectj.lang.annotation.After;
    4. import org.aspectj.lang.annotation.AfterReturning;
    5. import org.aspectj.lang.annotation.AfterThrowing;
    6. import org.aspectj.lang.annotation.Around;
    7. import org.aspectj.lang.annotation.Aspect;
    8. import org.aspectj.lang.annotation.Before;
    9. import org.springframework.stereotype.Component;
    10. @Aspect
    11. @Component
    12. public class MyAspect {
    13. @Before("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
    14. public void beforeNotify() {
    15. System.out.println("******@Before我是前置通知");
    16. }
    17. @After("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
    18. public void afterNotify() {
    19. System.out.println("******@@After我是后置通知");
    20. }
    21. @AfterReturning("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
    22. public void afterReturningNotify() {
    23. System.out.println("******@AfterReturning我是返回后通知");
    24. }
    25. @AfterThrowing("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
    26. public void afterThrowingNotify() {
    27. System.out.println("******@AfterThrowing我是异常通知");
    28. }
    29. @Around("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
    30. public Object aroundNotify(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    31. Object retValueObject = null;
    32. System.out.println("我是环绕通知之前AAA");
    33. retValueObject = proceedingJoinPoint.proceed();
    34. System.out.println("我是环绕通知之后BBB");
    35. return retValueObject;
    36. }
    37. }

    业务类

    1. package com.lwz.service;
    2. public interface CalcService {
    3. public int div(int x, int y);
    4. }

    实现类

    1. package com.lwz.service.impl;
    2. import org.springframework.stereotype.Service;
    3. import com.lwz.service.CalcService;
    4. @Service
    5. public class CalcServiceImpl implements CalcService {
    6. @Override
    7. public int div(int x, int y) {
    8. int result = x / y;
    9. System.out.println(" ======>CalcServiceImpl被调用了,计算结果:" + result);
    10. return result;
    11. }
    12. }

    测试类

    1. package com.lwz;
    2. import org.junit.Test;
    3. import org.junit.runner.RunWith;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.boot.SpringBootVersion;
    6. import org.springframework.boot.test.context.SpringBootTest;
    7. import org.springframework.core.SpringVersion;
    8. import org.springframework.test.context.junit4.SpringRunner;
    9. import com.lwz.service.CalcService;
    10. @SpringBootTest
    11. @RunWith(SpringRunner.class)
    12. public class AopTest {
    13. @Autowired
    14. private CalcService calcService;
    15. @Test
    16. public void testAop() {
    17. System.out.println(
    18. "spring版本:" + SpringVersion.getVersion() + "\t SpringBoot版本:" + SpringBootVersion.getVersion());
    19. calcService.div(5, 3);
    20. // calcService.div(5, 0);
    21. }
    22. }

    pom--->切换springboot版本:Spring4+springboot1.5.9/Spring5+springboot2.3.3正常系和异常系进行测试

    Spring4运行结果:

    1. 正常系运行结果:
    2. . ____ _ __ _ _
    3. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    4. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    5. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    6. ' |____| .__|_| |_|_| |_\__, | / / / /
    7. =========|_|==============|___/=/_/_/_/
    8. :: Spring Boot :: (v1.5.9.RELEASE)
    9. spring版本:4.3.13.RELEASE SpringBoot版本:1.5.9.RELEASE
    10. 我是环绕通知之前AAA
    11. ******@Before我是前置通知
    12. ======>CalcServiceImpl被调用了,计算结果:1
    13. 我是环绕通知之后BBB
    14. ******@@After我是后置通知
    15. ******@AfterReturning我是返回后通知
    16. 异常系运行结果:
    17. . ____ _ __ _ _
    18. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    19. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    20. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    21. ' |____| .__|_| |_|_| |_\__, | / / / /
    22. =========|_|==============|___/=/_/_/_/
    23. :: Spring Boot :: (v1.5.9.RELEASE)
    24. spring版本:4.3.13.RELEASE SpringBoot版本:1.5.9.RELEASE
    25. 我是环绕通知之前AAA
    26. ******@Before我是前置通知
    27. ******@@After我是后置通知
    28. ******@AfterThrowing我是异常通知
    29. java.lang.ArithmeticException: / by zero

    spring4 aop正常顺序:@Before-->@After-->@AfterReturning

    spring4 aop异常顺序:@Before-->@After-->@AfterThrowing

    1. 相当于:
    2. try {
    3. //@Before
    4. //method.invoke(args);
    5. //@AfterReturning
    6. } catch (Exception e) {
    7. //@AfterThrowing
    8. }finally {
    9. //@After
    10. }

    Spring5运行结果:

    1. 正常系运行结果:
    2. . ____ _ __ _ _
    3. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    4. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    5. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    6. ' |____| .__|_| |_|_| |_\__, | / / / /
    7. =========|_|==============|___/=/_/_/_/
    8. :: Spring Boot :: (v2.3.3.RELEASE)
    9. spring版本:5.2.8.RELEASE SpringBoot版本:2.3.3.RELEASE
    10. 我是环绕通知之前AAA
    11. ******@Before我是前置通知
    12. ======>CalcServiceImpl被调用了,计算结果:1
    13. ******@AfterReturning我是返回后通知
    14. ******@@After我是后置通知
    15. 我是环绕通知之后BBB
    16. 异常系运行结果:
    17. . ____ _ __ _ _
    18. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    19. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    20. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    21. ' |____| .__|_| |_|_| |_\__, | / / / /
    22. =========|_|==============|___/=/_/_/_/
    23. :: Spring Boot :: (v2.3.3.RELEASE)
    24. spring版本:5.2.8.RELEASE SpringBoot版本:2.3.3.RELEASE
    25. 我是环绕通知之前AAA
    26. ******@Before我是前置通知
    27. ******@AfterThrowing我是异常通知
    28. ******@@After我是后置通知
    29. java.lang.ArithmeticException: / by zero

    spring5 aop正常顺序:@Before-->@AfterReturning-->@After

    spring5 aop异常顺序:@Before-->@AfterThrowing-->@After

    2、AOP示例

    1、方法执行时间

    系统运行一段时间,发现系统运行比较慢,想知道是哪些方法执行时间比较慢?或者为了性能调优?

    每个方法的开头和结尾加代码处理记录打印时间,代码就会显得过于冗余,我们使用SpringAOP使用注解的方式来解决。

    创建SpringBoot项目

    pom

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-webartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>org.springframework.bootgroupId>
    7. <artifactId>spring-boot-starter-aopartifactId>
    8. dependency>

    定义注解

    1. package com.lwz.study.aop;
    2. import java.lang.annotation.*;
    3. @Target(ElementType.METHOD)
    4. @Retention(RetentionPolicy.RUNTIME)
    5. @Documented
    6. public @interface ExecTime {
    7. //描述
    8. String desc() default "";
    9. }

    定义切面类

    1. package com.lwz.study.aop;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.aspectj.lang.ProceedingJoinPoint;
    4. import org.aspectj.lang.Signature;
    5. import org.aspectj.lang.annotation.Around;
    6. import org.aspectj.lang.annotation.Aspect;
    7. import org.aspectj.lang.annotation.Pointcut;
    8. import org.aspectj.lang.reflect.MethodSignature;
    9. import org.springframework.stereotype.Component;
    10. import java.lang.annotation.Annotation;
    11. import java.lang.reflect.Method;
    12. @Slf4j
    13. @Aspect
    14. @Component
    15. public class ExecTimeAspect {
    16. //切点
    17. @Pointcut("@annotation(com.lwz.study.aop.ExecTime)")
    18. private void execTimeAspect(){}
    19. @Around("execTimeAspect()")
    20. public T around(ProceedingJoinPoint pjp) throws Throwable {
    21. Long startTime = System.currentTimeMillis();
    22. Object[] args = pjp.getArgs();
    23. T result;
    24. Method methodClass;
    25. try {
    26. result = (T)pjp.proceed(args);//执行方法
    27. }finally {
    28. long endTime = System.currentTimeMillis();
    29. Signature signature = pjp.getSignature();
    30. String methodName = signature.getName();
    31. Class targetClass = pjp.getTarget().getClass();
    32. Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes();
    33. methodClass = targetClass.getMethod(methodName, parameterTypes);
    34. Annotation[] annotations = methodClass.getAnnotations();
    35. for (Annotation annotation : annotations){
    36. Classextends Annotation> aClass = annotation.annotationType();
    37. String simpleName = aClass.getSimpleName();
    38. if("ExecTime".equals(simpleName)){
    39. ExecTime timeConsume = (ExecTime) annotation;
    40. String desc = timeConsume.desc();
    41. log.info(desc+"[{}] 执行耗时:{}ms",methodName,endTime-startTime);
    42. break;
    43. }
    44. }
    45. }
    46. return result;
    47. }
    48. }

    controller

    1. @RestController
    2. @RequestMapping("/")
    3. public class LogController {
    4. @Autowired
    5. private LogService logService;
    6. @RequestMapping("/test")
    7. public Map test(HttpServletRequest request){
    8. Map map = new HashMap<>();
    9. logService.initData("数据信息");
    10. return map;
    11. }
    12. }

    service

    1. public interface LogService {
    2. void initData(String data);
    3. }

    serviceImpl

    1. @Service
    2. public class LogServiceImpl implements LogService {
    3. @ExecTime(desc = "LogServiceImpl")
    4. @Override
    5. public void initData(String data) {
    6. System.out.println("data"+data);
    7. }
    8. }

    测试结果打印出信息:

    .....LogServiceImpl[initData] 执行耗时:18ms

    2、Log信息通用

    其他同上面项目

    1. package com.lwz.study.aop;
    2. import java.lang.annotation.*;
    3. @Target(ElementType.METHOD)
    4. @Retention(RetentionPolicy.RUNTIME)
    5. @Documented
    6. public @interface LogInfo {
    7. //描述
    8. String desc() default "";
    9. }

    1. package com.lwz.study.aop;
    2. import org.aspectj.lang.ProceedingJoinPoint;
    3. import org.aspectj.lang.annotation.Around;
    4. import org.aspectj.lang.annotation.Aspect;
    5. import org.aspectj.lang.annotation.Pointcut;
    6. import org.springframework.stereotype.Component;
    7. @Aspect
    8. @Component
    9. public class LogAspect {
    10. //切点
    11. // @Pointcut("execution(* com.*.controller..*.*(..))")
    12. @Pointcut("@annotation(com.lwz.study.aop.LogInfo)")
    13. private void logAspect(){}
    14. @Around("logAspect()")
    15. public Object log(ProceedingJoinPoint pjp) throws Throwable {
    16. System.out.println("Log....Start");
    17. //运行目标方法
    18. Object object = pjp.proceed();
    19. System.out.println("Log....End");
    20. //最后返回目标方法
    21. return object;
    22. }
    23. }

    Sping AOP切面编程学习

    Spring循环依赖

    再小的努力,乘以365都很明显!
    一个程序员最重要的能力是:写出高质量的代码!!
    有道无术,术尚可求也,有术无道,止于术。
    无论你是年轻还是年长,所有程序员都需要记住:时刻努力学习新技术,否则就会被时代抛弃!

  • 相关阅读:
    决策树——依据水果特征分类
    业务网关之AK中心建设
    【经纬恒润】自动驾驶感知算法岗位一面
    实验三 Servlet 相关技术
    String类、String类常见的构造方法、String类的方法介绍、判断功能的方法、转换功能方法、其他方法、Object类
    c++ 运算符重载(一)
    flutter sliver 多种滚动组合开发指南
    漫谈Web3的实现之路:组织形式、产品形态和技术发展
    vim编辑器 用法
    Vue2023 面试归纳及复习
  • 原文地址:https://blog.csdn.net/weixin_42472027/article/details/133692462