Spring(二)Spring AOP配置详解
来源:互联网 发布:淘宝无线端收藏链接 编辑:程序博客网 时间:2024/04/20 07:15
一、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注解——将类声明为切面
- @Aspect
- public class AdviceUtil {
- }
- /**
- * 使用@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("----->前置增强操作");
- }
- @AfterReturning("execution(public void com.wzj.entity.Student.say())")
- public void behind(){
- System.out.println("----->后置增强操作");
- }
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);
- }
- /**
- * 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());
- }
- /**
- * 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("后面的处理...");
- }
我们知道,如果在目标方法中抛出了异常,就不会执行后续的后置增强。在AspectJ中为我们提供了一种最终增强,无论是否出了异常都会执行,类似于try-catch中的finally块,一般用于释放资源
- /**
- * 使用After注解,其他用法相同
- */
- @After("execution(public * com.wzj.entity.Student.say())")
- public void after(){
- System.out.println("----->最终增强操作");
- }
- 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将此类定义为一个切面
- */
- @Aspect
- public 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("----->最终增强操作");
- }
- }
- <?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/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util-4.0.xsd
- http://www.springframework.org/schema/aop
- http://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>
- 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{
- @Override
- public 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("----->最终增强操作");
- }
- }
- <?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/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util-4.0.xsd
- http://www.springframework.org/schema/aop
- http://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(二)
- 手机端css中input的高度兼容问题
- 从浏览器或者App调起iOS应用之IOS自定义URL
- 安装Mutate时,add-apt-repository报:找不到命令
- 大数据融合技术:问题与挑战
- 数组的概念及创建
- Spring(二)Spring AOP配置详解
- VC6如何使用VS2005中的CImage类功能
- 软件开发行业,我来了。
- VC6如何使用VS2005中的CImage类功能2
- linux学习笔记之系统分区与文件格式化
- WPF textblock验证问题
- 自定义半圆进度view实现油门加速减速
- gulp watch error on CentOS 7
- 菜鸟学习Node.js--express(一)