文章目录
1、AOP相关概念的介绍
Spring框架的关键组件之一是AOP框架,虽然Spring IoC容器不依赖于AOP,但在Spring应用中,经常会使用AOP来简化编程。
优势:
- 提供声明式企业服务,可以进行声明式事务管理
- 允许实现自定义的切面,某些不适用OOP编程的场景中,采用AOP来补充。
- 可以对业务逻辑的各个部分进行隔离,从而降低业务逻辑之间的耦合度,提高程序的可用性,同时提高了开发的小路。
Spring要使用AOP模块,需要导入spirng-aop模块对应的jar。
AOP核心概念:
AOP的概念使用大多数AOP框架,如AspectJ
、Sprng AOP
- Aspect(切面):将关注点模块化,可以横跨多个对象,例如事务管理。在SpringAOP中,切面可以使用常规类(基于模式的方法)或者使用@Apsect注解的常规类来实现。
- Join Point(连接点):在程序执行中抽取出来的特定点,例如方法调用时或处理处理时。Spring AOP中,连接点总是代表一个方法的执行。
- Advice(通知):在切面的某个特定的连接点上执行的动作,通知的类型有before、after等通知
- Pointcut(切入点):匹配连接点的断言,通知和一个切入点表达式关联。并在满足这个连接的上运行。(切入点表达式和连接点的匹配时AOP的核心)。
- Introduction(引入):声明额外的方法或者某个类型库的字段,SpringAOP的使用从允许一个新的接口(加上对应的实现类,使用的是JDK动态代理)到任何被通知的对象(不需要实现接口,普通的Java类,使用的是CGLIB代理)。
- Target Object(目标对象):被一个及以上的切面所通知的对象。Spring主要时通过运行代理实现的,所以目标对象来永远是一个Proxied(被代理)对象
- AOP Proxy(AOP代理):AOP框架创建的对象,用来实现Apsect Contract(切面契约)包含通知方法执行功能等。
- Weaving(织入):把切面连接到对象上,并创建一个Advised对象(代理对象)的过程。可以在编译时(AspectJ编译器)、类加载时和运行时完成(Spring AOP)
支持的通知:
- Before(前置通知):在连接点之前执行的通知(这个通知不能阻止连接前的执行,除非出异常)
- AferReturning(返回通知):在方法(连接点)正常执行后,没有异常的时候,就会执行到该方法
- AfterThrowing(抛出异常通知):在方法抛出异常推出的时候执行的通知
- After(最后通知):当方法退出时执行的语句,无论是否出现异常,都会执行
- Around(环绕通知):包围一个连接点的通知,是前面四个通知的总和。
Spriing目前只支持方法调用作为连接点使用,默认使用的JDK动态代理
,如果代理类没有实现接口
,再使用CGLIB代理
。
2、使用注解配置Spring AOP
Java配置类:
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration // 表明该类是配置类
@EnableAspectJAutoProxy // 启用Spring AOP
@ComponentScan("com.example") // 指定扫描的包
public class SpringAopConfig {
}
2.1、目标对象没有是接口
目标类:
package com.example.aop;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class GeneralPerson {
public void say(){
System.out.println("说活");
}
public void goHome(String tool){
System.out.println("使用交通工具"+tool+"回家");
}
public double pay(double money){
System.out.println("已经支付了"+String.format("%.2f",money)+"元");
BigDecimal bg = new BigDecimal(money);
/**
*
* 方法:setScale
* 参数:
* newScale - 要返回的 BigDecimal 值的标度。
* roundingMode - 要应用的舍入模式。
* 返回:
* 一个 BigDecimal,其标度为指定值,其非标度值可以通过此 BigDecimal 的非标度值乘以或除以十的适当次幂来确定。
*/
double result = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println(result);
return result;
}
/**
* 如果number为零,出现异常,被除数不能为0
* */
public int divide(int number){
return 10/number;
}
}
切面类
package com.example.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(1) // 指定执行顺序
@Aspect // 定义为一个切面
@Component
public class AdviceForPerson {
/**
* 对GeneralPerson的所有方法进行拦截
* */
@Pointcut("execution(* com.example.aop.GeneralPerson.*(..))")
public void pointcut(){
}
@Before("pointcut()"