通常我们在进行开发的时候,主要编写的都是业务代码,而一些与业务没有强相关的外围事务,如日志记录、事务处理等,会在代码中大量重复出现,造成代码冗余、霰弹式修改等问题,需要实现这些功能的热插拔、在使用的时候通过简便地方式引入处理。由此,引入了AOP实现业务代码与外围功能分离。
通过AOP,可以将业务外的周边共用逻辑,比如日志、事务、权限等封装起来,然后在业务需要使用时,将这些功能和业务功能“编织”在一起。
Aspect Oriented Programming,即面向切面编程。AOP要实现的是在业务代码基础上,进行一定的包装,将切面的逻辑在方法返回前、方法返回后、方法抛异常等地方进行增强处理。在原来类的基础上,实现一个代理类,把切面的逻辑加在代理类中,实际上运行的是代理类的实例。
AOP实现方式有两种,一种是静态编译,一种是动态代理;Java语言的实现方案有AspectJ或Spring AOP。
AspectJ是一种编译期的用注解形式实现的AOP,是一个代码生成工具。需要用AspectJ语法来定义代码生成规则、由AspectJ的编译工具编译生成class文件。
AspectJ能干很多Spring AOP不能干的事情,是AOP编程的完全解决方案。
因为AspectJ在代码加载运行前就完成了织入,因此它生成的类是没有额外运行时开销的。
Spring AOP基于动态代理实现,在默认情况下,如果被代理类使用接口、则用JDK提供的动态代理实现,如果没有接口,使用Cglib实现。
Spring AOP依赖于IOC容器管理,只能作用于Spring容器中的bean对象,只能作用于bean对象的方法。
web开发时,有些时候需要的是一个Filter或者一个Intercepter,不一定是AOP
Aspect即切面,是实现功能增强的类,里面包含一些Pointcut和Advice。在AOP中,切面一般使用 @Aspect
注解来使用,在XML 中,可以使用 aop:aspect 来定义一个切面。 (注:在Spring中,仅使用@Aspect注解是无法将一个Java对象转换成bean的,还要使用类似@Component之类的注解标明)
Advice即增强,定义切面起作用的时机,比如是在方法执行前、执行后起作用。Spring AOP中有五种不同的增强方式:around(环绕通知),before(前置通知),after(后置通知), exception(异常通知),return(返回通知)
Advice对应的注解有:@Before、@After、@AfterReturn、@AfterThrow、@Around
JoinPoint即连接点,表示切面执行的地点,比如一个对象的一个方法。
Pointcut即切入点,表示一组连接点,对应的注解为@Pointcut。这些连接点或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方 。由切入点表达式匹配的连接点的概念是AOP的核心,Spring默认使用AspectJ切入点表达式语言。
Weaving即织入,是指把增强应用到目标对象来创建新的代理对象的过程,它(例如 AspectJ 编译器)可以在编译时期,加载时期或者运行时期完成。
Target即目标对象,是织入切面的对象(被代理的对象)
Aop Proxy即AOP代理类,由AOP框架创建的对象,在Spring框架中,AOP代理对象有两种:JDK动态代理和CGLIB代理
编译期:
切面在目标类编译时被织入,这种方式需要特殊的编译器。AspectJ 的织入编译器就是以这种方式织入切面的。类加载期:
切面在目标类加载到 JVM 时被织入,这种方式需要特殊的类加载器( ClassLoader ),它可以在目标类引入应用之前增强目标类的字节码。运行期:
切面在应用运行的某个时期被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象,Spring AOP 采用的就是这种织入方式。这里只讲Spring AOP是如何使用的,不涉及原理分析。
Spring中使用@AspectJ风格的注解来定义AOP,主要用到这几个注解:@Aspect、@Pointcut和增强相关的几个注解。而@Pointcut和增强相关的注解,都使用切点表达式(切点标识符designator)定义切面使用的时机(何时何地)。AspectJ5 的切点表达式由标志符(designator)和操作参数组成. 如 "execution( greetTo(…))" 的切点表达式, execution 就是 标志符, 而圆括号里的 greetTo(…) 就是操作参数。标识符中,重要的有:execution、within、@annotation
execution 匹配方法执行的连接点(一般是限定到类的方法), 对于给定的作用域、返回值类型、完全限定类名以及参数匹配的方法将会应用切点函数指定的通知
//scope :方法作用域,如public,private,protect
//returnt-type:方法返回值类型
//fully-qualified-class-name:方法所在类的完全限定名称
//parameters 方法参数
execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))
within 匹配指定类型内的方法执行(一般是限定到类)
@annotation 根据所应用的注解进行方法过滤
匹配方法签名
// 匹配指定包中的所有的方法
execution(* com.xys.service.*(…))
// 匹配当前包中的指定类的所有方法
execution(* UserService.*(…))
// 匹配指定包中的所有 public 方法
execution(public * com.xys.service.*(…))
// 匹配指定包中的所有 public 方法, 并且返回值是 int 类型的方法
execution(public int com.xys.service.*(…))
// 匹配指定包中的所有 public 方法, 并且第一个参数是 String, 返回值是 int 类型的方法
execution(public int com.xys.service.*(String name, …))
匹配类型签名
// 匹配指定包中的所有的方法, 但不包括子包
within(com.xys.service.*)
// 匹配指定包中的所有的方法, 包括子包
within(com.xys.service…*)
// 匹配当前包中的指定类中的方法
within(UserService)
// 匹配一个接口的所有实现类中的实现的方法
within(UserDao+)
参考文章https://www.cnblogs.com/duanxz/p/5217689.html
在Spring中,早期是用xml配置的方式来定义,后面可以通过xml配置+注解、或者完全通过注解的方式来使用。
参考文章https://www.cnblogs.com/ysocean/p/7476379.html
在xml配置文件中添加如下语句,使能@AspectJ注解,再用注解定义切面。
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.huang.aop.basic"/>
在SpringBoot中,通过注解的方式定义一个配置类,从而使能@AspectJ注解
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
待补充
https://www.cnblogs.com/cxuanBlog/p/13060510.html 相对概述的一篇文章
https://segmentfault.com/a/1190000007469968 比较详细
https://javadoop.com/post/spring-aop-source 基于xml配置详细讲解源码
https://www.cnblogs.com/duanxz/p/5217689.html 详解标识符语法
https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247483954&idx=1&sn=b34e385ed716edf6f58998ec329f9867&chksm=ebd74333dca0ca257a77c02ab458300ef982adff3cf37eb6d8d2f985f11df5cc07ef17f659d4#rd 从java代理讲解AOP,实例比较好
https://blog.csdn.net/javazejian/article/details/56267036 详解AOP,论述清晰,有实例