Spring中AOP简介与切面编程的使用
Spring中AOP简介与使用
什么是AOP?
Aspect Oriented Programming(AOP),多译作 “面向切面编程”,也就是说,对一段程序,从侧面插入,进行操做。即通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
为什么要用AOP?
日志记录,性能统计,安全控制,事务处理,异常处理等等。例如日志记录,在程序运行的某些节点上添加记录执行操作状态的一些代码,获取执行情况。而通过切面编程,我们将这些插入的内容分离出来,将它们独立到业务逻辑的方法之外,进而使这些行为的时候不影响业务逻辑的执行。
如何使用AOP?
下面我们以一个简单计算题目的例子用日志记录的方法演示一下面向切面编程。
(同时我们使用到Junit4来测试程序)
环境: jdk1.8
新建Dynamic Web Project
Jar包: (包的版本不定,可以根据个人开发需求添加,下面基本为必须包)
-com.springsource.net.sf.cglib-2.2.0.jar
-com.springsource.org.aopalliance-1.0.0.jar
-com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
-commons-logging-1.1.3.jar
-spring-aop-4.0.0.RELEASE.jar
-spring-aspects-4.0.0.RELEASE.jar
-spring-beans-4.0.0.RELEASE.jar
-spring-context-4.0.0.RELEASE.jar
-spring-core-4.0.0.RELEASE.jar
-spring-expression-4.0.0.RELEASE.jar
以下分两种方式来说明
一、注解的方式
开发步骤:
1、创建方法类
这个类中写了主要的业务操作步骤,选取了加法和出发作为案例(除法较为典型)
- package da.wei.aop;
- import org.springframework.stereotype.Component;
- @Component //普通类的注解配置spring.xml的配置,加入IOC容器
- public class MathTestImpl {
- public Integer add(int i,int j){
- System.out.println("执行add,参数i为: "+i+" ,参数j为: "+j+" ,结果为: "+(i+j));
- return (i+j);
- }
- public Integer div(int i,int j){
- System.out.println("执行div,参数i为: "+i+" ,参数j为: "+j+" ,结果为: "+(i/j));
- return (i/j);
- }
- }
该方法中需要强调一点规范问题,在使用函数返回值类型或者类的属性设置时,使用包装类型(Integer)来代替基本类型(int)可以避免不少错误。
2、创建多个方法的切面类
在这个切面类中,我们将每个通知类型的内容都单独列出来了,每一层都罗列其执行的效果。
其中有以下几个知识点
1)、切点注释@PointCut 通过配置切点方法可以将切点统一使用,减少了代码量,提高开发效率。
2)、切入点表达式
execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )
此处用到的时详细的有制定切唯一的方法,开发中我们不可能只有一个方法,因此可以用’*’通配符的方式表示,同时,方法返回值类型、权限修饰符、参数列表、包名、也可能不唯一,因此,可以优化为通配格式:
execution(* *.*(..)) 第一个’*’表示了权限修饰符以及方法返回值类型‘
3)、Before 中JoinPoint参数
Before 中JoinPoint参数可以获取切入点处方法的几乎全部信息,其中的方法名以及参数列表是常用信息
4)、AfterReturning 中的returning参数
AfterReturning 中的returning参数是用来接收切入方法的返回值的,其参数名需要其修饰方法体的参数名相同,同时由于参数类型不定,需要设为Object类型的
5)、Throwing 中的throwing参数
Throwing 中的throwing参数,用来获取异常信息值;其中throwing= “参数名a” 需要与方法中的参数相等对应。
- package da.wei.aop;
- import java.util.Arrays;
- import java.util.List;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.Signature;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.AfterThrowing;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
- /*
- * @Component 普通类的注解配置spring.xml的配置,加入IOC容器
- * @Aspect 标识出此类为切面方法类
- * Order 是为了指定在多个切面类的情况下,其执行的顺序;
- * value值为int类型的,值越小越先执行
- */
- @Component
- @Aspect
- @Order(value=)
- public class MathAspectMutil {
- //设置切点位置 此处设置的是add(int,int)方法
- @Pointcut(value="execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )")
- public void getPointCut(){}
- //注解,设置此方法是‘前置通知’
- @Before(value="getPointCut()")
- public void before(JoinPoint point){
- System.out.println("[MathAspectMutil]【Before日志】");
- //获取插入点的参数
- Object[] args = point.getArgs();
- //获取方法签名
- Signature signature = point.getSignature();
- //获取方法名
- String name = signature.getName();
- //将参数数组传为list
- List<Object> asList = Arrays.asList(args);
- System.out.println("方法签名 : "+signature);
- System.out.println("方法名为 : "+name+"方法体参数列表 : "+asList);
- }
- /*
- * 注解,设置此处是‘后置通知’
- * 此处可以看出其value值与上面before方法的不一样
- * 实则是一样的,只是通过PointCut将其统一封装使用而已,效果相同
- */
- @After(value="execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )")
- public void after(){
- System.out.println("[MathAspectMutil]【After日志】");
- }
- //注解,设置此方法是‘返回通知’
- @AfterReturning(value="getPointCut()",returning="result")
- public void afterReturning(JoinPoint point,Object result){
- System.out.println("[MathAspectMutil]【AfterReturning日志】");
- //获取插入点的参数
- Object[] args = point.getArgs();
- //获取方法签名
- Signature signature = point.getSignature();
- //获取方法名
- String name = signature.getName();
- //将参数数组传为list
- List<Object> asList = Arrays.asList(args);
- System.out.println("方法签名 : "+signature);
- System.out.println("方法名为 : "+name+"方法体参数列表 : "+asList+" ,执行结果为: "+result);
- }
- //注解,设置此方法是‘异常通知’
- @AfterThrowing(value="getPointCut()",throwing="ex")
- public void afterThrowing(Throwable ex){
- System.out.println("[MathAspectMutil]【AfterThrowing日志】");
- System.out.println("错误信息为 : "+ex.getMessage());
- }
- }
3、创建Around方法的切面类
Around方法其就是对上面四种通知的合并,在环绕通知中上面的四种通知都有体现到
通过对下面代码的分析就可以基本了解其运行结果了
- package da.wei.aop;
- import java.util.Arrays;
- import java.util.List;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.Signature;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
- @Component
- @Aspect
- @Order(value=5)
- public class MathAspectAround {
- //设置切点位置 此处设置的是add(int,int)方法
- @Pointcut(value="execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )")
- public void getPointCut(){}
- @Around(value="getPointCut()")
- public Object around(ProceedingJoinPoint pJoinPoint){
- //获取插入点的参数
- Object[] args = pJoinPoint.getArgs();
- //获取方法签名
- Signature signature = pJoinPoint.getSignature();
- //获取方法名
- String name = signature.getName();
- //将参数数组传为list
- List<Object> asList = Arrays.asList(args);
- Object result = null;
- try {
- try{
- System.out.println("[MathAspectAround]【Before】...");
- System.out.println("方法签名 : "+signature);
- System.out.println("方法名为 : "+name+"方法体参数列表 : "+asList);
- //获得结果
- result = pJoinPoint.proceed(args);
- }finally {
- System.out.println("[MathAspectAround]【After】....");
- }
- System.out.println("[MathAspectAround]【AfteReturning】..结果为"+result+"....");
- } catch (Throwable e) {
- // TODO Auto-generated catch block
- System.out.println("[MathAspectAround]【Throwing】..原因为 "+e.getMessage());
- }
- return result;
- }
- }
4、配置spring.xml
我这里的spring配置文件名为applicationContext.xml
- <!-- 扫描包,创建Bean对象 -->
- <context:component-scan base-package="da.wei.aop"></context:component-scan>
- <!-- 启用 切面编程注解 -->
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
5、Junit中代码编写
此处讲解AOP的使用至于IOC的使用就不再赘述。
- @Test
- public void test() {
- //获取applicationContext配置信息,主要用于获得IOC容器中的类对象
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
- //获取bean对象
- MathTestImpl bean = (MathTestImpl) applicationContext.getBean("mathTestImpl");
- /*
- * 调用方法
- * 由于在配置里只编写了针对add的切入点这里只执行add方法
- * 在之后的xml配置的方法中执行div方法
- */
- bean.add(1,2);
- //bean.div(10, 2);
- }
6、执行结果
从执行结果中我们能看到已经正确执行了,同时我们也要注意到两种方式的执行顺序。
由于我们设置MathAspectMutil的Order为100 比MathAspectAround的5大因此MathAspectAround先执行,当其执行完before之后释放的方法又被MathAspectMutil获取,当MathAspectMutil执行完全部之后MathAspectAround再执行其他的方法,类似于拦截器的运行顺序。
二、spring.xml配置的方式
spring.xml配置的方式其类的建立与上面相同,只是需要去除所有的注解,使用简单的方法,简单的类
1、其中的applicationContext.xml配置如下
- <bean id="mathTestImpl" class="da.wei.aop.MathTestImpl"></bean>
- <bean id="mathAspectMutil" class="da.wei.aop.MathAspectMutil"></bean>
- <bean id="mathAspectAround" class="da.wei.aop.MathAspectAround"></bean>
- <aop:config >
- <!-- 第一个 好多方法的切面类 -->
- <aop:pointcut expression="execution(* da.wei.aop.MathTestImpl.*(..))" id="myPointCut"/>
- <aop:aspect ref="mathAspectMutil" order="10">
- <aop:before method="before" pointcut-ref="myPointCut" />
- <aop:after method="after" pointcut-ref="myPointCut"/>
- <aop:after-returning method="afterReturning" pointcut-ref="myPointCut" returning="result"/>
- <aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="ex"/>
- </aop:aspect>
- <!-- Around -->
- <aop:aspect ref="mathAspectAround" order="5">
- <aop:around method="around" pointcut-ref="myPointCut" />
- </aop:aspect>
- </aop:config>
2、Junit代码如下
- @Test
- public void test() {
- //获取applicationContext配置信息,主要用于获得IOC容器中的类对象
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
- //获取bean对象
- MathTestImpl bean = (MathTestImpl) applicationContext.getBean("mathTestImpl");
- bean.div(10, 2);
- System.out.println();
- bean.div(10, 0); //此处我们测试了异常情况
- }
3、执行结果
从结果总我们可以看出当执行异常出现的时候,会执行性Throwing而不执行AfterReturning,这个也可以在Around的代码中可以看出。
以上是我最近学习AOP切面编程的一点总结,内容多为代码,总结不足,不过开发与思路过程在注释中有体现,希望能给大家一些帮助。
同时欢迎过路大神指点批评。
Spring中AOP简介与切面编程的使用的更多相关文章
- 02 浅析Spring的AOP(面向切面编程)
1.关于AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.O ...
- Spring之AOP实现面向切面编程
近期在学Java的动态代理和Spring面向切面编程,越来越认为Spring设计的真的是太完美了.于是,想一个最简单的样例来跑一下.但问题多多,显示缺少,Aspectj里面的相应的类.导入Aspect ...
- Spring核心AOP(面向切面编程)总结
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/75208354冷血之心的博客) 1.AOP概念: 面向切面编程,指扩 ...
- 杂项-编程:AOP(面向切面编程)
ylbtech-杂项-编程:AOP(面向切面编程) 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一 ...
- spring学习总结二-----面向切面编程(AOP)思想
上一篇spring博客简总结了spring控制反转和依赖注入的相关思想知识点,这篇博文对spring的面向切的编程思想进行简单的梳理和总结. 一.面向切面的思想 与面向对象的纵向关系概念不同,面向切面 ...
- AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...
- Spring(三)面向切面编程(AOP)
在直系学长曾经的指导下,参考了直系学长的博客(https://www.cnblogs.com/WellHold/p/6655769.html)学习Spring的另一个核心概念--面向切片编程,即AOP ...
- Spring的三大核心思想:IOC(控制反转),DI(依赖注入),AOP(面向切面编程)
Spring核心思想,IoC与DI详解(如果还不明白,放弃java吧) 1.IoC是什么? IoC(Inversion of Control)控制反转,IoC是一种新的Java编程模式,目前很多 ...
- Spring 中aop切面注解实现
spring中aop的注解实现方式简单实例 上篇中我们讲到spring的xml实现,这里我们讲讲使用注解如何实现aop呢.前面已经讲过aop的简单理解了,这里就不在赘述了. 注解方式实现aop我们 ...
随机推荐
- 微信小程序开发问答《五十四》同步请求授权 & 用户拒绝授权,重新调起授权 ... ...
1.同步请求授权 需求分析: 1.在小程序首次打开的时候,我需要同时请求获取多个权限,由用户逐一授权. (['scope.userInfo','scope.userLocation','scope.a ...
- VSCode自定义配色方案
说明 本文更新于2017-07-24,使用VSCode 1.14.1,操作系统为Windows. 配置文件 "文件-首选项-颜色主题"即可显示所有可用的颜色主题,上下选择后Ente ...
- Java 程序员技能导图 1.0
做Java开发已经一年,并非科班出身,在毕业工作三年后毅然决然辞职,参加培训机构从零开始.在这期间迷茫.失望.绝望时常伴我左右,但是在不断自我提高与努力中渐渐看到一些小小的成果使我不断坚信自己的选择并 ...
- elk 5.x的部署
前言 elk是由elasticsearch.logstash.kibana三者组成 其中elasticsearch主要负责数据存储与搜索 logstash主要负责收集日志信息以及对日志信息的切片索引等 ...
- JavaScript中的call()、apply()与bind():
关于call()与apply(): 在JavaScript中,每个函数都有call与apply(),这两个函数都是用来改变函数体内this的指向,并调用相关的参数. 看一个例子: 定义一个animal ...
- [Android]Android焦点流程代码分析
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/7286503.html 通过View的View::focusSe ...
- Python爬虫初学(一)—— 爬取段子
最近开始学Python的爬虫,是在这个博客跟着学习的,该博主用的是Python 2.7版本,而我使用的是3.5版本,很多不兼容的地方,不过没关系,自己改改就好了. 我们想针对网站的内容进行筛选,只获取 ...
- 为Tornado框架加上基于Redis或Memcached的session 【第三方】
Tornado 没有session,只有cookie_secret,这在一些情况下是不利于开发的.所有我们可以给Tornado加上session的功能. 这篇文章讲解的是依靠第三方包来实现.以后的文章 ...
- 多系统重装其中Win7后的启动引导列表恢复
重装Win7后会导致原grub引导被覆盖,要修复grub需要一张Ubuntu的LiveCD(安装光盘),用LiveCD启动电脑,进入Try Ubuntu(试用Ubuntu),进入之后打开终端,做如下几 ...
- windows下vue.js开发环境搭建教程
这篇文章主要为大家详细介绍了windows下vue.js开发环境搭建教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 最近,vue.js越来越火.在这样的大浪潮下,我也开始进入vue的学习行列中 ...