
AOP 的理解?
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性;
Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP会使用JDK Proxy去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,Cglib 生成一个被代理对象的子类来作为代理;
AOP的相关概念:
- Advice(通知):通知定义了切面什么时候引用;
- Join point(连接点):连接点是在程序执行过程中能够插入的一个点,切面代码可以利用这些点插入到程序的正常流程中;
- Poincut(切点):切点有助于缩小切面所通知的连接点的范围;
- Aspect(切面):切面时通知和切点的结合;
- Introduction(引入):允许我们向现有的类引入新的方法或属性;
- Weaving(织入):把切面应用到目标对象并创建新的代理对象的过程;
Spring切面的5种通知方式:
- Before(前置通知):在目标方法被调用之前调用通知功能;
- After(后置通知):在目标方法完成之后通知,此时不关心方法返回的是什么;
- After-returning(返回通知):在目标方法成功执行之后调用通知;
- After-throwing(异常通知):在目标方法抛出异常之后掉用;
- Around(环绕通知):通知包裹了被通知的方法,在被通知方法的调用前和调用后执行自定义的行为;
上代码:
package com.cn.concert;
/**
* @ClassName Audience
* @Author 小林林同学
* @Date 2021/6/19 17:10
**/
@Aspect
@Component
public class Audience {
@Pointcut("execution(* com.cn.concert..*(..))")
public void performance(){}
//前置通知
@Before("performance()")
public void silenceCellPhone(){
System.out.println("表演之前,手机静音!");
}
//前置通知
@Before("performance()")
public void takeSeats(){
System.out.println("表演之前,禁止说话!");
}
//后置返回通知
@AfterReturning("performance()")
public void applause(){
System.out.println("表演之后!");
}
//异常通知
@AfterThrowing("performance()")
public void demandRefund(){
System.out.println("表演失败之后!");
}
//环绕通知
@Around("performance()")
public void watchPerformance(ProceedingJoinPoint joinPoint){
try{
System.out.println("表演之前,手机静音!");
System.out.println("表演之前,禁止说话!");
Object[] args = joinPoint.getArgs();
Object proceed = joinPoint.proceed();
System.out.println(args.length);
for(Object o:args){
System.out.println(o);
}
System.out.println(proceed);
System.out.println("表演之后!");
}catch (Throwable e){
System.out.println("表演失败之后!");
}
}
}
package com.cn.concert;
public interface Performance {
public Integer perform(int i);
}
package com.cn.concert;
/**
* @ClassName testPerformance
* @Author 小林林同学
* @Date 2021/6/19 17:33
**/
@Component
public class TestPerformance implements Performance {
public Integer perform(int i) {
System.out.println("跳舞!!");
return i;
}
}
package com.cn.config;
/**
* @ClassName ConcerConfig
* @Author 小林林同学
* @Date 2021/6/19 17:18
**/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com"})
public class ConcerConfig {
@Bean
public Audience audience(){
return new Audience();
}
}
知识点:

- 使用注解@Aspect表示该类不仅是一个POJO,还是一个切面。
- 使用注解@Pointcut来定义命名切点,之后就可以在任意的通知注解表达式中使用它;
- 在环绕通知中,当要将控制权交给被通知的方法需要调用proceed()方法,未调用会阻塞对被通知方法的调用,在环绕通知中回去被通知方法的参数可调用getArgs()方法,获取返回值则在调用proceed()后获取;
- 记得在配置类中使用注解@EnableAspectAutoProxy来启用Aspect自动代理;