Spring的AOP,在不惊动(改动)原有设计(代码)的前提下,想给谁添加功能就给谁添加。这个也就是Spring的理念:
无入侵式/无侵入式
AOP中核心概念分别指的是什么?
- 连接点
- 切入点
- 通知
- 通知类
- 切面
下面以一个例子进行讲解,直接上代码:
1,配置依赖坐标
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.14</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
2,定义接口与实现类
//接口
public interface BookDao {
public void save();
public void update();
public void delete();
public void select();
}
//实现类
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
//记录程序当前执行执行(开始时间)
Long startTime = System.currentTimeMillis();
//业务执行万次
for (int i = 0;i<10000;i++) {
System.out.println("book dao save ...");
}
//记录程序当前执行时间(结束时间)
Long endTime = System.currentTimeMillis();
//计算时间差
Long totalTime = endTime-startTime;
//输出信息
System.out.println("执行万次消耗时间:" + totalTime + "ms");
}
public void update(){
System.out.println("book dao update ...");
}
public void delete(){
System.out.println("book dao delete ...");
}
public void select(){
System.out.println("book dao select ...");
}
}
3,定义通知类和通知、定义切入点、制作切面
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.itheima.dao.BookDao.*d*(..))")
private void pt(){}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("------------------------------");
Long startTime = System.currentTimeMillis();
for (int i = 0 ; i<10000 ; i++) {
//调用原始操作
pjp.proceed();
}
Long endTime = System.currentTimeMillis();
Long totalTime = endTime-startTime;
System.out.println("执行万次消耗时间:" + totalTime + "ms");
return null;
}
}
讲解:
- Pointcut(切入点)
@Pointcut(“execution(* com.itheima.dao.BookDao.*d*(…))”)
这个注解定义了一个切入点,它匹配所有在com.itheima.dao.BookDao类中以d开头的方法的执行。
这里的*表示返回类型可以是任何类型
而(…)表示方法可以接受任意数量和类型的参数
*d*中的第一个星号表示返回值类型不限,d之后的星号表示方法名中必须包含字母d,但是可以在其后有其他字符。 - Around Advice(环绕通知)
@Around(“pt()”)
这个注解定义了一个环绕通知,它会在切入点匹配的方法被执行之前和之后执行。
在这个环绕通知中,首先打印了一条分割线,然后记录了开始时间,接着在一个循环中调用了原始方法10000次(pjp.proceed()),最后计算并打印了这10000次调用所花费的时间。 - ProceedingJoinPoint 是 AspectJ 框架中的一个接口,用于表示环绕通知(@Around)中的连接点(Join Point)。连接点是指程序执行过程中的某个特定点,例如方法的调用、异常的抛出等。在环绕通知中,ProceedingJoinPoint 对象提供了访问连接点信息和控制连接点执行的能力。
主要功能和方法:
获取连接点的信息:
getSignature(): 返回连接点的签名,通常是一个方法签名。
getArgs(): 返回连接点方法的参数数组。
getTarget(): 返回目标对象,即被增强的对象。
getThis(): 返回代理对象,即当前执行的代理对象。
控制连接点的执行:
proceed(): 执行连接点的方法。如果不调用这个方法,连接点的方法将不会被执行。
proceed(Object[] args): 使用指定的参数数组重新执行连接点的方法。
4,核心配置类,开启注解格式AOP功能
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
5,运行程序
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.select();
//bookDao.delete();
//bookDao.update();
//bookDao.save();
}
}
运行结果:
- bookDao.select():并没有执行增强功能,因为@Pointcut(“execution(* com.itheima.dao.BookDao.*d*(…))”)中d不包含select
- bookDao.delete():执行了增强功能
- bookDao.update():执行了增强功能
- bookDao.save():同样没有执行增强功能,因为@Pointcut(“execution(* com.itheima.dao.BookDao.*d*(…))”)中d不包含save
示例讲解概念
(1)前面一直在强调,Spring的AOP是对一个类的方法在不进行任何修改的前提下实现增强。对于上面的案例中BookServiceImpl中有save
,update
,delete
和select
方法,这些方法我们给起了一个名字叫连接点
(2)在BookServiceImpl的四个方法中,update
和delete
只有打印没有计算万次执行消耗时间,但是在运行的时候已经有该功能,那也就是说update
和delete
方法都已经被增强,所以对于需要增强的方法我们给起了一个名字叫切入点
(3)执行BookServiceImpl的update和delete方法的时候都被添加了一个计算万次执行消耗时间的功能,将这个功能抽取到一个方法中,换句话说就是存放共性功能的方法,我们给起了个名字叫通知
(4)通知是要增强的内容,会有多个,切入点是需要被增强的方法,也会有多个,那哪个切入点需要添加哪个通知,就需要提前将它们之间的关系描述清楚,那么对于通知和切入点之间的关系描述,我们给起了个名字叫切面
(5)通知是一个方法,方法不能独立存在需要被写在一个类中,这个类我们也给起了个名字叫通知类
至此AOP中的核心概念就已经介绍完了,总结下:
- 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
- 在SpringAOP中,理解为方法的执行
- 切入点(Pointcut):匹配连接点的式子
- 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
- 一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
- 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点。
- 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
- 通知(Advice):在切入点处执行的操作,也就是共性功能
- 在SpringAOP中,功能最终以方法的形式呈现
- 通知类:定义通知的类
- 切面(Aspect):描述通知与切入点的对应关系。
[说明]:内容主要来源黑马程序员网上资源学习