• Spring 面向切面编程(AOP)



    Spring 系列教程


    面向切面编程(Aspect Oriented Programming/AOP)是Spring框架核心技术之一。

    面向切面编程的主要作用是,在不修改源代码的情况下,可以给目标类打补丁,让其执行补丁中的代码。

    例如,用户类中有个登录方法,现在需要加用户登录日志。使用AOP就不需要修改用户登录方法,只需把日志代码注入到用户登录方法前后,让其执行。日志代码就是“切面”,插入代码的地方(用户类的登录方法)就是“连接点”。

    面向切面编程概念

    先介绍一些AOP的概念

    • 切面(Aspect) - 一些横跨多个类的公共模块,如日志、安全、事务等。简单地说,日志模块就是一个切面。
    • 连接点(Joint Point) - 目标类中插入代码的地方。连接点可以是方法、异常、字段,连接点处的切面代码会在方法执行、异常抛出、字段修改时触发执行。
    • 建议(Advice) - 在连接点插入的实际代码(即切面的方法),有5种不同类型(后面介绍)。
    • 切点(Pointcut) - 定义了连接点的条件,一般通过正则表达式。例如,可以定义所有以loadUser开头的方法作为连接点,插入日志代码。

    建议类型

    • before - 在方法之前运行建议(插入的代码)
    • after - 不管方法是否成功执行,在方法之后运行插入建议(插入的代码)
    • after-returning - 当方法执行成功,在方法之后运行建议(插入的代码)
    • after-throwing - 仅在方法抛出异常后运行建议(插入的代码)
    • around - 在方法被调用之前和之后运行建议(插入的代码)

    实现

    与Bean配置一样,切面也需要配置,然后由Spring容器加载。切面配置可以使用XML,或者使用“AspectJ”语法,“AspectJ”语法使用Java代码实现切面配置。

    为更深理解AOP,下面实现一个日志切面的例子,例子使用XML配置。

    User类

    一个简单的用户类,是日志切面插入的目标类。用户类实现了几个不同的方法,这些方法会作为连接点。

    User.java

    public class User {
      private Integer id;
      private String name;
      
      public void setId(Integer id) {
        this.id = id;
      }
      
      public Integer getId() {
        System.out.println("Id: " + id);
        return id;
      }
      
      public void setName(String name) {
        this.name = name;
      }
      
      public String getName() {
        System.out.println("Name: " + name );
        return name;
      }
      
      public void printThrowException(){
        System.out.println("Exception raised");
        throw new IllegalArgumentException();
      }
    }
    

    切面 - Logging

    日志切面类,定义了要插入目标类执行的方法。

    Logging.java

    public class Logging {
      public void beforeAdvice(){
        System.out.println("Before Advice");
      }
    	
      public void afterAdvice(){
        System.out.println("After Advice");
      }
      
      public void afterReturningAdvice(Object retVal){
        System.out.println("After Advice Executed Successfully ... Returning: " + retVal.toString() );
      }
      
      public void AfterThrowingAdvice(IllegalArgumentException ex){
        System.out.println("There has been an exception when executing the advice: " + ex.toString());
      }
    }
    

    retVal是目标类连接点(方法)返回的值。例如,如果连接点是User类的getName()方法,该方法返回用户名称,那么retVal将被赋值用户名称。

    配置

    本例使用XML配置切面。

    首先定义切面类的Bean,然后切面定义中引用该Bean。

    切面定义中,会指明切点、插入的代码(建议),以及插入的代码怎么执行(建议类型)。

    下面的示例定义了一个名为UserAllMethod的切点,使用expression="execution(* User.*(..))"匹配User类中的所有方法作为连接点。

    如果想指定特定方法作为连接点,可使用execution(* User.getName(..))

    **示例:beans.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:context="http://www.springframework.org/schema/context"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    	http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context-3.0.xsd
    	http://www.springframework.org/schema/aop
    	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
    		
      <aop:config>
        <!-- Aspect -->
        <aop:aspect id="loggingAspect" ref="logging">
          
          <!-- Pointcut -->
          <aop:pointcut id="UserAllMethods" expression="execution(* User.*(..))"/>
          
          <!-- Advice(s) -->
          <aop:before pointcut-ref="UserAllMethods" method="beforeAdvice"/>
          <aop:after  pointcut-ref="UserAllMethods" method="afterAdvice"/>
          <aop:after-returning pointcut-ref="UserAllMethods" returning="retVal" method="afterReturningAdvice"/>
          <aop:after-throwing  pointcut-ref="UserAllMethods" throwing="ex" method="AfterThrowingAdvice"/>
        </aop:aspect>
      </aop:config>
      
      <!-- The user bean -->
      <bean id="user" class="User">
     	  <property name="name" value="隔壁老王" />
     	  <property name="id" value="99"/>
      </bean>
     
      <!-- logging 切面定义 -->
      <bean id="logging" class="Logging"/>
    </beans>
    

    确保已经添加了依赖的JAR包,我们使用Maven,pom.xml中添加依赖:

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.10</version>
    </dependency>
    

    测试切面

    在main类中调用用户类的方法,查看切面是否被执行:

    Test.java

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
      public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        
        User user = (User) context.getBean("user");	
        user.getName();
        user.printThrowException();
      }
    }
    
  • 相关阅读:
    实验四 决策树算法及应用
    实验三 朴素贝叶斯算法及应用
    实验二 K-近邻算法及应用
    实验一 感知器及其应用
    实验3: 面向对象分析与设计
    实验2:结构化分析与设计
    实验1:软件开发文档与工具的安装与使用
    软件工程第三次作业——ATM管理系统
    软件工程第二次作业——举例分析流程图与活动图的区别与联系
    软件工程第一次作业——小学四则运算题目生成程序
  • 原文地址:https://www.cnblogs.com/jinbuqi/p/10987723.html
Copyright © 2020-2023  润新知