Spring AOP 入门 注解

一、注解方式开发AOP

  • 创建Maven项目引入相应的pom
  • 引入Spring的配置文档 applicationContext.xml
  • 编写目标类以文章的增删改查为例,并完成配置
    ArticleDao.java
public class ArticleDao {
    public void save() {
        System.out.println("增加文章信息业务逻辑代码");
    }

    public boolean delete() {
        System.out.println("删除文章信息业务逻辑代码");
        return true;
    }

    public void update() {
        System.out.println("更新文章信息业务逻辑代码");

    }

    public void find() {
        System.out.println("查询文章信息业务逻辑代码");
        // 演示异常通知时打开
        // int i = 10 / 0;
    }
}

save演示前置通知

delete演示后置通知

update演示环绕通知

find演示异常通知和最终通知

将bean交给spring管理

<!--配置目标类-->
   <bean id="articleDao" class="edu.xufe.dao.ArticleDao"></bean>
  • 编写切面类并配置
public class MyAspectAnnotation {
    /**
     * 前置通知
     *
     * @param joinPoint
     */
    public void permissionToCheck(JoinPoint joinPoint) {
        System.out.println("权限校验业务逻辑代码........." + joinPoint);
    }

    /**
     * 后置通知
     */
    public void writeLog(Object result) {
        System.out.println("日志业务逻辑代码........." + result);
    }

    /**
     * 环绕通知
     *
     * @param proceedingJoinPoint
     * @return
     */
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知方法执行前业务逻辑代码。。。。。。。。。");

        Object object = proceedingJoinPoint.proceed();

        System.out.println("环绕通知方法执行后业务逻辑代码。。。。。。。。。");
        return object;
    }

    /**
     * 异常通知
     */
    public void afterThrowing(Throwable e) {
        System.out.println("异常通知逻辑代码........." + e);
    }

    public void after() {
        System.out.println("最终通知逻辑代码.........");
    }
}
<!--配置切面类-->
    <bean class="edu.xufe.aspect.MyAspectAnnotation" id="myAspectAnnotation"></bean>
  • 在配置文档中开启注解的AOP开发
<!--开启注解的AOP开发-->
  <aop:aspectj-autoproxy/>
  • 在切面类上使用注解
  • @Aspect 将类识别为切面
  • @Before 前置通知:@Before(value=“execution(表达式)”)
@Before(value = “execution(* edu.xufe.dao.ArticleDao.save())”)
  • @AfterReturning:后置通知@AfterReturning(value=“execution(表达式)”)
@AfterReturning(value = “execution(* edu.xufe.dao.ArticleDao.delete(…))”,returning = “result”)
  • @Around 环绕通知:@Around(value=“execution(表达式)”)
@Around(value = “execution(* edu.xufe.dao.ArticleDao.update(…))”)
  • @AfterThrowing(value=“execution(表达式)”)
@AfterThrowing(value = “execution(* edu.xufe.dao.ArticleDao.find(…))”,throwing = “e”)
  • @After(value=“execution(表达式)”)
@After(value = “execution(* edu.xufe.dao.ArticleDao.find(…))”)

加上注解后的切面类

@Aspect
public class MyAspectAnnotation {
    /**
     * 前置通知
     *
     * @param joinPoint
     */
    @Before(value = "execution(* edu.xufe.dao.ArticleDao.save(..))")
    public void permissionToCheck(JoinPoint joinPoint) {
        System.out.println("权限校验业务逻辑代码........." + joinPoint);
    }

    /**
     * 后置通知
     * returning = "result" 用于获取返回值
     */
    @AfterReturning(value = "execution(* edu.xufe.dao.ArticleDao.delete(..))",returning = "result")
    public void writeLog(Object result) {
        System.out.println("日志业务逻辑代码........."+result);
    }

    /**
     * 环绕通知
     *
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value = "execution(* edu.xufe.dao.ArticleDao.update(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知方法执行前业务逻辑代码。。。。。。。。。");

        Object object = proceedingJoinPoint.proceed();

        System.out.println("环绕通知方法执行后业务逻辑代码。。。。。。。。。");
        return object;
    }

    /**
     * 异常通知
     */
    @AfterThrowing(value = "execution(* edu.xufe.dao.ArticleDao.find(..))",throwing = "e")
    public void afterThrowing(Throwable e) {
        System.out.println("异常通知逻辑代码........." + e);
    }

    @After(value = "execution(* edu.xufe.dao.ArticleDao.find(..))")
    public void after() {
        System.out.println("最终通知逻辑代码.........");
    }
}
  • 编写测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")

public class ArticleDaoTest {
    @Resource(name = "articleDao")
    private ArticleDao articleDao;

    @Test
    public void test() {
        articleDao.save();
        articleDao.update();
        articleDao.delete();
        articleDao.find();
    }
}
  • 切入点的配置 注解
  • @Pointcut(value=“execution(表达式)”)
@Pointcut(value = “execution(* edu.xufe.dao.ArticleDao.save(…))”)
 private void pointcut() {
 }
  • 切入点的使用

@Before(value = “类名.pointcut()”)

使用切入点配置:便于维护,当方法很多时我们修改@Before(value=“execution(表达式)”) 这类配置显得很多很麻烦
但是修改切入点只改一个地方 及@Pointcut(value=“execution(表达式)”)中的表达式。

该目标类没有实现接口,所以在调试过程中我们可以看见AOP底层使用了Cglib代理。