Spring中通知是什么
面向切面编程 这个切面是哪个面
面向切面编程(Aspect-Oriented Programming,AOP)是一种编程范式,它通过切面(Aspect)来分离横切关注点(Cross-cutting Concerns)和核心业务逻辑。
在AOP中,切面是对横切关注点的抽象和封装。横切关注点是指那些与核心业务逻辑无关,但又散布在各个模块中、影响多个模块的功能或行为,如日志记录、事务管理、安全检查等。切面通过定义通知(Advice)和切点(Pointcut)来描述横切关注点。
通知(Advice)定义了切面在何时、如何执行附加逻辑。例如,在方法执行前执行的前置通知、在方法执行后执行的后置通知、在方法抛出异常时执行的异常通知等。
切点(Pointcut)定义了切面所要应用的连接点(Join Point)。连接点是程序执行过程中能够触发切面的特定位置,如方法调用、方法执行、异常抛出等。切点表达式定义了哪些连接点符合切点的条件。
切面通过将通知和切点组织在一起,实现了对横切关注点的统一管理和重用。在Spring框架中,AOP通过代理技术和动态字节码生成实现。在运行时,Spring会根据配置将切面织入到目标对象中,从而实现横切关注点的功能。
总而言之,AOP是一种通过切面来分离横切关注点和核心业务逻辑的编程范式,切面通过定义通知和切点来描述和管理横切关注点。
Spring中通知
在Spring框架中,通知(Advice)是AOP的核心概念之一,用于定义在目标方法执行过程中需要执行的附加逻辑。通知可以在目标方法执行前、执行后或发生异常时被触发执行。
Spring框架提供了以下几种类型的通知:
-
前置通知(Before Advice):
前置通知在目标方法执行之前执行,可以在此处进行一些准备工作或参数校验等操作。例如,可以在前置通知中记录日志或进行权限检查。 -
后置通知(After Returning Advice):
后置通知在目标方法成功执行后执行,可以获取到目标方法的返回值,并进行一些后处理操作。例如,可以在后置通知中对返回结果进行处理或记录日志。 -
异常通知(After Throwing Advice):
异常通知在目标方法抛出异常时执行,可以捕获目标方法抛出的异常,并进行相应的处理操作。例如,可以在异常通知中发送告警或记录异常日志。 -
最终通知(After Advice):
最终通知在目标方法执行结束后(包括正常结束和异常结束)执行,无论目标方法是否抛出异常,最终通知都会被执行。例如,可以在最终通知中释放资源或进行清理操作。 -
环绕通知(Around Advice):
环绕通知是最为灵活的通知类型,它可以在目标方法执行前后都进行逻辑处理,并且可以控制是否执行目标方法。环绕通知需要负责显式地调用目标方法,并可以改变传递给目标方法的参数。
通过使用这些通知类型,我们可以将横切关注点(例如日志、事务管理等)与业务逻辑相分离,提高代码的可维护性和重用性。在Spring AOP中,通知是通过切面(Aspect)来组织和管理的。
Spring AOP中的通知举例:
@Aspect
@Component
public class MyAspect {
//定义前置通知
@Before("execution(* com.example.demo.service.UserService.addUser(..))")
public void beforeAddUser(JoinPoint joinPoint) {
System.out.println("before addUser");
}
//定义后置通知
@AfterReturning(value = "execution(* com.example.demo.service.UserService.addUser(..))", returning = "result")
public void afterAddUser(JoinPoint joinPoint, Object result) {
System.out.println("after addUser, result: " + result);
}
//定义异常通知
@AfterThrowing(value = "execution(* com.example.demo.service.UserService.addUser(..))", throwing = "ex")
public void afterAddUserException(JoinPoint joinPoint, Exception ex) {
System.out.println("after addUser exception, message: " + ex.getMessage());
}
//定义最终通知
@After("execution(* com.example.demo.service.UserService.addUser(..))")
public void afterAddUserFinally(JoinPoint joinPoint) {
System.out.println("after addUser finally");
}
//定义环绕通知
@Around("execution(* com.example.demo.service.UserService.addUser(..))")
public Object aroundAddUser(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around addUser start");
Object result = null;
try {
result = pjp.proceed();
System.out.println("around addUser end, result: " + result);
} catch (Throwable e) {
System.out.println("around addUser exception, message: " + e.getMessage());
throw e;
}
return result;
}
}
上面的代码中,我们定义了一个切面MyAspect,并在其中定义了前置通知、后置通知、异常通知、最终通知和环绕通知。这些通知分别会在UserService的addUser方法执行前后或出现异常时被触发执行。例如,在执行UserService的addUser方法前会执行beforeAddUser方法,执行成功后会执行afterAddUser方法,出现异常时会执行afterAddUserException方法,在执行结束时会执行afterAddUserFinally方法,在执行过程中会执行aroundAddUser方法。通过这些通知,我们可以对UserService的addUser方法进行统一的日志记录、事务管理等操作。