• Spring框架(6)---AspectJ实现AOP


    AspectJ实现AOP

       上一篇文章Spring框架(4)---AOP讲解铺垫,讲了一些基础AOP理解性的东西,那么这篇文章真正开始讲解AOP

        通过AspectJ实现AOP要比普通的实现Aop要方便的多,所以第五篇文章有关SpringAOP我暂且不写,后面整理好了再补充上;

       那我们首先还是讲一些有的没的的东西:

    什么是Spring的AspectJ的AOP

          AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
      Spring2.0以后新增了对AspectJ切点表达式支持,@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
      新版本Spring框架,建议使用AspectJ方式来开发AOP

    那我们先来一个小案例,还是以前面狗的案例举例:

    1.导入相关架包

    在原来的基础上导入下面四个架包:

    • spring-aop-4.2.0.RELEASE.jar
    • com.springsource.org.aopalliance-1.0.0.jar
    • spring-aspects-4.2.0.RELEASE.jar
    • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

     2.编写配置文件applicationContext.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:p="http://www.springframework.org/schema/p"
        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.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"> <!-- bean definitions here -->
             
             <!-- 配置注解bean所在的包 -->
              <context:annotation-config/>
              <context:component-scan base-package="com.study.spring.d_advisor"></context:component-scan>
            <!-- 打开自动代理 -->
            <aop:aspectj-autoproxy/>
    </
    beans>
    
    

     3.编写代理对象

     1 public class Dog {
     2 
     3     public void run() {
     4         System.out.println("狗会跑");
     5     }
     6 
     7     public void jump() {
     8 
     9         System.out.println("狗会跳");
    10 
    11     }
    12 
    13     public void eat() {
    14 
    15         System.out.println("狗能吃");
    16     }
    17 }

    4)编写切面类

    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    //@Aspect声明当前类是一个切面
    @Aspect     
    public class MyAspectJ {
        //@Before代表在执行方法之前执行增强代码
        @Before("execution(* com.study.dog.Dog.*(..))")
        public void before1() {
            System.out.println("饲养员叫你你猜能动");
        }
    
    }

    5编写配置文件 

    <?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:p="http://www.springframework.org/schema/p"
        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.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"> <!-- bean definitions here -->
             
             <!-- 配置注解bean所在的包 -->
              <context:annotation-config/>
              <context:component-scan base-package="com.study.spring.d_advisor"></context:component-scan>
            <!-- 打开自动代理 -->
            <aop:aspectj-autoproxy/>
            
            
              <!-- 被代理对象 -->
               <bean id="Dog" class="com.study.dog.Dog"></bean>
             <!-- 切面 -->
              <bean id="MyAspectJ" class="com.study.dog.MyAspectJ"></bean>
           
            </beans>

    6.编写测试类

     1 import org.junit.Test;
     2 import org.junit.runner.RunWith;
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.beans.factory.annotation.Qualifier;
     5 import org.springframework.test.context.ContextConfiguration;
     6 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     7 
     8 //完成配置文件的加载
     9 @RunWith(SpringJUnit4ClassRunner.class)
    10 @ContextConfiguration(locations="classpath:applicationContext.xml")
    11 public class AspectJTest {
    12     // 得到dog对象
    13     @Autowired
    14     @Qualifier("Dog")
    15     private Dog dog;
    16 
    17     @Test
    18     public void Demo1() {
    19         dog.eat();
    20         dog.run();
    21         dog.jump();
    22     }
    23     /*
    24      * 输出结果:
    25      *    饲养员叫你你猜能动
    26      *    狗能吃
    27      *    饲养员叫你你猜能动
    28      *    狗会跑
    29      *    饲养员叫你你猜能动
    30      *    狗会跳
    31      */
    32 }

     总结:上面是一个最简单的AspectJ的AOP,我们这样就可以通过输入一个”饲养员叫你你猜能动",就可以在多个方法中存在,在以后开发非常需要

    那么下来来说一些非常重要的干货!

     AspectJ表达式:
        语法:execution(表达式) 通过execution函数,可以定义切点的方法切入

          execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)      

             例如

                   execution(public * *(..))                             匹配所有类public方法

                   execution(* cn.study.dao..*(..))                  匹配指定包下所有类方法,不包含子包

         execution(* cn.study.dao..*(..))                  ..*表示包、子孙包下所有类

         execution(* cn.study.service.UserService.*(..))  匹配指定类所有方法

         execution(* cn.study.dao.GenericDAO+.*(..))   匹配实现特定接口所有类方法

         execution(* save*(..))                                     匹配所有save开头的方法

        AspectJ增强
        @Before 前置通知,相当于BeforeAdvice
        @AfterReturning 后置通知,相当于AfterReturningAdvice
        @Around 环绕通知,相当于MethodInterceptor
        @AfterThrowing抛出通知,相当于ThrowAdvice
        @After 最终final通知,不管是否异常,该通知都会执行
        @DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)

    那现在我们通过上面的列子,来全面贯彻上面的干货!

    对上面MyAspectJ的进行全面增强:

    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;
    //@Aspect声明当前类是一个切面
    @Aspect     
    public class MyAspectJ {
       
         //@Before代表在执行方法之前执行增强代码
         @Before("execution(* com.study.dog.Dog.run(..))")
            public void before(JoinPoint joinPoint){
                System.out.println("前置增强...."+joinPoint);
            }  
         //后置通知
          @AfterReturning (value="execution(* com.study.dog.Dog.jump(..))",returning="returnVal")
            public void afterReturin(Object returnVal){
                System.out.println("后置增强....方法的返回值:"+returnVal);
            }  
          //环绕通知
            @Around(value="MyAspectJ.myPointcut()")
            public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
                System.out.println("环绕前增强....");
                Object obj = proceedingJoinPoint.proceed();
                System.out.println("环绕后增强....");
                return obj;
            } 
            //抛出通知
            @AfterThrowing(value="MyAspectJ.myPointcut()",throwing="e")
            public void afterThrowing(Throwable e){
                System.out.println("不好了 出异常了!!!"+e.getMessage());
            } 
            
            //最终final通知,不管是否异常,该通知都会执行
            @After("MyAspectJ.myPointcut()")
            public void after(){
                System.out.println("最终通知...");
            } 
          //切点的定义
            @Pointcut("execution(* com.study.dog.Dog.eat(..))")
            private void myPointcut(){}
    }

    编写测试类AspectJTest   和上面一点不变 

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    //完成配置文件的加载
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:applicationContext.xml")
    public class AspectJTest {
        // 得到dog对象
        @Autowired
        @Qualifier("Dog")
        private Dog dog;
    
        @Test
        public void Demo1() {
            dog.eat();
            dog.run();
            dog.jump();
        }
    
    }

    运行结果:

    通过这个例子,相信大家对于AspectJ的AOP有了一定的了解了。

    最后补充一个面试题:

         Advisor和Aspect的区别?
            Advisor:Spring传统意义上的切面:支持一个切点和一个通知的组合.
            Aspect:可以支持多个切点和多个通知的组合.

    这篇文章就讲到这里,有不足之处,欢迎大家指出,谢谢!

  • 相关阅读:
    python类库31[正则表达式匹配实例]
    Mysql百万级数据迁移实战笔记
    面试官:一千万数据,怎么快速查询?
    为什么MySQL不建议使用NULL作为列默认值?
    Redis各个数据类型最大存储量
    Rabbitmq延迟队列实现定时任务
    PHPstorm批量修改文件换行符CRLF为LF
    使用SeasLog打造高性能日志系统
    协程编程注意事项
    Rabbitmq 安装过程中常见问题(亲测可行)
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/6516946.html
Copyright © 2020-2023  润新知