之前做完了一个SpringBoot项目非常匆忙,就是在视频里面学多少,就用多少,很多东西也没有深入学习和探究,今天就先从这个Spring
的AOP
开始一点一点补充吧!😋
笔记内容来自B站尚硅谷
AOP
概念
AOP(Aspect Oriented Programming)
是一种设计思想,是软件设计领域中的面向切面编程,是面向对象编程的一种补充和完善。
作用
- 简化代码:把方法中固定位置的重复的代码抽取出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。
- 代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就被切面给增强了。
基于注解的AOP
Spring AOP引入
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.23</version>
</dependency>
</dependencies>
具体的代码示例
/**
* 在切面中需要通过指定的注解将方法标识为通知的方法
* 前置通知@Before:在目标对象方法执行之前执行
* 切入点表达式:设置在标识通知的注解的Value属性中
* 第一种:@Before("execution(public int com.dinosaur.spring.aop.annotation..CalculatorImpl.add(int ,int))")
* 第二种:@Before("execution(* com.dinosaur.spring.aop.annotation.CalculatorImpl.*(..))")
* 第一个*表示任意访问修饰符和返回值类型
* 第二个*表示类中任意的方法
* ..表示任意的参数列表
* 类的地方也可以使用*,表示包下所有类
* 后置通知@After:在目标对象方法的finally中执行的
* 返回通知@AfterReturning:在目标对象方法对象返回值之后通知
* 异常通知@AfterThrowing:在目标对象方法的catch中执行
* <p>
* 获取连接点的信息
* 在通知方法的参数位置,设置JoinPoint类型的参数,就可以获取连接点所对应方法的信息
* 重用@Pointcut("execution(* com.dinosaur.spring.aop.annotation.CalculatorImpl.*(..))")
* public void pointCut() {}
* <p>
* 使用方式:@Pointcut@Before("pointCut()")
* <p>
* 可以通过@Order注解设置切面方法设置优先级,值越小优先级越高,默认值为Integer的最大值
*/
@Component
@Aspect // 将当前组件标识为一个切面
public class LoggerAspect {
// 公共的切入点表达式,切入点表达式的重用
@Pointcut("execution(* com.dinosaur.spring.aop.annotation.CalculatorImpl.*(..))")
public void pointCut() {
}
// 前置通知
// @Before("execution(public int com.dinosaur.spring.aop.annotation..CalculatorImpl.add(int ,int))")
@Before("pointCut()") // 任意方法的任意参数列表
public void beforeAdviceMethod(JoinPoint joinPoint) {
// 获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
// 获取连接点所对应方法的参数
System.out.println("LoggerAspect,方法" + signature.getName() + ",参数: " + Arrays.toString(joinPoint.getArgs()));
}
@After("pointCut()")
public void afterAdviceMethod(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect, 方法:" + signature.getName() + ",执行完毕");
}
// 要想在返回通知中若要获取目标对象的返回值,只需要通过@AfterReturning注解的returning属性
// 就可以将通知方法的某个参数指定为接受目标对象方法的返回值的参数
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturningAdviceMethod(JoinPoint joinPoint, Object result) {
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:" + signature.getName() + ", 结果:" + result);
}
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void afterThrowingAdviceMethod(JoinPoint joinPoint, Exception exception) {
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:" + signature.getName() + "异常:" + exception);
}
@Around("pointCut()")
public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
System.out.println("环绕通知-->前置通知");
// 表示目标对象的方法执行
result = joinPoint.proceed();
System.out.println("环绕通知-->返回通知");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("环绕通知-->异常通知");
} finally {
System.out.println("环绕通知-->后置通知");
}
return result;
}
}
ValidateAspect.java
@Component
@Aspect
@Order(1)
public class ValidateAspect {
// @Before("execution(* com.dinosaur.spring.aop.annotation.CalculatorImpl.*(..))")
@Before("com.dinosaur.spring.aop.annotation.LoggerAspect.pointCut()")
public void beforeMethod(JoinPoint joinPoint) {
System.out.println("ValidateAspect-->前置通知");
}
}
aop-annotation.xml
<!--
AOP的注意事项:
切面类和目标类都需要交给IOC容器管理
切面类必须通过@Aspect注解标识为一个切面
在Spring的配置文件中设置<aop:aspectj-autoproxy/>开启基于注解的AOP
-->
<context:component-scan base-package="com.dinosaur.spring.aop.annotation">
</context:component-scan>
<!--开启基于注解的AOP-->
<aop:aspectj-autoproxy/>
基于XML的AOP
具体代码
LoggerAspect.java
@Component
public class LoggerAspect {
public void beforeAdviceMethod(JoinPoint joinPoint) {
// 获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
// 获取连接点所对应方法的参数
System.out.println("LoggerAspect,方法" + signature.getName() + ",参数: " + Arrays.toString(joinPoint.getArgs()));
}
public void afterAdviceMethod(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect, 方法:" + signature.getName() + ",执行完毕");
}
public void afterReturningAdviceMethod(JoinPoint joinPoint, Object result) {
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:" + signature.getName() + ", 结果:" + result);
}
public void afterThrowingAdviceMethod(JoinPoint joinPoint, Exception exception) {
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:" + signature.getName() + "异常:" + exception);
}
public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
System.out.println("环绕通知-->前置通知");
// 表示目标对象的方法执行
result = joinPoint.proceed();
System.out.println("环绕通知-->返回通知");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("环绕通知-->异常通知");
} finally {
System.out.println("环绕通知-->后置通知");
}
return result;
}
}
ValidateAspect.java
@Component
public class ValidateAspect {
public void beforeMethod(JoinPoint joinPoint) {
System.out.println("ValidateAspect-->前置通知");
}
}
aop-xml.xml
<!--扫描组件-->
<context:component-scan base-package="com.dinosaur.spring.aop.xml"></context:component-scan>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.dinosaur.spring.aop.xml.CalculatorImpl.*(..))"/>
<!--将IOC容器中的某个Bean设置为切面-->
<aop:aspect ref="loggerAspect">
<aop:before method="beforeAdviceMethod" pointcut-ref="pointcut"/>
<aop:after method="afterAdviceMethod" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturningAdviceMethod" pointcut-ref="pointcut" returning="result"/>
<aop:after-throwing method="afterThrowingAdviceMethod" pointcut-ref="pointcut" throwing="exception"/>
<aop:around method="aroundAdviceMethod" pointcut-ref="pointcut"/>
</aop:aspect>
<aop:aspect ref="validateAspect" order="1">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
Calculator.java
public interface Calculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
CalculatorImpl.java
@Component
public class CalculatorImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("方法内部result=" + result);
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
System.out.println("方法内部result=" + result);
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
System.out.println("方法内部result=" + result);
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
System.out.println("方法内部result=" + result);
return result;
}
}