zoukankan      html  css  js  c++  java
  • Spring AOP

    面向切面编程简介

    1. 什么是面向切面编程?

      面向切面编程是Spring的第二大特性,它能将一个函数中非主体但有很必要的代码封装到一个单独的类中,在程序运行的时候再把它们插入到函数中。这样能使程序猿只关注函数的主体功能,而且写出来的代码具有具有较强的可读性,简约明了。 

    2. 面向切面编程的优点

    面向切面编程的优点有两个: 
    1. 一个函数中所有额外的功能都被封装在一个类中,而不是分散在函数的各处。 
    2. 由于将非主体功能的代码转移到其他类中,因此函数的代码将更佳简洁。

    3. Spring的面向切面编程特点

    目前面向切面(AOP)市场的三足鼎立格局是这样的: 
    - AspectJ 
    - JBoss Aspect 
    - Spring Aspect 
    Spring Aspect借鉴AspectJ。

      所谓面向切面,前面已经介绍过,就是将函数的一部分代码抽取出来,封装到一个类中,然后在某一时刻将其插入到程序中去。 
    AOP世界中,将切面插入的到程序中的时机有以下三种: 
    1. 编译时插入 
    2. 类被加载的时候插入 
    3. 程序运行时被插入

      Spring是在程序运行期间将切面插入到相关函数中去的。 
      此外,在编译时插入需要特殊的编译器,在类加载的时候插入需要特殊的类加载器,而在运行时插入不需要额外的软件支持。

    开始使用

      假设现在有一个函数,用来查询数据库中名字为name的Person对象:

     public String queryPersons(String name){
            //查询的具体操作……
            //此处省略100行代码……
        }

      我们需要在查询开始前判断name是否为空,在查询结束后记录操作日志,在查询发生异常时记录异常日志。 
      在过去,我们把这些代码都直接写在这个函数中,这样会导致这个函数很长,可读性很差。下面我们使用面向切面编程的思想解决这个问题。 

    1. 定义切面代码

    首先需要将这个函数中额外的功能封装到一个类中,这个类就是一个普通类,功能封装在函数中:

    class PersonAspect(){
        /**
          * 判断参数是否为空
          */
        public void verifyNull(String name){
            //判断参数是否为空
        }
    
        /**
          * 记录操作日志
          */
        public void logInfo(){
    
        }
    
        /**
          * 记录异常日志
          */
        public void logError(){
    
        }
    }

    2. 将切面声明为bean

    在Spring的配置文件中添加bean的声明:

     <bean id="personAspect" class="com.njupt.PersonAspect">
        </bean>

    或者直接在PersonAspect类上使用@Componet标注:

    @Componet("personAspect")
    class PersonAspect(){
        /**
          * 判断参数是否为空
          */
        public void verifyNull(String name){
            //判断参数是否为空
        }
    
        /**
          * 记录操作日志
          */
        public void logInfo(){
    
        }
    
        /**
          * 记录异常日志
          */
        public void logError(){
    
        }
    }
    View Code

    3. 声明通知

    定义好了额外的功能之后,接下来我们需要告诉Spring,这些功能需要在何时添加到哪个函数的什么位置,因此我们需要在Spring的配置文件中作如下声明:

    <aop:config>
            <aop:aspect ref="personAspect">
                <!-- 在queryPersons函数执行之前先运行函数verifyNull -->
                <aop:before pointcut="excution(* com.njupt.Person.queryPersons(..))" method="verifyNull" />
    
                <!-- 在queryPersons函数执行之后再运行函数logInfo -->
                <aop:after-returning pointcut="excution(* com.njupt.Person.queryPersons(..))" method="logInfo" />
    
                <!-- 在queryPersons函数发生异常时运行函数logError -->
                <aop:throwing pointcut="excution(* com.njupt.Person.queryPersons(..))" method="logError" />
        </aop:config>

    到此为止,Spring AOP已经可以运行了!

    4. 声明环绕通知

      在上述示例中,函数前插入一段代码,函数后插入一段代码,函数异常时插入一段代码,这些代码块都是独立的,无法共享数据。如果需要实现函数前后代码块的数据共享,那就要使用环绕通知。 
    说来也很简单,首先需要在PersonAspect类中加上一个参数为ProceedingJoinPoint的函数,如下所示:

    @Componet("personAspect")
    class PersonAspect(){
        /**
          * 判断参数是否为空
          */
        public void verifyNull(String name){
            //判断参数是否为空
        }
    
        /**
          * 记录操作日志
          */
        public void logInfo(){
    
        }
    
        /**
          * 记录异常日志
          */
        public void logError(){
    
        }
    
        /**
          * 环绕通知
          */
        public void xxx(ProceedingJoinPoint joinPoint){
            int num = 0;
            //在函数前执行一些功能,修改num参数
    
            //执行函数
            joinPoint.proceed();
    
            //在函数后处理num
            num++;
            //……
        }
    }

    然后在配置文件中把这个函数声明为环绕通知即可:

     <aop:config>
            <aop:aspect ref="personAspect">
                <!-- 在queryPersons函数执行之前先运行函数verifyNull -->
                <aop:before pointcut="excution(* com.njupt.Person.queryPersons(..))" method="verifyNull" />
    
                <!-- 在queryPersons函数执行之后再运行函数logInfo -->
                <aop:after-returning pointcut="excution(* com.njupt.Person.queryPersons(..))" method="logInfo" />
    
                <!-- 在queryPersons函数发生异常时运行函数logError -->
                <aop:throwing pointcut="excution(* com.njupt.Person.queryPersons(..))" method="logError" />
    
                <!-- 环绕通知 -->
                <aop:around pointcut="excution(* com.njupt.Person.queryPersons(..))" method="xxx()" />
            </aop:aspect>
        </aop:config>

    到此为止,Spring的AOP介绍完毕,下面介绍如何使用注解取代XML。

    使用注解代替XML

    1. 注解切面

       首先需要在切面类上加上注解@Aspect,告诉Spring这个类是个切面类; 
      其次需要在切面类中创建一个函数,用于定义切点。该函数的名字即为切点名,函数返回值和参数均为空。

    @Aspect
    class PersonAspect(){
        /**
          * 定义切点
          */
        @Pointcut("excution(* com.njupt.Person.queryPersons(..))")
        public void personAspect(){
        }
    
        /**
          * 判断参数是否为空
          */
        @Before("personAspect()")
        public void verifyNull(String name){
            //判断参数是否为空
        }
    
        /**
          * 记录操作日志
          */
        @AfterReturning("personAspect()")
        public void logInfo(){
    
        }
    
        /**
          * 记录异常日志
          */
        @AfterThrowing("personAspect()")
        public void logError(){
    
        }
    
        /**
          * 环绕通知
          */
        @Around("personAspect()")
        public void xxx(ProceedingJoinPoint joinPoint){
            int num = 0;
            //在函数前执行一些功能,修改num参数
    
            //执行函数
            joinPoint.proceed();
    
            //在函数后处理num
            num++;
            //……
        }
    }

    转自:https://blog.csdn.net/u010425776/article/details/51044138

  • 相关阅读:
    程序的了解
    Oracle VM VirtualBox虚拟网卡消失解决方法
    YARN 运维、巡检、监控、调优、排障
    HDFS巡检、监控、调优、排障
    Windows CMD命令大全
    [HDU]6356 Glad You Came(ST表)
    [BZOJ] 1019 [SHOI2008]汉诺塔
    树上叶子之间点对距离平方和
    [BZOJ]1026[SCOI2009]windy数
    [计蒜客]A1542 The Maximum Unreachable Node Set
  • 原文地址:https://www.cnblogs.com/xdyixia/p/9351193.html
Copyright © 2011-2022 走看看