【Spring入门系列】篇6:再探SpringAOP(SpringAOP的使用)
前言
前面一篇文章中我们简单介绍了SpringAOP的作用以及原理,接下来我们来讲讲SpringAOP怎么配置使用。
一、SpringAOP的基本使用
还是使用上篇中的例子,假设我们需要给GoodsDao类进行增强:
public class GoodsDao {
public void save() {
System.out.println("goodsDao-----save");
}
}
1.编写切面类
切面类中主要包含了多个通知(增强功能所封装成的方法)
public class MyAspectXML {
public void check() {
System.out.println("增加权限校验");
}
}
2.配置applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="goodsDao" class="demo1.GoodsDao"></bean>
<bean id="myAspect" class="demo2.MyAspectXML"></bean>
<!--配置Aop-->
<aop:config>
<!--配置切点:需要增强的方法-->
<aop:pointcut id="savePoint" expression="execution(* demo1.GoodsDao.save(..))"/>
<!--配置切面:如何增强、增强的功能-->
<aop:aspect ref="myAspect">
<aop:before method="check" pointcut-ref="savePoint"/>
</aop:aspect>
</aop:config>
</beans>
第一步:配置applicationContext肯定是将需要增强的类、切面类交由Spring管理
<bean id="goodsDao" class="demo1.GoodsDao"></bean>
<bean id="myAspect" class="demo2.MyAspectXML"></bean>
第二步:在aop配置配置切点,我们当然要指定需要被增强的方法(切点)。expression表达式指定需要配置的方法,*
表示任意返回值..
表示任意参数。
<!--配置切点:需要增强的方法-->
<aop:pointcut id="savePoint" expression="execution(* demo1.GoodsDao.save(..))"/>
第三步:配置切面,配置完切点我们还需要配置切面来通知Spring需要增强的内容是什么,以及如何进行增强
<!--配置切面:如何增强、增强的功能-->
<aop:aspect ref="myAspect">
<aop:before method="check" pointcut-ref="savePoint"/>
</aop:aspect>
3.测试
import demo1.GoodsDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspectTest {
@Resource(name = "goodsDao")
GoodsDao goodsDao;
@Test
public void test() {
goodsDao.save();
}
}
运行结果:
增加权限校验
goodsDao-----save
二、SpringAOP通知类型
在动态代理中我们提到过我们可以在方法前面进行增强,也可以在方法后进行增强,springAOP也是如此,给我们提供了下面几种方式:
- 前置通知(before):在方法执行前通知
- 后置通知(after-returning):在方法执行后通知
- 环绕通知(around):在方法执行前后通知
- 异常抛出通知(after-throwing):在方法发生异常时通知
- 最终通知(after):无论是否发生异常都通知
我们先将GoodsDao修改一下:
public class GoodsDao {
public void save() {
System.out.println("goodsDao-----save");
}
public String delete() {
System.out.println("delete");
return "delete---return";
}
public void update() {
System.out.println("update");
}
public void find() {
System.out.println("find");
int a = 1/0;
}
}
接着修改一下切面类:
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspectXML {
public void check() {
System.out.println("增加权限校验");
}
public void writeLog(Object res) {
System.out.println(res);
System.out.println("记入日志");
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around------前置通知");
joinPoint.proceed();
System.out.println("around------后置通知");
}
public void exceptionNotice(Throwable e) {
System.out.println("发生了异常:"+ e.getMessage());
}
public void finalNotice() {
System.out.println("final--------------");
}
}
配置applicationContex.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="goodsDao" class="demo1.GoodsDao"></bean>
<bean id="myAspect" class="demo2.MyAspectXML"></bean>
<!--配置Aop-->
<aop:config>
<!--配置切点:需要增强的方法-->
<aop:pointcut id="savePoint" expression="execution(* demo1.GoodsDao.save(..))"/>
<aop:pointcut id="deletePoint" expression="execution(* demo1.GoodsDao.delete(..))"/>
<aop:pointcut id="updatePoint" expression="execution(* demo1.GoodsDao.update(..))"/>
<aop:pointcut id="findPoint" expression="execution(* demo1.GoodsDao.find(..))"/>
<!--配置切面:如何增强、增强的功能-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="savePoint"/>
<!--后置通知-->
<aop:after-returning method="writeLog" returning="res" pointcut-ref="deletePoint"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="updatePoint"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionNotice" throwing="e" pointcut-ref="findPoint"/>
<!--最终通知-->
<aop:after method="finalNotice" pointcut-ref="findPoint"/>
</aop:aspect>
</aop:config>
</beans>
测试类:
import demo1.GoodsDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspectTest {
@Resource(name = "goodsDao")
GoodsDao goodsDao;
@Test
public void test() {
goodsDao.save();
System.out.println("--------------------------------------------");
goodsDao.delete();
System.out.println("--------------------------------------------");
goodsDao.update();
System.out.println("--------------------------------------------");
goodsDao.find();
}
}
运行结果:
增加权限校验
goodsDao-----save
--------------------------------------------
delete
delete---return
记入日志
--------------------------------------------
around------前置通知
update
around------后置通知
--------------------------------------------
find
final--------------
发生了异常:/ by zero
三、SpringAOP注解编程
我们可以将上面的程序改为注解的形式:
修改applicationContex.xml,需要在配置中开启aop注解:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="goodsDao" class="demo1.GoodsDao"></bean>
<bean id="myAspect" class="demo2.MyAspectXML"></bean>
<!--AOP开启注解-->
<aop:aspectj-autoproxy/>
</beans>
修改切面类,用法与配置文件形式基本相同:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class MyAspectXML {
@Before(value = "execution(* demo1.GoodsDao.save(..))")
public void check() {
System.out.println("增加权限校验");
}
@AfterReturning(value = "execution(* demo1.GoodsDao.delete(..))" , returning = "res")
public void writeLog(Object res) {
System.out.println(res);
System.out.println("记入日志");
}
@Around(value = "execution(* demo1.GoodsDao.update(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around------前置通知");
Object proceed = joinPoint.proceed();
System.out.println("around------后置通知");
return proceed;
}
@AfterThrowing(value = "execution(* demo1.GoodsDao.find(..))" , throwing = "e")
public void exceptionNotice(Throwable e) {
System.out.println("发生了异常:"+ e.getMessage());
}
@After(value = "execution(* demo1.GoodsDao.find(..))")
public void finalNotice() {
System.out.println("final--------------");
}
}
注解切入点的配置
有时候我们想在一个切点中即添加前置通知,又添加异常通知和最终通知该如何操作呢?
我们可以在切面当中定义好切入点:
import org.aspectj.lang.annotation.*;
@Aspect
public class MyAspectXML2 {
@Before(value = "MyAspectXML2.pointcut1()")
public void check() {
System.out.println("增加权限校验");
}
@AfterThrowing(value = "MyAspectXML2.pointcut1()" , throwing = "e")
public void exceptionNotice(Throwable e) {
System.out.println("发生了异常:"+ e.getMessage());
}
@After(value = "MyAspectXML2.pointcut1()")
public void finalNotice() {
System.out.println("final--------------");
}
@Pointcut(value = "execution(* demo1.GoodsDao.save(..))")
public void pointcut1(){}//定义好切点
}