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日星期四)
相关推荐
本篇内容将对Spring AOP中基于AspectJ注解的使用进行总结,并通过实际案例进行解析。 首先,让我们理解AspectJ注解在Spring AOP中的核心概念: 1. **@Aspect**: 这个注解用于定义一个类为切面,这个类将包含切点和...
当启用AspectJ注解驱动的AOP(`@EnableAspectJAutoProxy`),Spring会自动创建代理对象来处理通知。此外,还可以通过`@AspectJSupport`和`<aop:aspectj-autoproxy>`元素来启用XML配置方式。 在实际应用中,AspectJ...
**Spring AOP 概念理解** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要组成部分,它允许我们通过...理解和熟练运用Spring AOP及其@AspectJ注解是每个Spring开发者必备的技能之一。
4. **启用注解驱动的AOP**: 在Spring配置中,使用`@EnableAspectJAutoProxy`注解开启对AspectJ注解的支持。 例如: ```java @Aspect @Component public class MyAspect { @Before("execution(* ...
`springAOP2`可能是一个包含具体示例代码的目录。`基于@AspectJ配置Spring AOP之一 - 飞扬部落编程仓库-专注编程,网站,专业技术.htm`和其关联的`_files`目录可能包含了一个详细的教程或演示如何配置和运行@AspectJ的...
在本主题中,我们将深入探讨Spring AOP的注解版,它是基于Java注解的实现,简化了配置并提高了代码的可读性。 首先,让我们理解AOP的基本概念。AOP是一种编程范式,允许程序员定义“切面”,这些切面封装了跨越多个...
总的来说,Spring AOP通过这四个关键的Jar包,结合AspectJ的强大功能和CGLIB的代理机制,为开发者提供了强大的面向切面编程支持,使得我们可以在不侵入原有业务代码的情况下,实现跨切面的关注点管理。
Spring支持两种AOP的实现方式:Spring AspectJ注解风格和Spring XML配置风格。使用AspectJ注解风格是最常见的,它允许开发者直接在方法上使用注解来定义切面。 Spring AOP中有五种不同类型的的通知(Advice): 1....
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来实现横切关注点,如日志、事务管理、性能监控等。本入门案例将帮助你理解并掌握Spring AOP的基本概念和使用方法。 在...
虽然Spring AOP提供了方便的注解式编程,但有时我们需要更复杂的切入点表达式或者更灵活的控制,这时AspectJ就派上用场了。AspectJ是一个独立的AOP框架,它的切入点表达式更为强大,支持类型匹配、方法参数匹配等。 ...
@AspectJ是Spring AOP的一个扩展,它提供了一种更接近传统编程的注解驱动的方式来定义切面。接下来,我们详细讲解如何使用@AspectJ进行切面定义: 1. **创建切面类**:首先,你需要创建一个Java类,并使用`@Aspect`...
Spring 提供了两种主要的 AOP 实现方式:基于代理的和基于 AspectJ 的。基于代理的方式是 Spring 默认的实现,它通过 JdkDynamicProxy 或 CGLIB 创建代理对象来实现切面。而基于 AspectJ 的方式则更为强大,它允许...
AspectJ是一个成熟的AOP框架,Spring在其AOP实现中整合了AspectJ,提供了更强大的面向切面编程能力。本篇文章将详细探讨在Spring 2.5中使用AspectJ进行AOP开发所需的知识点。 首先,我们需要理解AOP的核心概念: 1....
在这个版本中,Spring AOP支持基于注解的切面定义,比如`@Aspect`、`@Before`、`@After`等,同时也支持基于XML配置的切面定义。这个jar包使得Spring应用程序能够方便地利用AOP特性,无需引入额外的编译工具或构建...
在Spring AOP中,我们可以通过注解配置来实现切面编程,从而简化代码并提高可维护性。 首先,我们需要了解Spring AOP中的核心概念: 1. **切面(Aspect)**:切面是关注点的模块化,它包含了横切关注点(如日志)和...
下面将详细介绍Spring AOP的注解方式和XML配置方式。 ### 注解方式 #### 1. 定义切面(Aspect) 在Spring AOP中,切面是包含多个通知(advisors)的类。使用`@Aspect`注解标记切面类,例如: ```java @Aspect ...
8. **类型匹配(Type Matching)**:AspectJ的强项之一是类型匹配能力,它允许你基于类或接口来定义切入点,而不仅仅是方法签名,这比Spring AOP的基于方法签名的切入点更灵活。 9. **注解驱动(Annotation-Based)...
"9Spring AOP 盗梦空间之四——Around"这个标题暗示我们将深入探讨Spring AOP中的一个关键概念——环绕通知(Around Advice)。环绕通知是Spring AOP中功能最全面的通知类型,它提供了对方法执行前、执行后以及异常...
Spring AOP的实现主要有两种方式:一种是基于代理的AOP(Proxy-based AOP),另一种是基于AspectJ的AOP(AspectJ-based AOP)。基于代理的AOP是Spring默认的方式,它主要通过JDK动态代理或者CGLIB字节码生成技术来...