Spring AOP简介

BolunWu 2020-11-11 21:08:32
java spring AOP SegmentFault 简介


1.1 AOP概述

1.1.1 AOP是什么?

AOP是一种设计思想,是软件设计领域的面向切面编程,他是面向对象编程OOP的一种补充和完善.它以通过预编译的方式和运行期动态代理方式,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术.

1.1.2 AOP应用场景分析?

实际项目中通常会将系统分为两部分,一部分是核心业务,一部分是非核心业务.在编程实现时我们首先要完成的是核心业务的实现,非核心业务我们一般通过特定的方式切入到系统中,这种方式一般借助AOP实现.
AOP就是要基于OCP(开闭原则),在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以控制对象执行.例如AOP应用于项目中的日志处理,事务处理,权限处理,缓存处理等等.

1.1.3 AOP应用原理分析

1)假如目标对象(被代理对象)实现接口,则底层可以采用JDK动态代理机制为目标对象创建代理对象(目标类和代理类会实现共同接口).
2)假如目标对象(被代理对象)没有实现接口,则底层可以采用CGLIB代理机制为目标对象创建代理对象(默认创建的代理类会继承目标对象类型).
AOP在默认的情况下使用CGLIB代理,加入使用JDK动态代理可以在配置文件(application.properties)中配置如下:
spring.aop.proxy-target-class=false

1.2AOP相关术语分析

切面(asprct):横切面对象,一般为一个具体类对象(可以借助@Acpect声明).
通知(Advice):在横切面的某个特定连接点上执行的动作(扩展功能),例如around,before,after等.
连接点(joinpoint):程序执行中的某个特定点一般指被拦截到的方法.
切入点(pointcut):对多个连接点(Joinpoint)一种定义,一般可以理解为多个连接点的集合.

2.Spring AOP快速实践

2.1业务描述

基于项目中的核心业务,简单添加日志操作,借助SLF4J日志API输出目标方法的执行时长.(前提,不能修改目标方法的代码-遵循OCP原则)

2.2项目创建及配置

创建maven项目或在已有的项目基础上添加AOP启动依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
说明:基于此依赖spring可以整合AspectJ框架快锁完成AOP的基本操作,AspectJ是一个面向切面的框架,它定义了AOP的一些语法,有一个专门的自己吗生成器来生成遵守java规范的class文件.

2.3 扩展业务分析及实现

2.3.1创建日志切面类对象

将此日志切面类作为核心业务增强(一个横切面对象)类,用于输出业务执行时长.
package com.cy.pj.common.aspect;
@Aspect
@Slf4j
@Component
public class SysLogAspect {
@Pointcut("bean(sysUserServiceImpl)")
public void logPointCut() {}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint jp)
throws Throwable{
try {
log.info("start:{}"+System.currentTimeMillis());
Object result=jp.proceed();//最终会调用目标方法
log.info("after:{}"+System.currentTimeMillis());
return result;
}catch(Throwable e) {
log.error("after:{}",e.getMessage());
throw e;
}
}
说明:
@Aspect注解用于标识或者描述AOP中切面类型,基于切面类型构建的对象用于为目标对象进行功能扩展或控制目标对象的执行.
@Pointcut注解用于描述切面中的方法,并定义切面中的切入点,(基于特定表达式的方式进行描述).
@Around注解用以描述切面中的方法,这样的方法会被认为是一个环绕通知(核心业务方法执行之前和执行之后要执行的一个动作),@Around注解内部value属性的值为一个切入点表达式或者是切入点表达式的一个引用(这个引用为@Pointcut注解描述的方法的方法名).
ProceedingJoinPoint类作为一个连接点类型,此类型的对象用于封装要执行的目标方法相关的一些信息.只能用于@Around注解描述的方法参数.

2.3.1业务切面测试实现

启动项目测试或者进行单元测试:
@SpringBootTest
public class AopTests {
@Autowired
private SysUserService userService;
@Test
public void testSysUserService() {
PageObject<SysUserDeptVo> po=
userService.findPageObjects("admin",1);
System.out.println("rowCount:"+po.getRowCount());
}
}

2.4 扩展业务织入增强分析

2.4.1基于JDK代理方式实现

假如目标对象有实现接口,则可以基于JDK为目标对象创建代理对象,然后对目标对象进行功能扩展.

2.4.2基于CGLIB代理方式实现

加入目标对象没有实现接口(当然实现了接口也是可以的),可以基于CGLIB代理方式为目标对象织入功能扩展.
说明:目标对象实现了接口也可以基于CGLIB为目标对象创建对象.

3.Spring AOP增强

3.1切面通知应用增强

3.1.1通知类型

在基于Spring AOP编程的过程中,基于AspectJ框架标准,spring中定义了五种类型的通知(通知描述是一种扩展业务),它们分别是:
@Before
@AfterReturning
@AfterThrowing
@After
@Around重点掌握(优先级最高)
说明:在切面类中使用什么通知,由业务决定,并不是说,在切面中要把所有的通知都写上.

3.1.2 通知执行顺序

image

说明:实际项目中可能不会在切面中定义所有通知,具体定义那些通知要结合业务进行实现.

3.1.3通知实践过程分析

@Component
@Aspect
public class SysTimeAspect {
@Pointcut("bean(sysUserServiceImpl)")
public void doTime(){}
@Before("doTime()")
public void doBefore(JoinPoint jp){
System.out.println("time doBefore()");
}
@After("doTime()")
public void doAfter(){
System.out.println("time doAfter()");
}
/**核心业务正常结束时执行* 说明:假如有after,先执行after,再执行returning*/
@AfterReturning("doTime()")
public void doAfterReturning(){
System.out.println("time doAfterReturning");
}
/**核心业务出现异常时执行说明:假如有after,先执行after,再执行Throwing*/
@AfterThrowing("doTime()")
public void doAfterThrowing(){
System.out.println("time doAfterThrowing");
}
@Around("doTime()")
public Object doAround(ProceedingJoinPoint jp)
throws Throwable{
System.out.println("doAround.before");
try{
Object obj=jp.proceed();
System.out.println("doAround.after");
return obj;
}catch(Throwable e){
System.out.println(e.getMessage());
throw e;
}
}
}
说明:对于@AfterThrowing通知只有在出现有异常时才会执行,所以当做一些异常监控时可在此方法中进行代码实现.

3.2切入点表达式增强

3.2.1bean表达式(重点)

bean表达式一般应用于类级别,实现粗粒度的切入点定义,案例分析:
bean("userServiceImpl")指定一个userServiceImpl中的所有方法.
bean("*ServiceImpl")指定所有后缀为ServiceImpl的类中所有方法.
说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的名字应该是spring容器中的某个bean的name.

3.2.2within表达式(了解)

within表达式应用于类级别,实现粗粒度的切入点表达式定义,案例分析:
within("aop.service.UserServiceImpl")指定当前包中这个类内部的所有方法.
within("aop.service.*") 指定当前目录下的所有类的所有方法.
within("aop.service..*") 指定当前目录以及子目录中类的所有方法.

3.2.3execution表达式(了解)

execution表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析:
语法:execution(返回值类型 包名.类名.方法名(参数列表)).
execution(void aop.service.UserServiceImpl.addUser())匹配addUser方法。
execution(void aop.service.PersonServiceImpl.addUser(String)) 方法参数必须为String的addUser方法
execution( aop.service...*(..)) 万能配置.

[email protected]表达式(重点)

@annontation(anno.RequiredLog)匹配有此注解描述的方法.
@annontation(anno.RequiredCache)匹配有此注解描述的方法.
其中:RequiredLog为我们自定义注解,当我们使用@RequiredLog注解修饰业务层方法时,系统底层会在执行此方法时进行日扩展操作.
:定义一Cache相关切面,使用注解表达式定义切入点,并使用此注解对需要使用cache的业务方法进行描述,代码分析如下:
第一步:定义注解RequiredCache
package com.cy.pj.common.annotation;
/**
* 自定义注解,一个特殊的类,所有注解都默认继承Annotation接口
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredCache {
//...
}
第二步:定义SysCacheAspect切面对象
package com.cy.pj.common.aspect;
@Aspect
@Component
public class SysCacheAspect {
@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredCache)")
public void doCache() {}
@Around("doCache()")
public Object around(ProceedingJoinPoint jp)
throws Throwable{
System.out.println("Get data from cache");
Object obj=jp.proceed();
System.out.println("Put data to cache");
return obj;
}
}
第三步: 使用@RequiredCache注解对特定业务目标对象中的查询方法进行描述.
 @RequiredCache
@Override
public List<Map<String, Object>> findObjects() {
….
return list;
}

3.3切面优先级设置实现

切面的优先级需要借助@Order注解进行描述,数字越小优先级越高,默认优先级比较低。例如:
定义日志切面并指定优先级
@Order(1)
@Aspect
@Component
public class SysLogAspect {
…
}
定义缓存切面并指定优先级
@Order(2)
@Aspect
@Component
public class SysCacheAspect {
…
}
说明: 当多个切面作用于同一个目标对象方法时,这些切面会构建成一个切面链,类似过滤器链、拦截器链.

3.4关键对象与术语总结

Spring 基于AspectJ框架实现AOP设计的关键对象概览,如图-10所示:

image

版权声明
本文为[BolunWu]所创,转载请带上原文链接,感谢
https://segmentfault.com/a/1190000038138995

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云