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、创建方法类

这个类中写了主要的业务操作步骤,选取了加法和出发作为案例(除法较为典型)

 1 package da.wei.aop;
 2 import org.springframework.stereotype.Component;
 3
 4  @Component  //普通类的注解配置spring.xml的配置,加入IOC容器
 5 public class MathTestImpl {
 6      public Integer add(int i,int j){
 7         System.out.println("执行add,参数i为: "+i+" ,参数j为: "+j+" ,结果为: "+(i+j));
 8         return (i+j);
 9     }
10
11     public Integer div(int i,int j){
12         System.out.println("执行div,参数i为: "+i+" ,参数j为: "+j+" ,结果为: "+(i/j));
13         return (i/j);
14     }
15 }

该方法中需要强调一点规范问题,在使用函数返回值类型或者类的属性设置时,使用包装类型(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” 需要与方法中的参数相等对应。

 1 package da.wei.aop;
 2
 3 import java.util.Arrays;
 4 import java.util.List;
 5
 6 import org.aspectj.lang.JoinPoint;
 7 import org.aspectj.lang.Signature;
 8 import org.aspectj.lang.annotation.After;
 9 import org.aspectj.lang.annotation.AfterReturning;
10 import org.aspectj.lang.annotation.AfterThrowing;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.aspectj.lang.annotation.Pointcut;
14 import org.springframework.core.annotation.Order;
15 import org.springframework.stereotype.Component;
16 /*
17  * @Component 普通类的注解配置spring.xml的配置,加入IOC容器
18  * @Aspect  标识出此类为切面方法类
19  * Order 是为了指定在多个切面类的情况下,其执行的顺序;
20  * value值为int类型的,值越小越先执行
21  */
22 @Component
23 @Aspect
24 @Order(value=100)
25 public class MathAspectMutil {
26     //设置切点位置 此处设置的是add(int,int)方法
27     @Pointcut(value="execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )")
28     public void getPointCut(){}
29
30     //注解,设置此方法是‘前置通知’
31     @Before(value="getPointCut()")
32     public void before(JoinPoint point){
33         System.out.println("[MathAspectMutil]【Before日志】");
34         //获取插入点的参数
35         Object[] args = point.getArgs();
36         //获取方法签名
37         Signature signature = point.getSignature();
38         //获取方法名
39         String name = signature.getName();
40         //将参数数组传为list
41         List<Object> asList = Arrays.asList(args);
42         System.out.println("方法签名 : "+signature);
43         System.out.println("方法名为 : "+name+"方法体参数列表 : "+asList);
44     }
45
46     /*
47      * 注解,设置此处是‘后置通知’
48      * 此处可以看出其value值与上面before方法的不一样
49      * 实则是一样的,只是通过PointCut将其统一封装使用而已,效果相同
50      */
51     @After(value="execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )")
52     public void after(){
53         System.out.println("[MathAspectMutil]【After日志】");
54     }
55
56     //注解,设置此方法是‘返回通知’
57     @AfterReturning(value="getPointCut()",returning="result")
58     public void afterReturning(JoinPoint point,Object result){
59         System.out.println("[MathAspectMutil]【AfterReturning日志】");
60         //获取插入点的参数
61         Object[] args = point.getArgs();
62         //获取方法签名
63         Signature signature = point.getSignature();
64         //获取方法名
65         String name = signature.getName();
66         //将参数数组传为list
67         List<Object> asList = Arrays.asList(args);
68         System.out.println("方法签名 : "+signature);
69         System.out.println("方法名为 : "+name+"方法体参数列表 : "+asList+" ,执行结果为: "+result);
70     }
71
72     //注解,设置此方法是‘异常通知’
73     @AfterThrowing(value="getPointCut()",throwing="ex")
74     public void afterThrowing(Throwable ex){
75         System.out.println("[MathAspectMutil]【AfterThrowing日志】");
76         System.out.println("错误信息为 : "+ex.getMessage());
77     }
78 }

3、创建Around方法的切面类

Around方法其就是对上面四种通知的合并,在环绕通知中上面的四种通知都有体现到

通过对下面代码的分析就可以基本了解其运行结果了

 1 package da.wei.aop;
 2 import java.util.Arrays;
 3 import java.util.List;
 4
 5 import org.aspectj.lang.ProceedingJoinPoint;
 6 import org.aspectj.lang.Signature;
 7 import org.aspectj.lang.annotation.Around;
 8 import org.aspectj.lang.annotation.Aspect;
 9 import org.aspectj.lang.annotation.Pointcut;
10 import org.springframework.core.annotation.Order;
11 import org.springframework.stereotype.Component;
12
13 @Component
14 @Aspect
15 @Order(value=5)
16 public class MathAspectAround {
17     //设置切点位置 此处设置的是add(int,int)方法
18     @Pointcut(value="execution(public Integer da.wei.aop.MathTestImpl.add(int, int) )")
19     public void getPointCut(){}
20
21     @Around(value="getPointCut()")
22     public Object around(ProceedingJoinPoint pJoinPoint){
23         //获取插入点的参数
24         Object[] args = pJoinPoint.getArgs();
25         //获取方法签名
26         Signature signature = pJoinPoint.getSignature();
27         //获取方法名
28         String name = signature.getName();
29         //将参数数组传为list
30         List<Object> asList = Arrays.asList(args);
31         Object result = null;
32         try {
33            try{
34                System.out.println("[MathAspectAround]【Before】...");
35                System.out.println("方法签名 : "+signature);
36                System.out.println("方法名为 : "+name+"方法体参数列表 : "+asList);
37                //获得结果
38                result = pJoinPoint.proceed(args);
39            }finally {
40                System.out.println("[MathAspectAround]【After】....");
41            }
42            System.out.println("[MathAspectAround]【AfteReturning】..结果为"+result+"....");
43         } catch (Throwable e) {
44            // TODO Auto-generated catch block
45            System.out.println("[MathAspectAround]【Throwing】..原因为 "+e.getMessage());
46         }
47         return result;
48     }
49 }

4、配置spring.xml

我这里的spring配置文件名为applicationContext.xml

1 <!-- 扫描包,创建Bean对象 -->
2     <context:component-scan base-package="da.wei.aop"></context:component-scan>
3     <!-- 启用 切面编程注解 -->
4     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

5、Junit中代码编写

此处讲解AOP的使用至于IOC的使用就不再赘述。

 1 @Test
 2     public void test() {
 3         //获取applicationContext配置信息,主要用于获得IOC容器中的类对象
 4         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
 5         //获取bean对象
 6         MathTestImpl bean = (MathTestImpl) applicationContext.getBean("mathTestImpl");
 7         /*
 8          * 调用方法
 9          * 由于在配置里只编写了针对add的切入点这里只执行add方法
10          * 在之后的xml配置的方法中执行div方法
11          */
12         bean.add(1,2);
13         //bean.div(10, 2);
14     }

6、执行结果

从执行结果中我们能看到已经正确执行了,同时我们也要注意到两种方式的执行顺序

由于我们设置MathAspectMutil的Order为100 比MathAspectAround的5大因此MathAspectAround先执行,当其执行完before之后释放的方法又被MathAspectMutil获取,当MathAspectMutil执行完全部之后MathAspectAround再执行其他的方法,类似于拦截器的运行顺序。

二、spring.xml配置的方式

spring.xml配置的方式其类的建立与上面相同,只是需要去除所有的注解,使用简单的方法,简单的类

1、其中的applicationContext.xml配置如下

 1 <bean id="mathTestImpl" class="da.wei.aop.MathTestImpl"></bean>
 2     <bean id="mathAspectMutil" class="da.wei.aop.MathAspectMutil"></bean>
 3     <bean id="mathAspectAround" class="da.wei.aop.MathAspectAround"></bean>
 4     <aop:config >
 5         <!-- 第一个 好多方法的切面类 -->
 6         <aop:pointcut expression="execution(* da.wei.aop.MathTestImpl.*(..))" id="myPointCut"/>
 7         <aop:aspect ref="mathAspectMutil" order="10">
 8            <aop:before method="before" pointcut-ref="myPointCut" />
 9            <aop:after method="after" pointcut-ref="myPointCut"/>
10            <aop:after-returning method="afterReturning" pointcut-ref="myPointCut" returning="result"/>
11            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="ex"/>
12         </aop:aspect>
13         <!-- Around -->
14         <aop:aspect ref="mathAspectAround" order="5">
15            <aop:around method="around" pointcut-ref="myPointCut"  />
16         </aop:aspect>
17     </aop:config>

2、Junit代码如下

 1 @Test
 2     public void test() {
 3         //获取applicationContext配置信息,主要用于获得IOC容器中的类对象
 4         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
 5         //获取bean对象
 6         MathTestImpl bean = (MathTestImpl) applicationContext.getBean("mathTestImpl");
 7         bean.div(10, 2);
 8         System.out.println();
 9         bean.div(10, 0);   //此处我们测试了异常情况
10     }

3、执行结果

 

从结果总我们可以看出当执行异常出现的时候,会执行性Throwing而不执行AfterReturning,这个也可以在Around的代码中可以看出。

以上是我最近学习AOP切面编程的一点总结,内容多为代码,总结不足,不过开发与思路过程在注释中有体现,希望能给大家一些帮助。

 

同时欢迎过路大神指点批评。

时间: 2024-08-02 02:50:57

Spring中AOP简介与使用的相关文章

Spring中AOP原理,使用笔记

AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级服务. 系统级服务指的是:事务处理,日志记录,性能统计,安全控制,异常处理等,因为这些功能分散在程序的各个模块中,又是通用的,所以可以将它从业务逻辑中分离出来. 连接点(joinpoint):在连接点可以拦截方法的执行,在连接点前后织入上述的这些系统级服务(织入的就是通知). 切入点(pointcut)

Spring中AOP实例详解

Spring中AOP实例详解 需要增强的服务 假如有以下service,他的功能很简单,打印输入的参数并返回参数. @Service public class SimpleService { public String getName(String name) { System.out.println(get name is: + name); return name; } } 定义切面和切点 @Component @Aspect public class L ogAspect { // 定义切

Spring中Aop的扩展及剖析

AOP简介: 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率.面向对象编程是从[静态角度]考虑程序的结构,而面向切面编程是从[动态角度]考虑程序运行过程.AOP底层,就是采用[动态代理]模式实现的.采用了两种代理:JDK动态代理和C

Spring中AOP的一个通俗易懂的理解(转)

这是看到的一个最易懂得AOP简介了,适合初学者理解. 转自:http://www.verydemo.com/demo_c143_i20837.html 1.我所知道的aop 初看aop,上来就是一大堆术语,而且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等.一下子让你不知所措,心想着:怪不得很多人都和我说aop多难多难.当我看进去以后,我才发现:它就是一些java基础上的朴实无华的应用,包括ioc,包括许许多多这样的名词,都是万变不离其宗而已. 2.为什么用aop 1就是为了方便

关于spring中AOP的几件小事

0.AOP简介 AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是穿透OOP的补充. AOP的主要编程对象是切面(aspect),而切面模块化横切关注点. 在使用AOP编程时,仍然需要定义功能功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类.这样一来横切关注点就被模块化到特殊的对象(切面)里. AOP的好处: - 每个事物逻辑位于同一层,代码不分散,便于维护和升级. - 业务模块更简洁,只包含核心业务代码. 1.AOP

6.Spring中AOP术语与XML方式简单实现

1.AOP术语 1. Joinpoint(连接点):所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法,因为spring只支持方法类型的连接点 2. Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义 3. Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能) 4. Introduction(引介):引介是一种特殊的通知在不修改类代

浅谈spring中AOP以及spring中AOP的注解方式

AOP(Aspect Oriented Programming):AOP的专业术语是"面向切面编程" 什么是面向切面编程,我的理解就是:在不修改源代码的情况下增强功能.好了,下面在讲述aop注解方式的情况下顺便会提到这一点. 一.搭建aop注解方式的环境(导入以下的包) 二.实现 环境搭建好了之后,就创建项目. 1.创建接口类(CustomerDao)并添加两个方法 2.接口类创建好了后,自然是要new一个实现类(CustomerDaoImpl)并实现接口中的方法 3.以上基础工作做完

Spring中AOP和IOC深入理解

spring框架 Spring框架是由于软件开发的复杂性而创建的.Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的用途不仅仅限于服务器端的开发.从简单性.可测试性和松耦合性的角度而言,绝大部分Java应用都可以从Spring中受益. ◆目的:解决企业应用开发的复杂性 ◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能 ◆范围:任何Java应用 Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架. Spr

Spring中AOP的使用

问题:什么是AOP? 答:AOP基本概念:Aspect-Oriented Programming,面向方面编程的简称,Aspect是一种新的模块化机制.用来描写叙述分散在对象.类或方法中的横切关注点(crosscutting concern), 从关注点中分离出横切关注点是面向方面程序设计的核心所在. 分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特 定领域问题代码的调用.业务逻辑同特定领域问题的关系通过方面来封装.维护,这样原本分散在整个应用程序中的变动