1、什么是AOP
Aspect Oriented Programming AOP就是面向切面编程。
AOP 关注点是共同处理,可以通过配置将其作用到某一个或多个目标对象上。好处是实现组件重复
利用,改善程序结构,提高灵活性。将共通组件与目标对象解耦。通常用来进行程序扩展,或解决一些系统层面的问题,比如日志,事务,权限等操作
2、AOP中的几个相关概念
1)Aspect 切面:指的是共通业务处理,可以切入到多个目标对象,可以多次使用。
2)JoinPoint 连接点:指的是切面组件在目标对象上作用的的位置(方法上或者发生异常)
3)Pointcut 切入点:切入点是连接点的集合,采用表达式指定
4)TargetObject 目标对象
5)Advice 通知 :指的是切面组件在连接点上执行的动作
6)AutoProxy 动态代理
3、AOP 具体实现
1)编写AOP 切面业务逻辑
package com.seecen.aop.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
/**
* 日志切面
*
*/
@Component
public class LoggerAspect {
public void logger(){
System.out.println("记录操作日志。。。。");
}
/**
* after-returnning 方法
* @param retVal
*/
public void afterReturn(Object retVal){
System.out.println("---后置通知---"+retVal);
}
/**
* 异常通知
*/
public void afterException(Exception ex){
System.out.println("--异常通知begin--");
ex.printStackTrace();
System.out.println("--异常通知end--");
}
/**
* 环绕通知 配置为该通知后,
可以通过ProceedingJoinPoint 对象(连接点)来获取方法名、类名等
* @param pjp
* @return
* @throws Throwable
*/
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("方法调用前");
//调用对象的方法 并获取返回值
Object obj = pjp.proceed();
//获取调用的方法名
String method = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().getName();
System.out.println("执行了"+className+"的"+method+"方法");
return 2;
}
}
2)配置AOP
<!--通过注解注入-->
<context:component-scan base-package="com.seecen"></context:component-scan>
<!--aop 切面配置-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="servicePointcut" expression="execution(* com.seecen.aop.serviceImpl.*.*(..))"/>
<!--配置切面-->
<aop:aspect id="logger" ref="loggerAspect">
<!--方法执行之前通知-->
<aop:before method="logger" pointcut-ref="servicePointcut"/>
<!--方法执行之后通知-->
<aop:after method="logger" pointcut-ref="servicePointcut"/>
<!--环绕通知 配置为该通知后,
可以通过ProceedingJoinPoint 对象(连接点)来获取方法名、类名等-->
<aop:around method="around" pointcut-ref="servicePointcut"/>
<aop:after-returning method="afterReturn" pointcut-ref="servicePointcut" returning="retVal"></aop:after-returning>
<!--异常通知-->
<aop:after-throwing method="afterException" pointcut-ref="servicePointcut" throwing="ex" ></aop:after-throwing>
</aop:aspect>
</aop:config>
4、常用的通知类型
1)前置通知:在目标方法调用前执行,不能阻止后续执行,除非抛出异常
2)后置通知:<aop:after-returning>在目标方法调用之后执行。
3)最终通知:<aop:after> 目标方法调用之后无论如何都会执行(finally)
4)异常通知:<aop:after-throwing> 发生异常之后执行
5)环绕通知:<aop:around> 在目标方法调用之前或之后
注解方式配置AOP
<context:component-scan base-package="spring.aop"></context:component-scan>
<!--开启注解AOP-->
<aop:aspectj-autoproxy/>
package spring.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 描述:
*
* @author bigpeng
* @create 2019-10-25 13:25
*/
@Component
@Aspect
public class AopAspect {
/*
* 定义一个方法,用于声明切入点的表达式,一般地,该方法中不需要添加其他代码
* 使用@Pointcut来声明切入点表达式
* 后面的其他通知直接使用方法名来引用切入点表达式
*/
@Pointcut("execution(* spring.aop.*Impl.*(..))")
public void declareJoinPointExpression(){}
/*
* 在top.cheungchingyin.spring.aop.
* ArithmeticCalculator接口的每一个实现类的每一个方法开始之前执行一段代码
*/
@Before("declareJoinPointExpression()")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("The Method " + methodName + " Begins with " + Arrays.asList(args));
}
/*
* 返回通知:在方法执行后执行的代码,无论方法是否发生异常
*/
@After("declareJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " ends with");
}
/**
* 返回通知:在方法正常结束后执行代码 返回通知是可以访问到方法的返回值
*
* @param joinPoint
*/
@AfterReturning(value = "declareJoinPointExpression()", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " ends with " + result);
}
/**
* 在方法出现异常的时候会执行代码 可以访问到的异常对象,且可以指定出现特定异常的时候才执行通知代码
*
* @param joinPoint
* @param ex
*/
@AfterThrowing(value = "declareJoinPointExpression()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " occurs with " + ex);
}
/**
* 环绕通知需要携带ProceedingJoinPoint类型参数
* 环绕通知类似于动态代理的全过程,ProceedingJoinPoint类型的参数可以决定是否执行目标方法
* 且环绕通知必须要有返回值,返回值即为目标方法的返回值
*
* @param pjd
* @return
*/
@Around("declareJoinPointExpression()")
public Object arroundMethod(ProceedingJoinPoint pjd) {
Object result = null;
String methodName = pjd.getSignature().getName();
// 执行目标方法
try {
// 前置通知
System.out.println("【Around】The method 【" + methodName + "】 begins with" + Arrays.asList(pjd.getArgs()));
result = pjd.proceed();
// 后置通知
System.out.println("【Around】The Method " + " ends with 【" + result + "】");
} catch (Throwable e) {
// 异常通知
System.out.println("The method occurs exception" + e);
}
// 后置通知
System.out.println("【Around】The Method 【" + methodName + "】 ends ");
return result;
}
}