zoukankan      html  css  js  c++  java
  • Spring使用AspectJ开发AOP:基于Annotation

    基于 Annotation 的声明式

    在 Spring 中,尽管使用 XML 配置文件可以实现 AOP 开发,但是如果所有的相关的配置都集中在配置文件中,势必会导致 XML 配置文件过于臃肿,从而给维护和升级带来一定的困难。

    为此,AspectJ 框架为 AOP 开发提供了另一种开发方式——基于 Annotation 的声明式。AspectJ 允许使用注解定义切面、切入点和增强处理,而 Spring 框架则可以识别并根据这些注解生成 AOP 代理。

    关于 Annotation 注解的介绍如表 1 所示。

    表 1 Annotation 注解介绍
    名称说明
    @Aspect 用于定义一个切面。
    @Before 用于定义前置通知,相当于 BeforeAdvice。
    @AfterReturning 用于定义后置通知,相当于 AfterReturningAdvice。
    @Around 用于定义环绕通知,相当于MethodInterceptor。
    @AfterThrowing 用于定义抛出通知,相当于ThrowAdvice。
    @After 用于定义最终final通知,不管是否异常,该通知都会执行。
    @DeclareParents 用于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。


    下面使用注解的方式重新实现《基于XML的声明式》部分的功能。

    1. 创建切面类 MyAspect

    在 src 目录下创建一个名为 com.mengma.aspectj.annotation 的包,在该包下创建一个切面类 MyAspect,如下所示。

    package com.mengma.aspectj.annotation;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    //切面类
    @Aspect
    @Component
    public class MyAspect {
    // 用于取代:<aop:pointcut
    // expression="execution(*com.mengma.dao..*.*(..))" id="myPointCut"/>
    // 要求:方法必须是private,没有值,名称自定义,没有参数
    @Pointcut("execution(*com.mengma.dao..*.*(..))")
    private void myPointCut() {
    }
    
    // 前置通知
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint) {
    System.out.print("前置通知,目标:");
    System.out.print(joinPoint.getTarget() + "方法名称:");
    System.out.println(joinPoint.getSignature().getName());
    }
    
    // 后置通知
    @AfterReturning(value = "myPointCut()")
    public void myAfterReturning(JoinPoint joinPoint) {
    System.out.print("后置通知,方法名称:" + joinPoint.getSignature().getName());
    }
    
    // 环绕通知
    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
    throws Throwable {
    System.out.println("环绕开始"); // 开始
    Object obj = proceedingJoinPoint.proceed(); // 执行当前目标方法
    System.out.println("环绕结束"); // 结束
    return obj;
    }
    
    // 异常通知
    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
    System.out.println("异常通知" + "出错了" + e.getMessage());
    }
    
    // 最终通知
    @After("myPointCut()")
    public void myAfter() {
    System.out.println("最终通知");
    }
    }

    上述代码中,第 13 行 @Aspect 注解用于声明这是一个切面类,该类作为组件使用,所以要添加 @Component 注解才能生效。第 19 行中 @Poincut 注解用于配置切入点,取代 XML 文件中配置切入点的代码。

    在每个通知相应的方法上都添加了注解声明,并且将切入点方法名“myPointCut”作为参数传递给要执行的方法,如需其他参数(如异常通知的异常参数),可以根据代码提示传递相应的属性值。

    2. 为目标类添加注解

    在 com.mengma.dao.CustomerDaoImpl 目标类中添加注解 @Repository("customerDao")。

    import org.springframework.stereotype.Repository;
    @Repository("customerDao")
    public class CustomerDao {
        public void doSome(){
           // int i=1/0;
            System.out.println("正式业务");
        }
    }

    3. 创建Spring配置文件

    在 com.mengma.aspectj.annotation 包下创建 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!--扫描含com.mengma包下的所有注解-->
    <context:component-scan base-package="com.mengma"/>
    <!-- 使切面开启自动代理 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

    上述代码中,首先导入了 AOP 命名空间及其配套的约束,使切面类中的 @AspectJ 注解能够正常工作;第 13 行代码添加了扫描包,使注解生效。需要注意的是,这里还包括目标类 com.mengma.dao.CustomerDaoImpl 的注解,所以 base-package 的值为 com.mengma;第 15 行代码的作用是切面开启自动代理。

    4. 创建测试类

    在 com.mengma.aspectj.annotation 包下创建一个名为 AnnotationTest 的测试类,如下所示。

    package com.mengma.aspectj.annotation;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.mengma.dao.CustomerDao;
    
    public class AnnotationTest {
    @Test
    public void test() {
    String xmlPath = "com/mengma/aspectj/xml/applicationContext.xml";
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
    xmlPath);
    // 从spring容器获取实例
    CustomerDao customerDao = (CustomerDao) applicationContext
    .getBean("customerDao");
    // 执行方法
    customerDao.add();
    }
    }

    5. 运行项目并查看结果

    使用 JUnit 测试运行 test() 方法,运行成功后,控制台的输出结果如图 3 所示。

    运行结果
    图 3  运行结果


    删除 add() 方法中的“int i=1/0;”,重新运行 test() 方法,此时控制台的输出结果如图 4 所示。

    运行结果
    图 4  运行结果


    从图 3 和图 4 的输出结果中可以看出,已成功使用 Annotation 的方式实现了 AOP 开发。与其他方式相比,基于 Annotation 方式实现 AOP 的效果是最方便的方式,所以实际开发中推荐使用注解的方式。

  • 相关阅读:
    HDU 2236 无题Ⅱ
    Golden Tiger Claw(二分图)
    HDU 5969 最大的位或 (思维,贪心)
    HDU 3686 Traffic Real Time Query System (图论)
    SCOI 2016 萌萌哒
    Spring Boot支持控制台Banner定制
    构建第一个Spring Boot程序
    Spring Boot重要模块
    Java fastjson JSON和String互相转换
    BCompare 4 Windows激活方法【试用期30天重置】
  • 原文地址:https://www.cnblogs.com/lowerma/p/11762100.html
Copyright © 2011-2022 走看看