Spring 中的Advice类型介绍
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 中的Advice类型介绍相关的知识,希望对你有一定的参考价值。
Spring 中的 Advice 类型介绍
翻译原文链接 Introduction to Advice Types in Spring
1. 概述
在本文中,我们将讨论可以在 Spring 中创建的不同类型的 AOP 通知。
通知是切面在特定连接点采取的行动。不同类型的通知包括 环绕、前置 和 后置 通知。切面的主要目的是支持横切关注点,例如日志记录、分析、缓存和事务管理。
如果您想更深入地了解切点表达式,请查看前面的介绍(Spring 中的切点表达式介绍)。
2. 启用通知
在 Spring 中,您可以使用 AspectJ 注解声明通知,但您必须首先将 @EnableAspectJAutoProxy
注解应用到您的配置类,这将支持处理标记有 AspectJ 的 @Aspect
注解的组件。
@Configuration
@EnableAspectJAutoProxy
public class AopConfiguration
// ...
2.1. Spring Boot
在 Spring Boot 项目中,我们不必显式使用 @EnableAspectJAutoProxy
。如果 Aspect 或 Advice 在类路径上,则有一个专用的 AopAutoConfiguration 可以启用 Spring 的 AOP 支持。
3. 前置通知
顾名思义,该通知在连接点之前执行。除非抛出异常,否则它不会阻止它通知的方法的继续执行。
(现在我们来)考虑下面的切面,(该切面用来)在调用之前简单记录方法名称:
@Component
@Aspect
public class LoggingAspect
private Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() ;
@Before("repositoryMethods()")
public void logMethodCall(JoinPoint jp)
String methodName = jp.getSignature().getName();
logger.info("Before " + methodName);
The logMethodCall advice will be executed before any repository method defined by the repositoryMethods pointcut.
4. 后置通知
使用 @After
注解声明的 后置通知在匹配的方法执行后执行,无论是否抛出异常。
在某些方面,它类似于 finally 块。如果你需要仅在正常执行后触发通知,则应使用 @AfterReturning
注解声明的返回通知。如果你希望仅在目标方法抛出异常时触发您的通知,您应该使用抛出通知,通过使用 @AfterThrowing
注解声明。
假设我们希望在创建 Foo 的新实例时通知某些应用程序组件。我们可以从 FooDao 发布一个事件,但这会违反单一职责原则。
相反,我们可以通过定义以下的切面来实现这一点:
@Component
@Aspect
public class PublishingAspect
private ApplicationEventPublisher eventPublisher;
@Autowired
public void setEventPublisher(ApplicationEventPublisher eventPublisher)
this.eventPublisher = eventPublisher;
@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods()
@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods()
@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods()
@AfterReturning(value = "entityCreationMethods()", returning = "entity")
public void logMethodCall(JoinPoint jp, Object entity) throws Throwable
eventPublisher.publishEvent(new FooCreationEvent(entity));
请注意,首先,通过使用 @AfterReturning
注解,我们可以访问目标方法的返回值。其次,通过声明 JoinPoint 类型的参数,我们可以访问目标方法调用的参数。
接下来我们创建一个监听器,它会简单地记录事件:
@Component
public class FooCreationEventListener implements ApplicationListener<FooCreationEvent>
private Logger logger = Logger.getLogger(getClass().getName());
@Override
public void onApplicationEvent(FooCreationEvent event)
logger.info("Created foo instance: " + event.getSource().toString());
5. 环绕通知
环绕通知围绕一个连接点,例如方法调用。
这是(功能)最强大的一种通知。环绕通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续连接点还是通过提供自己的返回值或抛出异常来缩短建议的方法执行。
为了演示它的用法,假设我们要测量方法执行时间。让我们为此创建一个切面:
@Aspect
@Component
public class PerformanceAspect
private Logger logger = Logger.getLogger(getClass().getName());
@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryClassMethods() ;
@Around("repositoryClassMethods()")
public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable
long start = System.nanoTime();
Object retval = pjp.proceed();
long end = System.nanoTime();
String methodName = pjp.getSignature().getName();
logger.info("Execution of " + methodName + " took " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
return retval;
当执行 repositoryClassMethods 切点匹配的任何连接点时,会触发此通知。
该通知采用 ProceedingJointPoint 类型的一个参数。该参数使我们有机会在目标方法调用之前采取行动。在这种情况下,我们只需保存方法启动时间。
其次,通知返回类型是 Object,因为目标方法可以返回任何类型的结果。如果目标方法为 void,则返回 null。在目标方法调用之后,我们可以测量时间,记录它,并将方法的结果值返回给调用者。
6. 总结
在本文中,我们学习了 Spring 中不同类型的通知及其声明和实现。我们使用基于模式的方法和 AspectJ 注解来定义切面。
所有这些示例和代码片段的实现都可以在我的 GitHub 项目 中找到。
以上是关于Spring 中的Advice类型介绍的主要内容,如果未能解决你的问题,请参考以下文章
Spring中的AOP——在Advice方法中获取目标方法的参数
Spring AOP 中 advice 的四种类型 before after throwing advice around