Spring Aop(四)——基于Aspectj注解的Advice介绍

简介: 4 基于Aspectj注解的Advice介绍 之前介绍过,Advice一共有五种类型,分别是before、after return、after throwing、after(finally)和around。

4 基于Aspectj注解的Advice介绍

之前介绍过,Advice一共有五种类型,分别是before、after return、after throwing、after(finally)和around。在使用注解的时候,它们对应的注解分别是@Before、@AfterReturning、@AfterThrowing、@After和@Around。 这几个注解都是在org.aspectj.lang.annotation包中。

4.1 @Before

Before Advice将在目标方法执行前执行Advice逻辑,通过它我们可以在指定的切入点方法执行前加入特定的逻辑。如下是定义的一个Before Advice,通过其value属性(注解中只指定value属性时属性名是可以省略的)指定其需要拦截的切入点id或name为userService的bean的方法执行,然后拦截后我们只是简单的打印一条语句,在实际应用中这里应该加上我们特定的逻辑。

@Before("bean(userService)")
public void before() {
	System.out.println("-----before with pointcut expression: bean(userService)------");
}

注:

  • 1、@Before除了可以通过value属性指定需要拦截的切入点外,还可以指定一个argNames属性,这个是用于方便我们在Advice中访问切入点方法参数的,这个在后续会专门用一篇文章来讲如何在Advice中使用切入点方法参数。
  • 2、argNames这个属性不仅在@Before上有,在其它的Advice注解上也有。
  • 3、除非抛出异常,否则Before Advice是没法阻止程序继续往下执行的。

所有的Advice方法都可以接收一个JoinPoint参数,而且这个参数必须是Advice方法的第一个参数,通过这个参数我们可以获取到目标方法的一些信息,比如当前方法调用传递的参数信息、目标对象等。而如果是Around类型的Advice则必须接受一个ProceedingJoinPoint类型的参数,ProceedingJoinPoint是JoinPoint的子类。

@Before("bean(userService)")
public void before(JoinPoint joinPoint) {
	System.out.println("-----before with pointcut expression: bean(userService)------");
	joinPoint.getArgs();//获取当前目标方法调用传递的参数
	joinPoint.getSignature();//获取当前目标方法的签名,通过它可以获取到目标方法名
	joinPoint.getThis();//获取AOP生成的代理对象
	joinPoint.getTarget();//获取被代理对象,即目标对象
	System.out.println(joinPoint.getArgs());
	System.out.println(joinPoint.getSignature().getName());
	System.out.println(joinPoint.getThis().getClass());
	System.out.println(joinPoint.getTarget().getClass());
	System.out.println(joinPoint.toString());
}

4.2 @AfterReturning

AfterReturning Advice对应的是切入点方法正常执行完的拦截,即切入点方法执行时没有对外抛出异常,包括在目标方法被Around类型的Advice处理时没有抛出异常,如果目标方法在被Around类型的Advice处理时也抛出了异常,则同样会被认为目标方法是执行异常的,因为Around Advice是最先处理的,AfterReturning Advice会在Around Advice处理结束后才被触发的。如果我们希望在AfterReturning Advice中根据目标方法的返回结果做特定的业务逻辑,那么我们可以给AfterReturning Advice处理方法加一个参数,参数类型可以是你能确定的目标方法返回类型或用通用的Object,然后需要在@AfterReturning上通过returning属性指定目标方法的返回值需要赋值给AfterReturning Advice处理方法的哪个参数。如下示例中就在Advice处理方法上加入了一个通用类型的Object类型的returnValue参数,然后指定@AfterReturning的returning属性为“returnValue”。如果我们确定目标方法的返回结果一定是一个User类型的,那么我们也可以指定下面的方法参数类型是User类型。

@AfterReturning(value="bean(userService)", returning="returnValue")
public void afterReturning(Object returnValue) {
	System.out.println("-----after returning with pointcut expression: bean(userService)------");
	System.out.println("-----return value is: " + returnValue);
}

4.3 @AfterThrowing

AfterThrowing Advice对应的是切入点方法执行对外抛出异常的拦截。因为当一个切入点方法可以同时被Around Advice和AfterThrowing Advice拦截时,实际上AfterThrowing Advice拦截的是Around Advice处理后的结果,所以这种情况下最终AfterThrowing Advice是否能被触发,还要看Around Advice自身是否对外抛出异常,即算是目标方法对外抛出了异常,但是被Around Advice处理了又没有向外抛出异常的时候AfterThrowing Advice也不会被触发的。如果希望在AfterThrowing Advice处理方法中获取到被抛出的异常,可以给对应的Advice处理方法加一个Exception或其子类型(能确定抛出的异常类型)的方法参数,然后通过@AfterThrowing的throwing属性指定拦截到的异常对象对应的Advice处理方法的哪个参数。如下就指定了拦截到的异常对象将传递给Advice处理方法的ex参数。

@AfterThrowing(value="bean(userService)", throwing="ex")
public void afterThrowing(Exception ex) {
	System.out.println("-----after throwing with pointcut expression: bean(userService)------" + ex);
}

AfterThrowing是用于在切入点方法抛出异常时进行某些特殊的处理,但是它不会阻止方法调用者看到异常结果。

4.4 @After

After Advice就相当于try…catch…finally语句里面的finally的角色,即无论被拦截的切入点方法是成功执行完成还是对外抛出了异常,对应的Advice处理方法都将会执行。

@After("bean(userService)")
public void after() {
	System.out.println("-----after with pointcut expression: bean(userService)------");
}

4.5 @Around

Around Advice必须接收一个ProceedingJoinPoint类型的方法参数,然后在方法体中选择一个合适的时机来调用ProceedingJoinPoint的proceed方法以触发对目标方法的调用,然后Around Advice处理方法的返回值会被当做是目标方法调用的返回值。所以通过Around Advice我们可以在通过ProceedingJoinPoint调用目标方法的前后加上特定的逻辑,包括使用try…catch…finally等,所以Around Advice是功能最强大的一个Advice,前面的任何一种Advice在应用的时候都可以被Around Advice替换。

@Around("bean(userService)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
	System.out.println("-----around with pointcut expression: bean(userService)------");
	System.out.println("---------------------调用前---------------------");
	Object result = pjp.proceed();
	System.out.println("---------------------调用后---------------------");
	return result;
}

在上面的示例中我们就通过Around Advice拦截了id或name为userService的bean的所有方法调用,把真实的目标方法的返回结果返回去了。而实际上我们这里还可以修改目标方法的返回结果,比如常用的就是Spring的缓存会通过Around Advice在调用目标方法前先从缓存中获取结果,如果获取到了则直接返回。这也是Around Advice跟AfterReturning Advice一个比较大的差别,AfterReturning Advice是不能改变返回对象的引用的,但是它可以改变返回对象的个别属性。在使用Around Advice时也可以改变目标方法调用时传递的参数,这个时候要用到ProceedingJoinPoint 的带参数的proceed(Object[] args)方法了。如下示例中我们就在Around Advice中把调用目标方法的参数替换为15了。

@Around("bean(userService)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
	System.out.println("-----around with pointcut expression: bean(userService)------");
	System.out.println("---------------------调用前---------------------");
	Object[] params = new Object[]{15};
	Object result = pjp.proceed(params);//可以调整目标方法调用时传递的参数
	System.out.println("---------------------调用后---------------------");
	return result;
}

4.6 Advice执行顺序

官方的说法是在进入切入点前优先级越高的越先执行,而在从切入点出去时优先级越高的会越后执行。当一个切面类中定义了多个Advice需要作用于同一个切入点时它们的执行顺序是不确定的,理由是无法通过反射获取到这些Advice在编译好的字节码中的声明顺序,这种情况下官方建议将多种切面逻辑整合到一个Advice中处理,以免造成错误。当两个定义在不同的切面中的Advice需要作用在同一个切入点时,除非你在切面类上使用@Order注解指定了顺序,数字越小表示优先级越高,或者是使切面类实现Ordered接口。以下是官方原文地址。 http://docs.spring.io/spring/docs/4.1.0.RELEASE/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering

(注:本文是基于Spring4.1.0所写,写于2017年1月19日星期四)

目录
相关文章
|
3天前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
|
23天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
165 73
|
18天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
49 21
|
11天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
51 8
|
23天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
23天前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
96 5
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
174 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
69 2
|
2月前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
137 0