0


Spring(AOP)的使用方法

为什么要使用AOP?

AOP是面向对象的补充,当我们需要为多个对象引入一个公共行为,比如日志,操作记录等,就需要在每个对象中引用公共行为,这样程序就产生了大量的重复代码,使用AOP可以完美解决这个问题。

  1. AOP:全称是 Aspect Oriented Programming 即:面向切面编程。简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
  2. Aop的作用:在程序运行期间,不修改源码对已有方法进行增强。
  3. Aop优势:减少重复代码、提高开发效率、维护方便
  4. AOP的实现方式:使用动态代理技术

一、通过注解使用AOP

1.1、需求定义

完成日志记录功能,当用户进行数据库增、删、改的时候记录操作日志。

1.2、需求分析

  1. 在系统调用Service中增、删、改的方法时通过AOP来记录操作日志

1.3、需求实现

第1步:添加坐标

  1. <dependencies>
  2. <!--spring坐标-->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>5.0.9.RELEASE</version>
  7. </dependency>
  8. <!--解析切入点表达式-->
  9. <dependency>
  10. <groupId>org.springframework</groupId>
  11. <artifactId>spring-aspects</artifactId>
  12. <version>5.0.9.RELEASE</version>
  13. </dependency>
  14. </dependencies>

第2步:添加配置beans.xml配置文件

使用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:aop="http://www.springframework.org/schema/aop"
  5. xmlns:context="http://www.springframework.org/schema/context"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop
  9. http://www.springframework.org/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  10. <!-- 开启自动扫描注解-->
  11. <context:component-scan base-package="demo"/>
  12. <!--开启AspectJ生成代理对象-->
  13. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  14. </beans>

使用配置类的方式

  1. package demo;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.context.annotation.EnableAspectJAutoProxy;
  5. @Configuration //设置为配置文件
  6. @ComponentScan({"demo"}) //组件扫描
  7. @EnableAspectJAutoProxy //开启生成切面的代理对象
  8. public class SpringConfig {
  9. }

第3步:添加一个业务类AccountService

  1. package demo;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class PaperService {
  5. public void publishUpdate(){
  6. System.out.println("论文已发布");
  7. }
  8. public void updatePaper(){
  9. System.out.println("论文已修改");
  10. }
  11. public void deletePaper(){
  12. System.out.println("论文已删除");
  13. }
  14. public void selectList(){
  15. System.out.println("查询论文");
  16. }
  17. }

第4步:添加一个切面类

定义切入点表达式和通知类型

  1. package demo;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.*;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. @Aspect //表示这是一个切面类
  7. public class Logger {
  8. @Pointcut("execution(* demo.*.*(..))")//设置切入点表达式
  9. private void pott(){}
  10. /**
  11. * 前置通知
  12. * 应用场景:权限控制(权限不足抛出异常)、记录方法调用信息日志
  13. */
  14. @Before("pott()")
  15. public void beforePrintLog(){
  16. System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志******");
  17. }
  18. /**
  19. * 后置通知,在异常时不执行
  20. * 特点:在目标方法运行后返回值后再增强代码逻辑
  21. * 应用:与业务相关的,如银行在存取款结束后的发送短信消息
  22. */
  23. @AfterReturning("pott()")
  24. public void afterReturningPrintLog() {
  25. System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志=========");
  26. }
  27. /**
  28. * 异常通知
  29. * 作用:目标代码出现异常,通知执行。记录异常日志、通知管理员(短信、邮件)
  30. * 应用场景:处理异常(一般不可预知),记录日志
  31. */
  32. @AfterThrowing("pott()")
  33. public void afterThrowingPrintLog() {
  34. System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志++++++++++++");
  35. }
  36. /**
  37. * 最终通知,不管异常与否
  38. * 作用:不管目标方法是否发生异常,最终通知都会执行(类似于finally代码功能)
  39. * 应用场景:释放资源 (关闭文件、 关闭数据库连接、 网络连接、 释放内存对象 )
  40. */
  41. @After("pott()")
  42. public void afterPrintLog() {
  43. System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志&&&&&&&&&&&&&&&&&&");
  44. }
  45. /**
  46. * 环绕通知
  47. * 特点:目标方法执行前后,都进行增强(控制目标方法执行)
  48. * 应用:日志、缓存、权限、性能监控、事务管理
  49. */
  50. @Around("pott()")
  51. public Object aroundPrintLog(ProceedingJoinPoint point){
  52. //定义返回值
  53. Object result = null;
  54. try {
  55. //获得切入点中方法的参数列表
  56. Object[] args = point.getArgs();
  57. //调用前置通知
  58. beforePrintLog();
  59. //执行切入点的方法
  60. result = point.proceed(args);
  61. //调用后置通知
  62. afterReturningPrintLog();
  63. } catch (Exception e){
  64. //调用异常通知
  65. afterThrowingPrintLog();
  66. } catch (Throwable throwable) {
  67. throwable.printStackTrace();
  68. }
  69. return result;
  70. }
  71. }

第5步:定义测试类进行测试

  1. package demo;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4. public class PaperText {
  5. public static void main(String[] args) {
  6. ApplicationContext context=new AnnotationConfigApplicationContext(EatConfig.class);
  7. PaperService paperService= (PaperService) context.getBean("paperService");
  8. paperService.publishUpdate();
  9. paperService.updatePaper();
  10. paperService.deletePaper();
  11. paperService.selectList();
  12. }
  13. }

1.5、知识点补充

1、切入点表达式的写法-execution函数

关键字:execution(表达式)

表达式:访问修饰符 返回值 包名.包名.包名...类名.方法名

2、Spring中的通知

Spring中一共有5种通知

前置通知(before)、后置通知(returning)、异常通知(throwing)、最终通知(after)、环绕通知(around)

二、案例

2.1、使用AOP记录用户操作日志

需求

1、定义PaperService类,提供发布论文的方法publishPaper、修改论文的方法updatePaper、删除论文的方法deletePaper、查询论文列表的方法selectPaperList

2、要求对论文的发布、修改、删除的操作记录日志,并输出到控制台

实现思路

使用aop的前置通知实现日志的记录功能

2.2、使用AOP实现取款短信的发送功能

需求

1、定义AccountService类,提供取款的方法drawMoney

2、要求在用户取款之后,模拟发送短信给客户(控制台输出”您的账号被取款1000元“)

实现思路

使用AOP的后置通知实现该功能

2.3、使用AOP实现程序异常发送email功能

需求

1、定义UserService类,提供用户注册的方法addUser

2、要求在注册用户的时候模拟一个异常(比如:1/0)

3、要求在程序出现异常之后模拟发送Email给管理员的功能(控制台输出”用户注册功能出现了异常,请及时查看“)

实现思路

使用AOP的异常通知实现该功能

2.3、使用AOP实现查看方法执行的时间

需求

1、定义MyService类,提供计算0-1000累加和的方法doSum

2、要求计算这个方法执行的所用时长(毫秒数)

实现思路

1、使用AOP的环绕通知实现该功能

2、获取当前时间的毫秒数:long timeStap = new Date().getTime();

参考代码

beans.xml

  1. package demo;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.context.annotation.EnableAspectJAutoProxy;
  5. @Configuration
  6. @ComponentScan({"demo"})
  7. @EnableAspectJAutoProxy
  8. public class SpringConfig {
  9. }

** Service**

  1. package demo;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class MyService {
  5. public void doSum(){
  6. int sum=0;
  7. for (int i = 0; i < 101; i++) {
  8. sum=sum+i;
  9. }
  10. System.out.println(sum);
  11. }
  12. }

MyAspect

  1. package demo;
  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. import java.util.Date;
  8. @Component
  9. @Aspect
  10. public class Myaspect {
  11. @Pointcut("execution(* demo.MyService.doSum())")
  12. public void men(){}
  13. @Around("men()")
  14. public Object croundSum(ProceedingJoinPoint pro){
  15. Object result=null;
  16. try {
  17. //执行前通知
  18. long timeStap1=new Date().getTime();
  19. //执行增强的业务方法
  20. Object[] arr=pro.getArgs();
  21. result=pro.proceed(arr);
  22. //执行后通知
  23. long timeStap2=new Date().getTime();
  24. //算出前后的时间差
  25. long time=timeStap2-timeStap1;
  26. System.out.println("该方法执行用时"+time+"毫秒");
  27. } catch (Throwable throwable) {
  28. throwable.printStackTrace();
  29. }
  30. return result;
  31. }
  32. }

测试类

  1. package demo;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4. public class demoText {
  5. public static void main(String[] args) {
  6. ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
  7. MyService myService= (MyService) context.getBean("myService");
  8. myService.doSum();
  9. }
  10. }
标签: spring java 后端

本文转载自: https://blog.csdn.net/m0_74795259/article/details/128000792
版权归原作者 雷大胖胖 所有, 如有侵权,请联系我们删除。

“Spring(AOP)的使用方法”的评论:

还没有评论