天天看点

Spring AOP Example TutorialAOP 概要AOP 核心概念AOP 通知类型Spring AOP AspectJ 依赖模型类服务类AOP 配置Before Aspect 例子切点方法和重用连接点和通知参数After Advice 例子Around Aspect 例子自定义的注解切点Spring AOP XML Configuration

大多数的企业应用都会有一些共同的对横切的关注,横切是否适用于不同的对象或者模型。一些共同关注的横切有日志、事务管理以及数据校验等等。在面向对象的编程中,应用模块是有类来实现的,然而面向切面的编程的应用模块是由切面(aspect)来获取的,他们被配置用于切不同的类。

aop 任务将横切任务的直接依赖从类中抽离出来,因为我们不能直接从面向对象编程的模型中获取这些依赖。例如,我们可以有一个单独的类用于记录日志,但是相同功能的类将不得不调用这些方法去获取应用的中的日志。

在我们深入了解 spring 框架中 aop 的实现方式之前,我们需要了解 aop 中的一些核心概念。

<code>aspect</code>:切面,实现企业应用中多个类的共同关注点,例如事务管理。切面可以是使用 spring xml 配置的一个普通类或者是我们使用 spring aspectj 定义的一个标有 @aspect 注解的类。

<code>join point</code>:连接点,一个连接点是应用程序中的一个特定的点,例如方法执行、异常处理、改变对象变量的值等等。在 spring aop 中,一个连接点永远是指一个方法的执行。

<code>advice</code>:通知,通知是指在一个特别的连接点上发生的动作。在编程中,他们是当一个连接点匹配到一个切入点时执行的方法。你可以把通知想成 strust2 中的拦截器或者是 servlet 中的过滤器。

<code>pointcut</code>:切入点,切入点是一些表达式,当匹配到连接点时决定通知是否需要执行。切入点使用不同种类型的表达式来匹配连接点,spring 框架使用 aspectj 表达式语法。

<code>target object</code>:通知执行的目标对象。spring aop 是使用运行时的代理来实现的,所以该对象永远是一个代理对象。这意味着一个子类在运行期间会被创建,该类的目标方法会被覆盖并且通知会基于他们的配置被引入。

<code>aop proxy</code>:spring aop 实现使用 jdk 的动态代理来创建包含有目标类和通知调用的代理类,这些类被称为 aop 代理类。我们也可以使用 cglib 代理来作为 spring aop 项目的依赖实现。

<code>weaving</code>:织入,将切面和其他用于创建被通知的代理对象的类联系起来的过程。这可以是在运行时完成,也可以是在代码加载过程中或者运行时。spring aop 是在运行时完成织入的过程。

基于通知的执行策略,这里有以下几种通知类型:

<code>before advice</code>:在连接点方法执行之前运行。我们可以使用 <code>@before</code> 注解来标记一个通知类型为 before advice。

<code>after (finally) advice</code>:在连接点方法执行完成之后运行。我们可以使用 <code>@after</code> 来创建一个 after (finally) advice。

<code>after returning advice</code>:在方法返回之后运行,通过 <code>@afterreturning</code> 注解创建。

<code>after throwing advice</code>:在方法抛出异常之后运行,通过 <code>@afterthrowing</code> 注解创建。

<code>around advice</code>:这是最重要和最强的通知。这个通知在连接点方法前后运行并且我们可以决定该通知是否运行,通过 <code>@around</code> 注解创建。

上面提到的知识点可能会使我们困惑,但是当我们看到 spring aop 的实现之后,就会豁然开朗了。下面我们来创建一个 spring aop 的项目。spring 支持使用 aspectj 的注解来创建切面,为了简单,我们将直接使用这些注解。上面提到的所有 aop 的注解都定义在 org.aspectj.lang.annotation 包中。

创建一个简单的 spring maven 项目,通过 pom.xml 引入 spring 的核心库。在项目创建成功之后,我们可以看到下面的目录结构:

Spring AOP Example TutorialAOP 概要AOP 核心概念AOP 通知类型Spring AOP AspectJ 依赖模型类服务类AOP 配置Before Aspect 例子切点方法和重用连接点和通知参数After Advice 例子Around Aspect 例子自定义的注解切点Spring AOP XML Configuration

spring 框架默认提供了对 aop 的支持,既然我们需要使用 aspectj 的注解,则需要在 pom.xml 中引入相关的依赖:

需要注意的是,我在项目中添加了对 aspectjrt 和 aspectjtools (版本为 1.7.4)的依赖。并且我也把 spring 的版本更新到了 4.0.2.release。

下面我们来创建一个简单的 java bean:

employee.java

你有注意到 <code>setname()</code> 方法上定义了一个 <code>loggable</code> 注解吗?它是一个我们项目中创建的自定义注解。我们将在后面介绍它的用法。

下面,我们来创建一个服务类来处理 employee 对象:

employeeservice.java

我本来可以使用 spring 注解来将其配置为一个 spring 的组件,但是在该项目中我们将会使用 xml 来配置。employeeservice 是一个非常标准的类,并提供了一个访问 employee 的点。

我项目中的配置 spring.xml 如下:

在 spring beans 中使用 aop,我们需要添加:

申明 aop 命名空间,如:<code>xmlns:aop="http://www.springframework.org/schema/aop"</code>。

添加 <code>aop:aspectj-autoproxy</code> 节点开启 spring aspectj 在运行时自动代理的支持。

配置 aspect 类。

employeeaspect.java:

上面例子中重要的地方说明如下:

aspect 类需要添加 <code>@aspect</code> 注解。

<code>@before </code>注解用于创建 before advice。

<code>@before</code> 注解中的字符串参数是 pointcut 表达式。

getnameadvice() 通知将会在任何带有 <code>public string getname()</code>` 方法签名的 spring bean 方法执行时执行。这点是非常重要的,如果我们使用 new 操作符来创建一个 employee bean,该通知并不会执行,其只会在 applicationcontext 获取该 bean 时执行。

有时候,我们需要在多个地方上使用相同的切点表达式,我们可以使用一个空方法的 <code>@pointcut</code> 注解,然后在通知中将它作为表达式来使用。

employeeaspectpointcut.java

上面的例子非常清晰,相对于表达式,我们在使用方法名称作为注解的参数。

我们可以使用 joinpoint 作为通知方法的参数并且使用他获取方法签名或者目标对象。

我们可以在连接点中使用 <code>args()</code> 表达式来匹配任何方法的任何参数。如果我们使用它,则我们需要在通知方法中使用同参数相同的名称。我们也可以在通知参数中使用泛型。

employeeaspectjoinpoint.java

employeeafteraspect.java 如下:

我们可以在切点表达式中使用 <code>within</code> 来申明该通知会在一个类的所有方法上执行。

正如前面提到的,我们可以使用 around aspect 来定义在方法前后进行执行指定的代码。

employeearoundaspect.java

前面提到了 <code>@loggable</code> 注解,其定义如下:

我们可以创建一个切面来使用该切点,employeeannotationaspect.java 如下:

<code>myadvice()</code> 方法仅仅会在 <code>setname()</code> 方法执行前执行。

如果我们使用 sping 的配置文件来定义切面,则定义方式如下。

employeexmlconfigaspect.java

在 配置文件中定义如下:

最后,来看看一个简单的程序来说明切面如何作用在 bean 的方法上。

我们将看到如下输出:

你将会看到通知将会基于切点配置一个个的执行。你应该一个个的配置他们,以免出现混乱。

上面是 spring aop 教程的所有内容,我希望你理解了 spring aop 的基本概念并能从例子中学习到更多。你可以从下面链接下载本文中的项目代码。

<a href="http://www.journaldev.com/?wpdmact=process&amp;did=mjauag90bgluaw==" target="_blank">download spring aop project</a>