1、通知

目标对象:

  1. package com.sgcc.lms.aop;
  2. @Component("calc")
  3. public class CalcImpl implements Calc {
  4. @Override
  5. public int add(int i, int y) {
  6. int result = i + y;
  7. return result;
  8. }
  9. @Override
  10. public int sub(int i, int y) {
  11. int result = i - y;
  12. return result;
  13. }
  14. @Override
  15. public int mul(int i, int y) {
  16. int result = i * y;
  17. return result;
  18. }
  19. @Override
  20. public int div(int i, int y) {
  21. int result = i / y;
  22. return result;
  23. }
  24. }

切面:

  1. package com.sgcc.lms.aop;
  2. import java.util.Arrays;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.annotation.After;
  5. import org.aspectj.lang.annotation.AfterReturning;
  6. import org.aspectj.lang.annotation.AfterThrowing;
  7. import org.aspectj.lang.annotation.Aspect;
  8. import org.aspectj.lang.annotation.Before;
  9. import org.aspectj.lang.annotation.Pointcut;
  10. import org.springframework.core.annotation.Order;
  11. import org.springframework.stereotype.Component;
  12. /**
  13. * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高
  14. */
  15. @Order(2)
  16. @Aspect
  17. @Component
  18. public class LoggingAspect {
  19. /**
  20. * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.
  21. * 使用 @Pointcut 来声明切入点表达式.
  22. * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
  23. */
  24. @Pointcut("execution(public int com.sgcc.lms.aop.Calc.*(..))")
  25. public void declareJointPointExpression(){}
  26. /**
  27. * 在 com.atguigu.spring.aop.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码
  28. */
  29. @Before("declareJointPointExpression()")
  30. public void beforeMethod(JoinPoint joinPoint){
  31. String methodName = joinPoint.getSignature().getName();
  32. Object [] args = joinPoint.getArgs();
  33. System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
  34. }
  35. /**
  36. * 在方法执行之后执行的代码. 无论该方法是否出现异常
  37. */
  38. @After("declareJointPointExpression()")
  39. public void afterMethod(JoinPoint joinPoint){
  40. String methodName = joinPoint.getSignature().getName();
  41. System.out.println("The method " + methodName + " ends");
  42. }
  43. /**
  44. * 在方法法正常结束受执行的代码
  45. * 返回通知是可以访问到方法的返回值的!
  46. */
  47. @AfterReturning(value="declareJointPointExpression()",
  48. returning="result")
  49. public void afterReturning(JoinPoint joinPoint, Object result){
  50. String methodName = joinPoint.getSignature().getName();
  51. System.out.println("The method " + methodName + " ends with " + result);
  52. }
  53. /**
  54. * 在目标方法出现异常时会执行的代码.
  55. * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
  56. */
  57. @AfterThrowing(value="declareJointPointExpression()",
  58. throwing="e")
  59. public void afterThrowing(JoinPoint joinPoint, Exception e){
  60. String methodName = joinPoint.getSignature().getName();
  61. System.out.println("The method " + methodName + " occurs excetion:" + e);
  62. }
  63. /**
  64. * 环绕通知需要携带 ProceedingJoinPoint 类型的参数.
  65. * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.
  66. * 且环绕通知必须有返回值, 返回值即为目标方法的返回值
  67. */
  68. /*
  69. @Around("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
  70. public Object aroundMethod(ProceedingJoinPoint pjd){
  71. Object result = null;
  72. String methodName = pjd.getSignature().getName();
  73. try {
  74. //前置通知
  75. System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
  76. //执行目标方法
  77. result = pjd.proceed();
  78. //返回通知
  79. System.out.println("The method " + methodName + " ends with " + result);
  80. } catch (Throwable e) {
  81. //异常通知
  82. System.out.println("The method " + methodName + " occurs exception:" + e);
  83. throw new RuntimeException(e);
  84. }
  85. //后置通知
  86. System.out.println("The method " + methodName + " ends");
  87. return result;
  88. }
  89. */
  90. }

applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
  7. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
  9. <!-- <bean id="calc" class="com.sgcc.lms.aop.CalcImpl"></bean> -->
  10. <!-- 配置自动扫描的包 -->
  11. <context:component-scan
  12. base-package="com.sgcc.lms.aop"></context:component-scan>
  13. <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 -->
  14. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  15. </beans>

使用

  1. package com.sgcc.lms.aop;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. public class Main {
  5. public static void main(String[] args) {
  6. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  7. Calc calc = (Calc) ctx.getBean("calc");
  8. System.out.println(calc.getClass().getName());
  9. int result = calc.add(1, 2);
  10. System.out.println("result:" + result);
  11. result = calc.div(1000, 10);
  12. System.out.println("result:" + result);
  13. }
  14. }

依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-aop</artifactId>
  5. <version>${springframework.version}</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-core</artifactId>
  10. <version>${springframework.version}</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework</groupId>
  14. <artifactId>spring-beans</artifactId>
  15. <version>${springframework.version}</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.springframework</groupId>
  19. <artifactId>spring-context</artifactId>
  20. <version>${springframework.version}</version>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.springframework</groupId>
  24. <artifactId>spring-expression</artifactId>
  25. <version>${springframework.version}</version>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.springframework</groupId>
  29. <artifactId>spring-aspects</artifactId>
  30. <version>${springframework.version}</version>
  31. </dependency>
  32. </dependencies>

2、spring boot使用注解记录方法耗时

image.png

  1. package com.kd.ndmp.dc.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. /**
  7. * @Author 李孟帅
  8. * @Date 2021/8/13
  9. * @Description TODO 方法耗时注解
  10. */
  11. @Target(ElementType.METHOD)
  12. @Retention(RetentionPolicy.RUNTIME)
  13. public @interface TakeTime {
  14. String value() default "";
  15. }

环绕通知

  1. package com.kd.ndmp.dc.aspect;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Pointcut;
  7. import org.springframework.stereotype.Component;
  8. import java.time.Duration;
  9. import java.time.LocalDateTime;
  10. /**
  11. * @Author 李孟帅
  12. * @Date 2021/8/13
  13. * @Description TODO
  14. */
  15. @Aspect
  16. @Slf4j
  17. @Component
  18. public class TakeTimeAspect {
  19. private static final String LINE = "==========================================》{}";
  20. @Pointcut("@annotation(com.kd.ndmp.dc.annotation.TakeTime)")
  21. public void pointCut() {
  22. }
  23. @Around("pointCut()")
  24. public Object around(ProceedingJoinPoint joinPoint) {
  25. Object result = null;
  26. try {
  27. LocalDateTime now = LocalDateTime.now();
  28. result = joinPoint.proceed();
  29. Duration between = Duration.between(now, LocalDateTime.now());
  30. log.info("耗时:{}",between.toMillis());
  31. } catch (Throwable throwable) {
  32. throwable.printStackTrace();
  33. }
  34. return result;
  35. }
  36. }

使用

image.png

注意

使用注解的,该类需要通过spirng ioc容器的bean 管理