Catalog
  1. 1. Spring学习笔记(九)AOP实例
    1. 1.1. 九、Spring中的AOP
      1. 1.1.1. 1、AOP术语
      2. 1.1.2. 2 、Spring中基于 xml 的 AOP 配置步骤
      3. 1.1.3. 3、实例
Spring学习笔记(九)AOP实例

Spring学习笔记(九)AOP实例

九、Spring中的AOP

1、AOP术语

  • Advice (通知/增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
  • Joinpoint (连接点): 所谓连接点是指那些被拦截到的点。在 Spring 中,这些点指的是方法,因为 Spring 只支持方法类型的 连接点。
  • Pointcut (切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
  • Introduction (引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方 法或 Field。 Target(目标对象): 代理的目标对象。
  • Weaving (织入): 是指把增强应用到目标对象来创建新的代理对象的过程。 Spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
  • Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类。 Aspec t(切面): 是切入点和通知(引介)的结合。

2 、Spring中基于 xml 的 AOP 配置步骤

  1. 把通知 Bean 也交给 Spring 来管理
  2. 使用 aop : config 标签来表明开始 AOP 的设置
  3. 使用 aop : aspect 标签配置切面
    • id 属性:是给切面提供一个唯一标识
    • ref 属性:是指定通知类 Bean 的 id
  4. 在 aop : aspect 标签的内部使用对应标签来配置通知的类型
    1. aop : before 标识前置通知
      • method 属性:用于指定类中哪个放啊是前置通知
      • pointcut 属性:用于指定切入点表达式,该切入点表达式指的是对业务层中哪些方法增强
    2. 切入点表达式的写法:
      • 关键字:execution ( 表达式 )
      • 表达式:
        • 标准写法:访问修饰符 + 返回值 + 包名.类名.方法名(参数列表)
        • 举例:public void com.greyson.service.impl.IAccountServiceImpl.saveAccount ( )
      • 全通配写法:* * ..*.*(..)
        • 访问修饰符可以省略
        • 返回值可以使用通配符,表示任意返回值
        • 包名可以使用通配符,表示任意包,但是有几级包就需要写几个 *.
        • 包名可以使用 .. 表示当前包和子包
        • 类名和方法名都可以使用 * 来实现通配
        • 参数列表:
          • 可以直接使写数据类型:
            • 基本类型直接写名称(如 int )
            • 引用类型写包名.类名的方式 (如 java.lang.String )
          • 可以使用通配符表四任意类型,但是必须有参数
          • 可以使用 .. 表示有无参数即可,有参数可以是任意类型
      • 实际开发中切入点表达式的通常写法:
        • 切到业务层类实现下的所有方法:* com.greyson.service.impl.*.*(..)
      • 配置切入点表达式(aop : pointcut):
        • id属性用于指定表达式的唯一标识,expression属性用于指定表达式内容
        • 此标签写在 aop : aspect 标签内部只能当前切面使用,在其外部则所有切面可用
    3. Spring常用通知类型
      • 前置通知(aop : before):在切入点方法执行之前执行
      • 后置通知(aop : after-returning):在切入点方法正常执行之后执行,它和异常通知永远只能执行一个
      • 异常通知(aop : after-throwing):在切入点方法执行产生异常之后执行,它和后置通知永远只能执行一个
      • 最终通知(aop : after):无论切入点方法是否正常执行它都会在其后面执行
    4. 环绕通知

3、实例

  1. 引入 Maven 工程

    • Pom.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.greyson</groupId>
          <artifactId>day03_SpringAOP</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>jar</packaging>
      
          <build>
              <finalName>webapp</finalName>
              <plugins>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <version>3.6.0</version>
                      <configuration>
                          <source>1.8</source>
                          <target>1.8</target>
                      </configuration>
                  </plugin>
              </plugins>
          </build>
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
                  <version>5.0.7.RELEASE</version>
              </dependency>
      
              <!--解析切入点表达式-->
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjweaver</artifactId>
                  <version>1.9.1</version>
              </dependency>
          </dependencies>
​    

    </project>
  1. 编写业务代码

    • IAccountService

      /**
       * 账户的业务层接口
       */
      public interface IAccountService {
          /**
           * 模拟保存账户
           *
           */
          void saveAccount();
      
          /**
           * 模拟更新账户
           * @param i
           */
          void updateAccount(int i);
      
          /**
           * 删除账户
           * @return
           */
          int deleteAccount();
      }
    • AccountServiceImpl

      /**
       * 账户的业务层实现类
       */
      public class AccountServiceImpl implements IAccountService {
      
          @Override
          public void saveAccount() {
              System.out.println("执行了保存");
          }
      
          @Override
          public void updateAccount(int i) {
              System.out.println("执行了更新" + i);
          }
      
          @Override
          public int deleteAccount() {
              System.out.println("执行了删除");
              return 0;
          }
      }
    • Logger

      /**
       * 用于记录日志的工具类,它里面提供了公共的代码
       */
      public class Logger {
          public void printLog() {
              System.out.println("lOGGER类中的printLog开始记录日志了。。。");
          }
      }
  2. 配置Spring

    • bean.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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              http://www.springframework.org/schema/aop/spring-aop.xsd">
      
              <!-- 配置Spring的IOC,把Service对象配置进来-->
              <bean id="accountService" class="com.greyson.service.impl.AccountServiceImpl"></bean>
      
              <!--配置Logger类-->
              <bean id="logger" class="com.greyson.utils.Logger"></bean>
      
              <!--配置AOP-->
              <aop:config>
                      <!--配置切面-->
                      <aop:aspect id="logAdvice" ref="logger">
                              <!--配置通知的类型,并且建立通知方法和切入点方法的关联-->
                              <aop:before method="printLog" pointcut="execution(* com.greyson.service.impl.*.*(..))"></aop:before>
                      </aop:aspect>
              </aop:config>
      </beans>
  3. 编写测试类

    • TestAOP

      /**
       * 测试AOP的配置
       */
      public class TestAOP {
          public static void main(String[] args) {
              // 1. 获取容器
              ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
              // 2. 获取对象
              IAccountService accountService = (IAccountService)applicationContext.getBean("accountService");
              // 3. 执行方法
              accountService.saveAccount();
              accountService.updateAccount(1);
              accountService.deleteAccount();
          }
      }
Author: zycode1561
Link: https://zycode1561.github.io/2019/11/07/Spring%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B9%9D%EF%BC%89AOP%E5%AE%9E%E4%BE%8B/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
  • 支付宝

Comment