Spring基于AspectJ注解方式的AOP开发
注解开发的好处是 开发迅速 ,但是维护必须在源代码处修改,维护时不方便
创建web项目,引入jar包
引入配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
创建目标类(被增强的对象)
这次不实现接口,Spring底层会使用Cglib动态代理产生代理对象
public class OrderDao { public void save(){ System.out.println("保存订单..."); } public void update(){ System.out.println("修改订单..."); } public void delete(){ System.out.println("删除订单..."); } public void find(){ System.out.println("查询订单..."); } }
配置目标类
<!-- 配置目标类================ --> <bean id="orderDao" class="com.itheima.spring.demo1.OrderDao"/>
创建切面类
注解方式的AOP开发,就是的切面类中设置注解
/** * 切面类:注解的切面类 */ public class MyAspectAnno { public void before(){ System.out.println("前置增强==========="); } }
配置切面类
<!-- 配置切面类================ --> <bean id="myAspect" class="com.itheima.spring.demo1.MyAspectAnno"/>
使用AOP注解对目标类进行加强
首先 要在 配置文件中 打开 注解的AOP开发
<!-- 在配置文件中开启注解的AOP的开发============ --> <aop:aspectj-autoproxy/>
接下来就可以在切面类中使用注解了
对save方法进行前置通知
/** * 切面类:注解的切面类 * 在类上添加@Aspect注解 */ @Aspect public class MyAspectAnno { /** * 对sava方法进行前置通知,在before通知上添加@Befor注解 */ @Before("execution(* com.itheima.spring.demo1.OrderDao.save(..))") public void before() { System.out.println("前置增强==========="); } }
编写测试方法
/** * Spring的AOP的注解开发 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo1 { @Resource(name="orderDao") private OrderDao orderDao; @Test public void demo1(){ orderDao.save(); orderDao.update(); orderDao.delete(); orderDao.find(); } }
测试结果
Spring注解的AOP通知的类型
@Before 前置通知
前置通知可以获取切入点信息(其实所有通知都可以获得)
@AfterReturning 后置通知
获取返回值
在delete中添加后置通知,并获取返回值
/** *后置通知 获取返回值 * @param result */ @AfterReturning(value="execution(* com.itheima.spring.demo1.OrderDao.delete(..))",returning="result") public void afterReturning(Object result){ System.out.println("后置增强==========="+result); }
测试结果
@Around 环绕通知
在update方法 上添加环绕通知
/** * 环绕通知 */ @Around(value="execution(* com.itheima.spring.demo1.OrderDao.update(..))") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("环绕前增强=========="); Object obj = joinPoint.proceed(); System.out.println("环绕后增强=========="); return obj; }
测试结果
@AfterThrowing 异常抛出通知
在find方法上添加异常抛出通知
/** * 异常抛出通知 */ @AfterThrowing(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))",throwing="e") public void afterThrowing(Throwable e){ System.out.println("异常抛出增强========="+e.getMessage()); }
测试结果
@After 最终通知
在find方法上添加最终通知
/** * 最终通知 */ @After(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))") public void after(){ System.out.println("最终增强============"); }
测试结果
Spring的注解的AOP开发的切入点的注解
上面的形式有个问题:即当我们要更改通知作用的目标方法(切入点时)会很麻烦(每次都要写execution函数及其里面的表达式)
解决办法 将切入点用其他名字代替,需要用到切入点的注解@Pointcut
// 切入点注解: @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))") private void pointcut1(){} @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.save(..))") private void pointcut2(){} @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.update(..))") private void pointcut3(){} @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.delete(..))") private void pointcut4(){}
使用时
/** * 切面类:注解的切面类 * 在类上添加Aspect注解 */ @Aspect public class MyAspectAnno { //前置通知 @Before(value="MyAspectAnno.pointcut2()") public void before(){ System.out.println("前置增强==========="); } // 后置通知: @AfterReturning(value="MyAspectAnno.pointcut4()",returning="result") public void afterReturning(Object result){ System.out.println("后置增强==========="+result); } // 环绕通知: @Around(value="MyAspectAnno.pointcut3()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("环绕前增强=========="); Object obj = joinPoint.proceed(); System.out.println("环绕后增强=========="); return obj; } // 异常抛出通知: @AfterThrowing(value="MyAspectAnno.pointcut1()",throwing="e") public void afterThrowing(Throwable e){ System.out.println("异常抛出增强========="+e.getMessage()); } // 最终通知 @After(value="MyAspectAnno.pointcut1()") public void after(){ System.out.println("最终增强============"); } // 切入点注解: @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))") private void pointcut1(){} @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.save(..))") private void pointcut2(){} @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.update(..))") private void pointcut3(){} @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.delete(..))") private void pointcut4(){} }
使用 类名.方法名()代替