首页 > 代码库 > 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>
三、具体实现
任何技术都是为业务服务的,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