Spring AOP,也就是面向切面编程,是对于面向对象编程的一种补充,也是Spring框架的一项重要内容,核心思想是动态代理。
为什么需要AOP:
但我们在开发的过程中,我们慢慢会发现,有一些代码会不断重复出现,而且随着代码量增大,这一类代码会不断的重复出现,如果没有使用AOP,这一类的代码我们一般会采取复制粘贴的方式去解决,但是这样会造成难以维护,假如有一天,我们需要对这一类重复代码进行修改,还得找到每一个用到这重复代码进行修改,这样就会比较麻烦,还容易出错。这时候,如果我们能够把这类重复代码单独提取出来,就可以对它进行单独处理,并且也不用复制粘贴了,这就很方便了,而这就是AOP。
假如,我们有一个用户操作类,里面封装着对用户数据的操作,有保存,更新,删除等方法,这些方法都有共同的部分,每次执行操作前都需要开启事务,和操作后关闭事务。使用AOP我们就可以将这些操作事务的部分给提取出来。AOP就是类似这种应用
Spring AOP的用法例子:
- 导包,需要导入(Maven导包)
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.20.RELEASE</version> </dependency>
-
编写需要增强的类UserServiceImpl
package com.springday.service; public interface UserService { public void save(); public void delete(); public void update(); public void find(); }
package com.springday.service; public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存操作");//模拟进行操作 } @Override public void delete() { System.out.println("删除操作"); } @Override public void update() { System.out.println("更新操作"); } @Override public void find() { System.out.println("查找操作"); } }
-
编写通知类MyAdvice
package com.springday.springaop; import org.aspectj.lang.ProceedingJoinPoint; //通知类 public class MyAdvice { //前置通知 // |-目标方法运行之前调用 //后置通知(如果出现异常不会调用) // |-在目标方法运行之后调用 //环绕通知 // |-在目标方法之前和之后都调用 //异常拦截通知 // |-如果出现异常,就会调用 //后置通知(无论是否出现 异常都会调用) // |-在目标方法运行之后调用 //---------------------------------------------------------------- //前置通知 public void before(){ System.out.println("这是前置通知!!"); } //后置通知 public void afterReturning(){ System.out.println("这是后置通知(如果出现异常不会调用)!!"); } //环绕通知 public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("这是环绕通知之前的部分!!"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("这是环绕通知之后的部分!!"); return proceed; } //异常通知 public void afterException(){ System.out.println("出事啦!出现异常了!!"); } //后置通知 public void after(){ System.out.println("这是后置通知(出现异常也会调用)!!"); } }
-
在Spring的配置文件applicationContext.xml进行AOP配置如下
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 导入AOP(约束)命名空间 --> <!-- 1、配置目标对象 --> <bean name="userServiceTarget" class="com.springday.service.UserServiceImpl"></bean> <!-- 2、配置通知对象 --> <bean name="myAdvice" class="com.springday.springaop.MyAdvice"></bean> <!-- 3、配置将通知织入目标对象 --> <aop:config> <!-- 配置切入点(要增强的方法) public void com.springday.service.UserService.save() void com.springday.service.UserService.save() * com.springday.service.UserService.save() //任意返回类型 * com.springday.service.UserService.*() //对所有UserService所有方法进行增强 * com.springday.service.UserService.*(..) //对传入的参数不作要求 * com.springday.service.*Service.*(..) * com.springday.service..*Service.*(..) --> <aop:pointcut expression="execution(* com.springday.service.*Service.*(..))" id="pc"/> <aop:aspect ref="myAdvice"> <!-- 指定名为before的方法作为前置通知--> <aop:before method="before" pointcut-ref="pc"/> <!-- 后置 --> <aop:after-returning method="afterReturning" pointcut-ref="pc"/> <!-- 环绕通知 --> <aop:around method="around" pointcut-ref="pc"/> <!-- 异常拦截通知 --> <aop:after-throwing method="afterException" pointcut-ref="pc"/> <!-- 指定名为after的方法作为后置通知--> <aop:after method="after" pointcut-ref="pc"/> </aop:aspect> </aop:config> </beans>
-
编写测试类,测试配置了AOP后增强的方法
package com.springday.springaop; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.springday.service.UserService; //创建容器 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:com/springday/springaop/applicationContext.xml") public class Demo { @Resource(name="userServiceTarget") private UserService us; @Test //测试注解 public void fun1() { us.save(); } }
-
运行结果显示如下
可以看到,我们在执行保存操作时,多了上面红框的内容,只要符合配置上面切入点表达式的,
<aop:pointcut expression="execution(* com.springday.service.*Service.*(..))" id="pc"/>
都会执行一遍通知类的方法