首页 > 代码库 > JavaEE学习之Spring aop

JavaEE学习之Spring aop

一、基本概念

  AOP——Aspect-Oriented Programming,面向切面编程,它是spring框架的一个重要组成部分。一般的业务逻辑都有先后关系,我们可以理解为纵向关系,而AOP关注的是横向关系,每一个关注点可以理解为一个横切面。例如我们的大部分代码都会涉及到日志记录,很多的数据库操作都会涉及到事务的创建和提交。那么从横向关注这些逻辑,他们都一个个的切面。

  AOP技术的具体实现,可以通过动态代理技术或者是在程序编译期间进行静态的"织入"方式。AOP经常使用的场景包括:日志记录,事务管理,异常处理,安全控制等方面。Spring 中 AOP 代理由 Spring 的 IoC 容器负责生成、管理,其依赖关系也由 IoC 容器负责管理。在spring中可以仅通过配置文件实现AOP,也可以使用注解实现。

  AOP相关概念:

  • Joinpoint(连接点):是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个 join point。   
  • Pointcut(切入点):本质上是一个捕获连接点的结构。在AOP中,可以定义一个point cut,来捕获相关方法的调用。    
  • Advice(通知):是Pointcut的执行代码,是执行“方面”的具体逻辑。AOP通知大致上包括:前置通知(Before),环绕通知(Around),后置通知(After Returning),异常通知(Throws Advice) .  
  • Aspect(方面,切面):Pointcut和Advice结合起来就是Aspect,它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。    
  • Introduce(引入):为对象引入附加的方法或属性,从而达到修改对象结构的目的。
  • Weaving(编织):组装Aspect来创建一个被通知对象。

二、依赖jar包

 本文主要学习spring aop相关使用,所以需要的jar主要包括spring相关jar包和aop相关jar包,具体pom.xml文件如下:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 2   <modelVersion>4.0.0</modelVersion> 3   <groupId>wzhang</groupId> 4   <artifactId>spring-aop</artifactId> 5   <version>0.0.1-SNAPSHOT</version> 6   <name>spring-aop</name> 7   <description>Hello World</description> 8   <dependencies> 9       <dependency>10           <groupId>org.springframework</groupId>11           <artifactId>spring-aop</artifactId>12           <version>3.2.3.RELEASE</version>13       </dependency>14       <dependency>15           <groupId>org.springframework</groupId>16           <artifactId>spring-beans</artifactId>17           <version>3.2.3.RELEASE</version>18       </dependency>19       <dependency>20           <groupId>org.springframework</groupId>21           <artifactId>spring-context</artifactId>22           <version>3.2.3.RELEASE</version>23       </dependency>24       <dependency>25           <groupId>org.springframework</groupId>26           <artifactId>spring-core</artifactId>27           <version>3.2.3.RELEASE</version>28       </dependency>29       <dependency>30           <groupId>org.springframework</groupId>31           <artifactId>spring-expression</artifactId>32           <version>3.2.3.RELEASE</version>33       </dependency>34       <dependency>35           <groupId>aopalliance</groupId>36           <artifactId>aopalliance</artifactId>37           <version>1.0</version>38       </dependency>39       <dependency>40           <groupId>log4j</groupId>41           <artifactId>log4j</artifactId>42           <version>1.2.17</version>43       </dependency>44       <dependency>45           <groupId>org.aspectj</groupId>46           <artifactId>aspectjrt</artifactId>47           <version>1.8.2</version>48       </dependency>49       <dependency>50           <groupId>org.aspectj</groupId>51           <artifactId>aspectjweaver</artifactId>52           <version>1.8.2</version>53       </dependency>54   </dependencies>55 </project>
pom.xml

三、具体实现

任何技术都是为业务服务的,AOP也不例外。下面以经典的计算器业务为例,简单介绍下AOP的应用。

1.利用maven创建一个simple project,并添加相关依赖。

2.在src/main/resources目录下创建spring配置文件:applicationContext.xml,先放着,用的时候再去配置。

(***************上面两步都是准备工作,下面才是具体实现*********************)

3.定义业务类

定义接口:ICalculate,并提供int add(int,int)方法,再定义一个实现类CalculateImpl:

 1 /************** ICalculate接口 **************/ 2  3 package com.wzhang.service; 4  5 public interface ICalculate { 6  7     /** 8      * add 加运算 9      * @return 两数和10      */11     int add(int a,int b);12 }13 14 /********* ICalculate 的实现类 **************/15 16 package com.wzhang.service.impl;17 18 import com.wzhang.service.ICalculate;19 20 public class CalculateImpl implements ICalculate {21 22     public int add(int a, int b) {23         return a+b;24     }25 }

4.spring 实现AOP有两种方式,配置文件和注解方式。这里先通过配置文件实现方法调用前的权限检查:

1)定义类SecurityAspect,并提供方法checkAuthority.代码如下:

 1 package com.wzhang.aspect; 2 /** 3 * 安全检查切面(方面) 4 */ 5 public class SecurityAspect { 6      7     /** 8      * 权限检查 9      */10     public void checkAuthority(){11         System.out.println("方法调用前,先检查权限!");12     }13 }

2) 在applicationContext.xml中配置AOP:

 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" 5     xsi:schemaLocation="http://www.springframework.org/schema/beans  6     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 7     http://www.springframework.org/schema/context      8     http://www.springframework.org/schema/context/spring-context-3.2.xsd 9     http://www.springframework.org/schema/tx 10     http://www.springframework.org/schema/tx/spring-tx-3.2.xsd11     http://www.springframework.org/schema/aop 12     http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">13 14     <!-- 扫描com.wzhang下的所有包 -->15     <context:component-scan base-package="com.wzhang" />16 17     <!-- 定义业务类 -->18     <bean id="calculate" class="com.wzhang.service.impl.CalculateImpl" />19 20     <!-- 定义一个安全控制切面 -->21     <bean id="authority" class="com.wzhang.aspect.SecurityAspect" />22 23     <!-- 通过配置文件实现 -->24     <aop:config>25         <!-- 定义切面 -->26         <aop:aspect id="security" ref="authority">27             <!-- 指定切入点 -->28             <aop:pointcut expression="execution(* com.wzhang.service.*.*(..))"29                 id="securityPointcut" />30             <!-- 配置前置通知 -->31             <aop:before method="checkAuthority" pointcut-ref="securityPointcut" />32             <!-- 还可以配置环绕通知,后置通知,异常通知 -->33         </aop:aspect>34     </aop:config>35 </beans>

注意事项:

  • 需要引入AOP相关的namespace;
  • 在<aop:config></aop:config>节点中配置切面,也就是我们之前定义的处理类;
  • 指定切入点,使用切入点表达式。
  • 通知(Advice),可以通过pointcut-ref指定已定义切入点;要定义内置切入点,可将 pointcut-ref 属性替换为 pointcut 属性。

经过以上几步,使用配置文件实现的主体代码就完成了,剩下的就是测试了。我们这里和用注解实现AOP一起测试

5. 通过注解实现方法调用前后的日志记录

1)通过注解实现AOP需要在配置文件中配置:  <aop:aspectj-autoproxy />节点,启动对@AspectJ注解的支持。

2)定义切面。代码如下:

 1 package com.wzhang.aspect; 2  3 import org.aspectj.lang.annotation.AfterReturning; 4 import org.aspectj.lang.annotation.Aspect; 5 import org.aspectj.lang.annotation.Before; 6 import org.aspectj.lang.annotation.Pointcut; 7  8 /** 9  * 记录日志切面10  * @author wzhang11  *12  */13 @Aspect14 public class LogAspect {15     16     /**17      * 前置切入点,18      */19     @Pointcut("execution(* com.wzhang.service.*.*(..))")20     public void beforePointcut(){}21     22     /**23      * 后置通知,日志记录24      */25     @AfterReturning("execution(* com.wzhang.service.*.*(..))")26     public void log(){27         System.out.println("方法调用后,记录操作日志!");28     }29     30     /**31      * 前置通知32      */33     @Before("beforePointcut()")34     public void beforeLog(){35         System.out.println("使用@Pointcut注解,实现方法调用前记录操作日志!");36     }37 38 }

3)配置bean:<bean id="log" class="com.wzhang.aspect.LogAspect" />

几点说明:

通过@Aspect注解声明切面;

通过@Before,@Around,@AfterReturning,@AfterThrowing等定义通知,可以通过表达式execution(xxx)定义切入点;

还可以在方法上@Pointcut定义切入点,方便同类中其他方法使用此处配置的切入点。

6.测试,在src/test/java目录下创建测试类:AppTest.代码如下:

 1 package com.wzhang.test; 2  3 import org.junit.Assert; 4 import org.junit.Test; 5 import org.springframework.context.ApplicationContext; 6 import org.springframework.context.support.ClassPathXmlApplicationContext; 7  8 import com.wzhang.domain.UserBean; 9 import com.wzhang.service.ICalculate;10 import com.wzhang.service.IUser;11 12 public class AopTest {13 14     static ApplicationContext ctx;15     static {16         ctx = new ClassPathXmlApplicationContext("applicationContext.xml");17     }18     19     @Test20     public void calculateTest(){21         ICalculate cal =  (ICalculate) ctx.getBean("calculate");22         int result =  cal.add(5, 6);23         Assert.assertEquals(11, result);24     }25 }

运行测试,输入以下结果:

第一行说明使用配置文件实现AOP成功,第二行说明使用@Pointcut注解实现前置通知成功。

四、切入点表达式的相关说明

1.切入点表达式中:"*"-匹配所有字符;".."-用于匹配多个包,多个参数;"+"-表示类及其子类;

2.切入点表达式支持逻辑运算符:&&,||,!;

3.使用execution用于匹配子表达式;

4.AOP的注解不仅仅局限于例子中的几个,还有@args,@within,@this,@target等注解,需要我们深入研究。

 

示例代码下载:spring-aop.zip