前言:AOP,也就是面向切面编程,作为面向切面编程的一种补充,已经比较成熟,如果是OOP是从静态角度考虑程序结构,那么AOP则是从动态角度考虑程序运行。本文旨在介绍Spring对AOP的支持,简述其用法。
本篇文章重点关注以下问题:
- SpringAOP访问目标方法的参数
- 增强处理的执行顺序
1. SpringAOP访问目标方法的参数
访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点。JoinPoint里包含了如下几个常用的方法:
- Object[] getArgs:返回目标方法的参数
- Signature getSignature:返回目标方法的签名
- Object getTarget:返回被织入增强处理的目标对象
- Object getThis:返回AOP框架为目标对象生成的代理对象
提示:当使用@Around处理时,我们需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。
2. 输出DEMO
测试项目目录如下图:
2.1 准备XML配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 指定自动搜索Bean组件、自动搜索切面类 --> <context:component-scan base-package="com.wj.chapter6.aop2"> <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/> </context:component-scan> <!-- 启动@AspectJ支持 --> <aop:aspectj-autoproxy/> </beans>
说明:
- <aop:aspectj-autoproxy/>用来启动Spring对@AspectJ的支持
- 有关<context:component-scan>使用说明可参考http://super-wangj.iteye.com/blog/2387655
2.2 编写切面类
下面的切面类中定义了Before、Around、AfterReturning和After 4中增强处理,并分别在4种增强处理中访问被织入增强处理的目标方法、目标方法的参数和被织入增强处理的目标对象等:
package com.wj.chapter6.aop2.aspect; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /** * 定义一个切面,用于测试对目标方法参数的访问 */ @Aspect public class FourAdviceTest { @Around("execution(* com.wj.chapter6.aop2.service.*.*(..))") public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable { System.out.println("【Around增强】执行目标方法之前,模拟开始事务..."); // 访问执行目标方法的参数 Object[] args = jp.getArgs(); // 当执行目标方法的参数存在, // 且第一个参数是字符串参数 if (args != null && args.length > 0 && args[0] instanceof String) { // 修改目标方法调用参数的第一个参数 args[0] = "【增加的前缀】" + args[0]; } //执行目标方法,并保存目标方法执行后的返回值 Object rvt = jp.proceed(args); System.out.println("【Around增强】执行目标方法之后,模拟结束事务..."); // 如果rvt的类型是Integer,将rvt改为它的平方 if(rvt != null && rvt instanceof Integer) rvt = (Integer)rvt * (Integer)rvt; return rvt; } @Before("execution(* com.wj.chapter6.aop2.service.*.*(..))") public void authority(JoinPoint jp) { System.out.println("【Before增强】模拟执行权限检查"); // 返回被织入增强处理的目标方法 System.out.println("【Before增强】被织入增强处理的目标方法为:" + jp.getSignature().getName()); // 访问执行目标方法的参数 System.out.println("【Before增强】目标方法的参数为:" + Arrays.toString(jp.getArgs())); // 访问被增强处理的目标对象 System.out.println("【Before增强】被织入增强处理的目标对象为:" + jp.getTarget()); } @AfterReturning(pointcut="execution(* com.wj.chapter6.aop2.service.*.*(..))", returning="rvt") public void log(JoinPoint jp , Object rvt) { System.out.println("【AfterReturning增强】获取目标方法返回值:" + rvt); System.out.println("【AfterReturning增强】模拟记录日志功能..."); // 返回被织入增强处理的目标方法 System.out.println("【AfterReturning增强】被织入增强处理的目标方法为:" + jp.getSignature().getName()); // 访问执行目标方法的参数 System.out.println("【AfterReturning增强】目标方法的参数为:" + Arrays.toString(jp.getArgs())); // 访问被增强处理的目标对象 System.out.println("【AfterReturning增强】被织入增强处理的目标对象为:" + jp.getTarget()); } // 定义After增强处理 @After("execution(* com.wj.chapter6.aop2.service.*.*(..))") public void release(JoinPoint jp) { System.out.println("【After增强】模拟方法结束后的释放资源..."); // 返回被织入增强处理的目标方法 System.out.println("【After增强】被织入增强处理的目标方法为:" + jp.getSignature().getName()); // 访问执行目标方法的参数 System.out.println("【After增强】目标方法的参数为:" + Arrays.toString(jp.getArgs())); // 访问被增强处理的目标对象 System.out.println("【After增强】被织入增强处理的目标对象为:" + jp.getTarget()); } }
从上面的代码可以看出,在Before、Around、AfterReturning、After四种增强处理中,其实都可以通过相同的代码访问被增强的对象、目标方法和方法的参数。但只有Around增强处理可以改变方法的参数和返回值。
2.3 编写业务类代码
接口+实现,业务相关接口就不上代码了,可以通过附件查看,下面是业务实现类:
package com.wj.chapter6.aop2.service; import org.springframework.stereotype.Component; @Component("addService") public class AddService implements IAddService { @Override public boolean addUser(String name , String pass){ System.out.println("【AddService.addUser】添加用户:" + name); return true; } @Override public void addProduct(String name) { System.out.println("【AddService.addProduct】添加商品:" + name); } @Override public void addException() { throw new NullPointerException(); } }
2.4 编写测试代码、查看运行结果
package com.wj.chapter6.aop2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.wj.chapter6.aop2.service.IAddService; public class BeanTest { // 1.指明xml配置文件位置,便于Spring读取,从而知道Bean的相关信息 private static final String PATH_XML = "com/wj/chapter6/aop2/applicationContext.xml"; @SuppressWarnings("resource") public static void main(String[] args) { // 2.根据xml配置文件,创建Spring IOC容器的上下文 ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH_XML); IAddService addService = ctx.getBean("addService" , IAddService.class); addService.addUser("熊燕子", "123456"); } }
测试结果为:
3. 访问目标方法参数的简单方式
我们可以在程序中使用args来绑定目标方法的参数。如果在一个 args表达式中指定了一个或多个参数,该切入点将只匹配具有对应形参的方法,且目标方法的参数值将被传入增强处理方法。下面辅以例子说明:
package com.wj.chapter6.aop3.aspect; import java.util.Date; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; @Aspect public class AccessArgAspect { // 下面的args(arg0,arg1)会限制目标方法必须有2个形参 @AfterReturning(returning="rvt" , pointcut="execution(* com.wj.chapter6.aop3.service.*.*(..)) && args(date,name,pass)") // 此处指定date为Date类型,name、pass为String类型 // 则args(date,name,pass)还要求目标方法的第一个参数为Date类型,后两个形参都是String类型 public void access(Object rvt, Date date, String name , String pass) { System.out.println("调用目标方法第1个参数为:" + date); System.out.println("调用目标方法第2个参数为:" + name); System.out.println("调用目标方法第3个参数为:" + pass); System.out.println("获取目标方法返回值:" + rvt); System.out.println("模拟记录日志功能..."); } }
上面的程序中,定义pointcut时,表达式中增加了args(date,name,pass)部分,意味着可以在增强处理方法(access方法)中定义date,name,pass三个属性——这三个形参的类型可以随意指定,但一旦指定了这三个参数的类型,则这三个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二、三个参数类型为String的方法(方法参数个数和类型若有不同均不匹配)。
args表达式有如下两个作用:
-
提供了一种简单的方式来访问目标方法的参数
-
可用于对切入点表达式作额外的限制
相关推荐
本入门案例将帮助你理解并掌握Spring AOP的基本概念和使用方法。 在Spring AOP中,我们首先需要了解的是"切面"(Aspect)的概念。切面是封装了横切关注点的代码模块,它可以包含通知(Advice)、切点(Pointcut)和...
Spring支持三种织入时机:编译时(使用AspectJ编译器)、加载时(使用AspectJ LTW)和运行时(Spring容器初始化时)。 7. **源码分析**: 在Spring AOP的源码中,`org.springframework.aop.framework....
下面我们将深入探讨Spring AOP的相关概念和使用方法。 ### 1. AOP的基本概念 - **切面(Aspect)**:切面是关注点的模块化,它结合了通知(Advice)和切点(Pointcut)定义。 - **通知(Advice)**:在特定连接点...
Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...
本压缩包文件主要涵盖了Spring框架的核心部分——Spring MVC和AOP(面向切面编程)的详细知识,对于想要深入理解和运用Spring框架的开发者来说,是一份非常宝贵的资源。 首先,我们来看看《Spring3.20权威开发指南...
在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理、权限检查等)与核心业务逻辑解耦。AOP的核心概念是切面、通知、连接点、切入点和织入。在...
比如,可能在定义AOP通知(advises)或切点(pointcuts)时,使用了错误的表达式或者没有正确地指定目标方法。 2. **类加载问题**:由于Struts2和Spring使用不同的类加载机制,可能会导致类找不到或者重复加载的...
"spring-aop-jar"这个主题涉及到Spring框架中的核心组件之一——Spring AOP。这里我们将深入探讨Spring AOP、相关jar文件以及它们在实际开发中的作用。 首先,我们来看一下提供的文件: 1. aopalliance.jar:这是一...
现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...
Spring容器简介——AOP AOP核心概念 Spring AOP的使用 Spring AOP常见用法 示例代码
通过阅读《Spring AOP盗梦空间之二——获得返回值AfterReturnning》这篇博文(链接:https://garrincha.iteye.com/blog/2111779),你可以获得更详细的实践指导和示例代码。同时,结合提供的压缩包文件"Spring_AOP_...
Spring框架是Java开发中不可或缺的一部分,它通过提供两种核心特性——控制反转(IoC)和面向切面编程(AOP)来简化应用的构建。理解并掌握这两种技术对于任何Java开发者来说都至关重要。 **控制反转(IoC)**,也...
本文将深入探讨“Spring AOP——Schema”,这是Spring AOP的一种配置方式,通过XML schema定义切面和通知。 首先,我们需要理解AOP的基本概念。面向切面编程是一种编程范式,旨在提高软件的模块化程度,将关注点...
在本文中,我们将深入探讨如何在Spring Security 2.0版本中配置并使用AOP(面向切面编程)来实现方法级别的权限控制。首先,我们需要理解Spring Security的基础概念。 1. **Spring Security基本架构** Spring ...
本篇文章将深入探讨@AspectJ的使用方法和背后的原理。 首先,我们需要理解面向切面编程(AOP)的基本概念。AOP是一种编程范式,它允许开发者将关注点(如日志、事务处理)与业务逻辑分离,从而提高代码的可读性和可...
首先,我们来理解Spring AOP的基本概念。在Spring中,切面由通知(advises)和切点(pointcuts)组成。通知是在特定的程序执行点执行的代码,例如方法调用前或后。切点则是定义这些执行点的规则,通常基于方法签名或...
《深入解析Spring AOP框架——以spring-aop.jar为例》 Spring AOP,全称Aspect Oriented Programming(面向切面编程),是Spring框架的核心部分之一,它为Java开发者提供了强大的面向切面的编程能力。本文将围绕...
Spring AOP,全称Aspect Oriented Programming(面向切面编程),是Spring框架的重要组成部分,它为应用程序提供了一种模块化和声明式的方式来处理交叉关注点,如日志、事务管理、性能监控等。通过AOP,我们可以将...
5. **启用AOP**:为了使AOP生效,我们需要在Spring配置中启用AOP支持,这可以通过在XML配置中添加`<aop:aspectj-autoproxy>` 或者在Java配置中使用`@EnableAspectJAutoProxy` 注解来实现。 在"Spring3.1.0Demo2-AOP...