一:什么是AOP
上一波百度百科…
AOP:全称是 Aspect Oriented Programming 即:面向切面编程
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
二:AOP作用及其优势
作用:
在程序运行期间,不修改源码对已有方法进行增强。
优势:
减少重复代码、提高开发效率、维护方便
三:AOP 的实现方式
使用动态代理技术
如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。
四:AOP 相关术语
Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。
在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
Pointcut(切入点):
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
简单来说,切入点 就是指 对需要增强的方法进行拦截,搭配切入点表达式
Advice(通知/增强):
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):
引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方
法或 Field。
Target(目标对象):
代理的目标对象。
Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理):
一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面):
是切入点和通知(引介)的结合(一个切入点类,类中有要进行通知的方法)
五:使用Spring实现AOP
使用AOP织入,需要导入一个依赖包。
<!--AOP织入-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一 、使用Spring的API接口
定义两个日志类 分别 实现 Spring 原生的API接口
配置类
<!--注册bean-->
<bean id="userService" class="com.csnz.service.UserServiceImpl"/>
<bean id="log" class="com.csnz.log.log"/>
<bean id="afterLog" class="com.csnz.log.AfterLog"/>
<!--方式一:使用原生Spring API接口-->
<!--配置AOP-->
<aop:config>
<!--切入点:在哪里执行方法 expression:表达式 execution( 要执行的位置 )-->
<aop:pointcut id="pointcut" expression="execution(* com.csnz.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
方式二、自定义类来实现AOP
主要是切面定义
<!--方式二:自定义类-->
<bean id="diy" class="com.csnz.diy.DiyPointCut"/>
<!--配置AOP-->
<aop:config>
<!--自定义切面:引用自定义的类-->
<aop:aspect id="diy" ref="diy">
<!--切入点:在哪里执行方法 expression:表达式 execution( 要执行的位置 )-->
<aop:pointcut id="pointcut" expression="execution(* com.csnz.service.UserServiceImpl.*(..))"/>
<!--通知-->
<!--前置通知-->
<aop:before method="before" pointcut-ref="pointcut"/>
<!--后置通知-->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
方式三、使用注解实现
AnnotationPointCut类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect //标注这个类是一个切面
@Component //创建bean对象
public class AnnotationPointCut {
// @Before("execution(* com.csnz.service.UserServiceImpl.*(..))")
@Before("pointCut()")
public void before(){
System.out.println("方法执行前 ~");
}
// @After("execution(* com.csnz.service.UserServiceImpl.*(..))")
@After("pointCut()")
public void after(){
System.out.println("方法执行后 ~");
}
//在环绕增强中,我们可以给定一个参数,代表我们要获取切入的点
// @Around("execution(* com.csnz.service.UserServiceImpl.*(..))")
@Around("pointCut()")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("环绕前");
pj.proceed();
System.out.println("环绕后");
}
//配置切入点 就不用 每次都在方法上重复写 切入点表达式
@Pointcut("execution(* com.csnz.service.UserServiceImpl.*(..))")
private void pointCut(){}
}
配置类
<!--方式二:使用注解配置 因为类上已经加了@Component注解 所以不用再注入了
<bean id="annotationPointCut" class="com.csnz.diy.AnnotationPointCut"/> -->
<!--开启 spring 对注解 AOP 的支持-->
<aop:aspectj-autoproxy/>