Spring(二)Spring AOP配置详解
来源:互联网 发布:js点击事件的写法 编辑:程序博客网 时间:2024/04/25 08:04
一、Spring AOP
面向切面编程(AOP),是软件编程思想发展到一定阶段的产物,是对面向对象编程(OOP)的有益补充。AOP一般适用于具有横切逻辑的场合,如访问控制、事务管理、性能监测等。面向切面编程,简单的说,就是在不改变源程序的基础上为代码段增加新的功能,对代码进行增强处理,它的设计思想来源于代理设计模式。
了解之后需要知道以下概念:
1.增强类型(Advice,有的翻译为通知,个人感觉不太好理解):
前置增强(通知),在在原方法执行之前进行处理,同理还有后置增强、环绕增强、异常抛出增强、最终增强等。
2.连接点(Joinpoint):
程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。
3.切点(Pointcut):
每个类都拥有多个连接点:类的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
下面编写一个HelloWorld:
需求:
在Student类中有一个说话的say方法,需要使用AOP对此方法进行增强处理。
package com.wzj.entity;public class Student {private int id;private String name;//省略get、set方法public void say(){System.out.println("大家好,我的名字叫:"+getName());}}
二、基于注解的方式实现spring aop增强
步骤:1.创建普通的java项目,加入jar包(在上文中有jar包的下载地址),创建好spring-config.xml文件,另外还要导入AspectJ框架所需jar包:aspectjweaver.jar、aopalliance.jar,可以百度下载
2.创建一个增强类如:AdviceUtil
(1)@Aspect注解——将类声明为切面
@Aspectpublic class AdviceUtil {}(2)@Before注解——声明为前置增强方法
/** * 使用@Before注解将方法声明为前置增强方法 * 参数中需要加入:匹配切点的表达式execution(public void com.wzj.entity.Student.say()) * 匹配切点的表达式:execution(修饰符 返回值 方法全名(..)) * 可以使用“*”和“..”通配符,* 表示匹配所有,.. 用在方法参数中,表示匹配任意个数、类型的参数 */@Before("execution(public void com.wzj.entity.Student.say()))")public void before(){System.out.println("----->前置增强操作");}(3)@AfterReturning注解——声明后置增强方法
@AfterReturning("execution(public void com.wzj.entity.Student.say())")public void behind(){System.out.println("----->后置增强操作");}【为了获取到代理对象以及方法的相关信息,可以再增强方法中声明一个JoinPoint类型参数,spring会自动注入该参数】
a-->getTarget():获取到代理对象
b-->getSignature:获取到目标方法,其中包含一些信息
c-->getArgs:获取到目标方法的参数列表
注意:对于后置增强还可以获取到目标方法的返回值,如:
/** * 1.在方法中声明一个目标方法的返回值参数 * 2.在AfterReturning注解中通过returning属性指定参数名称 * 3.spring会自动注入参数 * @param jp * @param returnValue */@AfterReturning(pointcut="execution(public * com.wzj.entity.Student.say())",returning="returnValue")public void behind(JoinPoint jp,String returnValue){System.out.println("目标方法返回值:"+returnValue);}(4)@AfterThrowing注解——声明异常抛出增强方法
/** * 1.使用AfterThrowing注解将方法声明为异常抛出增强 * 2.可以在方法中定义对应异常类型的参数,不过需要通过注解的throwing属性指定参数名 * 3.spring会自动注入异常类型实例 * 4.异常增强方法可以有多个 * @param ex */@AfterThrowing(pointcut="execution(public * com.wzj.entity.Student.say())",throwing="ex")public void catchException(ArithmeticException ex){System.out.println("异常增强捕获到:"+ex.getMessage());}(5)@Around注解——声明环绕增强方法
/** * 1.通过Around注解将方法声明为环绕增强 * 2.可以定义ProceedingJoinPoint类型的参数获取到连接点信息 * 3.ProceedingJpintPoint是JoinPoint的子接口,用法相同 * 4.注意:环绕增强不会自动调用目标方法,所以必须手动在方法中使用proceed()方法调用目标方法 * 从而达到对连接点的完全控制 * @param pj * @throws Throwable */@Around("execution(public * com.wzj.entity.Student.say())")public void around(ProceedingJoinPoint pj) throws Throwable{System.out.println("前面的处理...");pj.proceed();//调用目标方法System.out.println("后面的处理...");}(6)@After注解——声明最终增强方法
我们知道,如果在目标方法中抛出了异常,就不会执行后续的后置增强。在AspectJ中为我们提供了一种最终增强,无论是否出了异常都会执行,类似于try-catch中的finally块,一般用于释放资源
/** * 使用After注解,其他用法相同 */@After("execution(public * com.wzj.entity.Student.say())")public void after(){System.out.println("----->最终增强操作");}完整的AdviceUtil类:
package com.wzj.entity;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.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;/** * 使用@Aspect将此类定义为一个切面 */@Aspectpublic class AdviceUtil {/** * 匹配切点的表达式:execution(修饰符 返回值 方法全名(..)) * 可以使用“*”和“..”通配符,* 表示匹配所有,.. 用在方法参数中,表示匹配任意个数、类型的参数 */@Before("execution(void com.wzj.entity.Student.say())")public void before(){System.out.println("----->前置增强操作");}@AfterReturning(pointcut="execution(public * com.wzj.entity.Student.say())",returning="returnValue")public void behind(JoinPoint jp,String returnValue){System.out.println("----->后置增强操作");}@AfterThrowing(pointcut="execution(public * com.wzj.entity.Student.say())",throwing="ex")public void catchException(ArithmeticException ex){System.out.println("异常增强捕获到:"+ex.getMessage());}@Around("execution(public * com.wzj.entity.Student.say())")public void around(ProceedingJoinPoint pj) throws Throwable{System.out.println("前面的处理...");pj.proceed();//调用目标方法System.out.println("后面的处理...");}@After("execution(public * com.wzj.entity.Student.say())")public void after(){System.out.println("----->最终增强操作");}}3.在spring-config.xml文件中进行配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd"><!-- Student类的实例bean --><bean id="student" class="com.wzj.entity.Student" p:name="张三"/><!-- 切面的实例bean --><bean class="com.wzj.entity.AdviceUtil"></bean><!-- 使用注解方式需增加AspectJ的支持 --><aop:aspectj-autoproxy/></beans>4.main方法:
public static void main(String[] args) {//通过ApplicationContext接口的实现类实例化Spring上下文对象ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");//通过getBean()方法来获取到Student类的对象Student student=(Student)context.getBean("student");student.say();}
三、使用xml文件配置spring aop增强
1.前置增强:
(1)创建AdviceBefore类,实现MethodBefore接口及其before方法:public class AdviceBefore implements MethodBeforeAdvice{@Overridepublic void before(Method arg0, Object[] arg1, Object arg2)throws Throwable {System.out.println("前置增强的一些处理");}}
(2)配置xml文件:
需要导入aop的命名空间,配置(beans跟标签省略):
<!-- Student类的实例bean --><bean id="student" class="com.wzj.entity.Student" p:name="张三"/><!-- 前置增强类的实例 --><bean id="adviceBefore" class="com.wzj.advice.AdviceBefore"></bean><!-- 配置切面 --><aop:config><!-- 配置切点 --><aop:pointcut expression="execution(* com.wzj.entity.Student.say())" id="pt"/><!-- 将切点和具体的前置增强类实例粘合1.advice-ref:增强类实例的引用2.pointcut-ref:切入点的引用 --><aop:advisor advice-ref="adviceBefore" pointcut-ref="pt"/></aop:config>
2.后置增强:
(1)创建AdviceBehind类,实现AfterReturningAdvice接口中的afterReturning接口(2)配置:
<!-- 后置增强类的实例 --><bean id="adviceBehind" class="com.wzj.advice.AdviceBehind"></bean><aop:config>标签中添加:<aop:advisor advice-ref="adviceBehind" pointcut-ref="pt"/>
3.异常抛出增强:
(1)创建类,实现ThrowsAdvice接口,该接口中并没有提供方法,需要自己定义注意,方法的定义需要遵守下面的方法签名:
void afterThrowing([Method method,Object[] arguments,Object target,]Throwable ex)
a.-->方法名必须是afterThrowing(2)配置:
b.-->前三个参数要么都有,要么都没有,不能单个出现
c.-->Throwable类型的表示异常的类型
<!-- 异常类型的实例 --><bean id="adviceException" class="com.wzj.util.AdviceException"></bean><aop:config>标签中添加:<aop:advisor advice-ref="adviceException" pointcut-ref="pt"/>
4.环绕增强:
实现MethodInterceptor接口中的invoke方法,参数类型为MethodInvocation,调用参数的proceed()方法即可调用目标方法,其他配置上同。四、基于schema配置定义切面
我们还可以在spring配置文件中通过aop命名空间将一个普通的JavaBean中的方法 声明为增强类型1.创建一个普通的类,如:AdviceUtil
package com.wzj.entity.schema;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;public class AdviceUtil {public void before(){System.out.println("----->前置增强操作");}public void behind(JoinPoint jp,String returnValue){System.out.println("----->后置增强操作");}public void catchException(ArithmeticException ex){System.out.println("捕获到异常:"+ex.getMessage());}public void around(ProceedingJoinPoint pj) throws Throwable{System.out.println("前面的处理...");pj.proceed();//调用目标方法System.out.println("后面的处理...");}public void after(){System.out.println("----->最终增强操作");}}2.配置xml文件:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd"><!-- Student类的实例bean --><bean id="student" class="com.wzj.entity.Student" p:name="张三"/><!-- 含有增强方法的Bean --><bean id="advice" class="com.wzj.schema.AdviceUtil"></bean><!-- 配置切面 --><aop:config><!-- 定义切入点 --><aop:pointcut expression="execution(* com.wzj.entity.Student.say())" id="pt"/><!-- 引用包含增强方法的Bean --><aop:aspect ref="advice"><!-- 将其中的before方法定义为增强方法,并引用切点,下同 --><aop:before method="before" pointcut-ref="pt"/><!-- 如果有需要,可以使用returning属性向增强方法中注入返回值 --><aop:after-returning method="behind" pointcut="pt" returning="returnValue"/><aop:after-throwing method="catchException" pointcut-ref="pt"/><aop:around method="around" pointcut-ref="pt"/><aop:after method="after" pointcut-ref="pt"/></aop:aspect></aop:config></beans>
五、配置建议:
通过接口实现增强处理是较低版本的spring aop的做法,如果在一个使用较低版本的spring aop的项目上进行升级,可以考虑使用<aop:advisor>复用已经存在的增强类; 如果项目采用JDK5.0以上版本,可以使用注解的形式,减少配置工作量; 如果不想使用注解或者项目的JDK版本较低,可以使用aop:aspect配合javabean 的方式。 0 0
- Spring(二)Spring AOP配置详解
- Spring(二)Spring AOP配置详解
- Spring AOP详解(二)
- Spring--AOP 详解和使用(二)
- 深入浅出Spring(二) AOP详解
- Spring AOP(二、注解配置实现)
- Spring AOP (二)
- Spring AOP (二)
- Spring学习笔记(二)----Spring AOP配置与应用
- Spring(六)spring之AOP基本概念和配置详解
- Spring AOP使用配置介绍(二):切面的配置
- [Spring]一步步实现Spring AOP(二)
- spring随笔(二) AOP
- spring初学二(AOP)
- Spring IOC AOP (二)
- Spring AOP初探(二)
- Spring AOP 基础(二)
- Spring之AOP(二)
- 利用人性弱点赚钱的项目分析
- java基础:Http协议
- STL容器各项操作并非绝对安全
- MFC 创建ContextMenu
- 【Android基础-I】新建APP下各种文件的作用
- Spring(二)Spring AOP配置详解
- 【学习笔记+实践】网页简单布局之结构与表现分离
- 经典递归
- 有吸引力的服务营销(运营营销)案例
- 热插拔时间从内核空间到用户空间的传递过程
- 【呆子谈营销】:从街旁网的倒闭开始谈起
- Python 编码风格指南中译版(Google SOC)
- 全部希腊字母读音-数学公式中常用
- 软件如何控制硬件、编译器和操作系统是否需要编译