Spring学习-6【基于xml的aop配置】

  • 直接使用简单案例

1.修改pom.xml文件

<packaging>jar</packaging>
  <dependencies>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.0.10.RELEASE</version>
      </dependency>
      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.9.4</version>
      </dependency>

  </dependencies>

2.业务层接口和实现类

package com.service;

public interface IAccountService {
  //模拟保存账户
  void saveAccount();

  /**
    * 模拟更新账户
    * @param i
    */
  void updateAccount(int i);

  /**
    * 删除账户
    * @return
    */
  int deleteAccount();
}
-----------------------------------------------------------------------------
package com.service.impl;

import com.service.IAccountService;
import org.springframework.stereotype.Service;


public class AccountServiceImpl implements IAccountService {
  @Override
  public void saveAccount() {
      System.out.println("save");
  }

  @Override
  public void updateAccount(int i) {
      System.out.println("update"+i);
  }

  @Override
  public int deleteAccount() {
      System.out.println("delete");
      return 0;
  }
}

3.自定义日志类,用作切面

package com.utils;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//日志类,用于之切入点方法之前执行
public class Logger {
  /**
    * 前置通知
    */
  public void beforePrintLog(){
      System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
  }

  /**
    * 后置通知
    */
  public void afterReturningPrintLog(){
      System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
  }
  /**
    * 异常通知
    */
  public void afterThrowingPrintLog(){
      System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
  }

  /**
    * 最终通知
    */
  public void afterPrintLog(){
      System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
  }
}

4.配置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">

  <bean id="accountService" class="com.service.impl.AccountServiceImpl">

  </bean>
  <!--spring中基于XML的AOP配置步骤
      1、把通知Bean也交给spring来管理
      2、使用aop:config标签表明开始AOP的配置
      3、使用aop:aspect标签表明配置切面
              id属性:是给切面提供一个唯一标识
              ref属性:是指定通知类bean的Id。
      4、在aop:aspect标签的内部使用对应标签来配置通知的类型
              我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
              aop:before:表示配置前置通知
                  method属性:用于指定Logger类中哪个方法是前置通知
                  pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强

          切入点表达式的写法:
              关键字:execution(表达式)
              表达式:
                  访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
              标准的表达式写法:
                  public void com.service.impl.AccountServiceImpl.saveAccount()
              访问修饰符可以省略
                  void com.service.impl.AccountServiceImpl.saveAccount()
              返回值可以使用通配符,表示任意返回值
                  * com.service.impl.AccountServiceImpl.saveAccount()
              包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
                  * *.*.*.*.AccountServiceImpl.saveAccount())
              包名可以使用..表示当前包及其子包
                  * *..AccountServiceImpl.saveAccount()
              类名和方法名都可以使用*来实现通配
                  * *..*.*()
              参数列表:
                  可以直接写数据类型:
                      基本类型直接写名称           int
                      引用类型写包名.类名的方式   java.lang.String
                  可以使用通配符表示任意类型,但是必须有参数
                  可以使用..表示有无参数均可,有参数可以是任意类型
              全通配写法:
                  * *..*.*(..)

              实际开发中切入点表达式的通常写法:
                  切到业务层实现类下的所有方法
                      * com.service.impl.*.*(..)
  -->
  <!-- 配置Logger类 -->
  <bean id="logger" class="com.utils.Logger"></bean>

  <!--配置AOP-->
  <aop:config>
      <!-- 配置切入点表达式 id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
            此标签写在aop:aspect标签内部只能当前切面使用。
            它还可以写在aop:aspect外面,此时就变成了所有切面可用
        -->
      <aop:pointcut id="pt1" expression="execution(* com.service.impl.*.*(..))"></aop:pointcut>
      <!--配置切面 -->
      <aop:aspect id="logAdvice" ref="logger">
          <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
          <aop:before method="beforePrintLog" pointcut="execution(* com.service.impl.*.*(..))"></aop:before>

          <!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个 -->
          <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>

          <!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个-->
          <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>

          <!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行-->
          <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>

      </aop:aspect>
  </aop:config>
</beans>

5.测试类

package com;

import com.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
  public static void main(String[] args) {

      ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
      //得到业务层对象

      IAccountService interService=applicationContext.getBean("accountService", IAccountService.class);
      //执行方法
      interService.saveAccount();
  }
}