(III)AOP:第三节:AOP概述

一、AOP 配置

  1、导入 jar 包

    ① 导入 Spring 基础包

           <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.1.3</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring-version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring-version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring-version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-expression</artifactId>
                <version>${spring-version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring-version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring-version}</version>
            </dependency>

 

    ② 导入基础的 AOP 包

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>5.2.3.RELEASE</version>
            </dependency>

 

    ③ 导入加强版的面向切面编程(即使目标对象没有实现任何接口也能创建动态代理

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>com.springsource.org.aspectj.weaver</artifactId>
                <version>1.6.4.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.aopalliance</groupId>
                <artifactId>com.springsource.org.aopalliance</artifactId>
                <version>1.0.0</version>
            </dependency>
            <dependency>
                <groupId>net.sourceforge.cglib</groupId>
                <artifactId>com.springsource.net.sf.cglib</artifactId>
                <version>2.1.3</version>
            </dependency>

 

 

  2、写配置

①将目标类和切面类(封装通知方法(在目标方法执行前后的方法))加入到IOC容器中

②告诉Spring哪个是切面类@Aspect

③告诉Spring,切面类里面的每一个方法,都是何时何地运行

   将业务类添加到容器中:

@Service
public class MyMathCalculator implements Calculator{}

   将切面类(日志类)加到容器中

/**
 * 如果将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
 */
@Aspect
@Component
public class LogUtils {

    /**
     * 告诉 Spring 每个方法都什么时候运行
     *
     * try {
     *     @Before
     *     method.invoke(obj, args);
     *     @AfterReturning
     * }catch(e) {
     *     @AfterThrowing
     * }finally {
     *     @After
     * }
     *
     *
     * @Before:在目标方法运行之前              前置通知
     * @After:在目标方法运行结束之后           后置通知
     * @AfterReturning:在目标方法正常放回之后  返回通知
     * @AfterThrowing:在目标方法抛异常之后     异常通知
     * @Around:环绕                           环绕通知
     */

    //想在执行目标方法之前
    //execution(访问权限符 返回值类 方法签名)
    @Before("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    public static void logStart(){
        System.out.println("【XXX】方法执行了,参数为【XXX】");
    }

    //想在目标方法正执行完毕之后
    @AfterReturning("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    public static void logReturn(){
        System.out.println("【XXX】方法执行完成,他的结果为是:");
    }

    @AfterThrowing("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    //想在目标方法出现异常时执行
    public static void logException(){
        System.out.println("【XXX】方法出现了异常,异常为: ");
    }

    //想在目标方法结束时执行
    @After("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    public static void logEnd(){
        System.out.println("【XXX】方法执行最终完成");
    }
}

 

    开启包扫描:

    <context:component-scan base-package="com.njf.aop"></context:component-scan>

 

 

  3、在配置文件中 开启基于注解的AOP模式

    <!--  开启基于注解的AOP功能:aop 名称空间  -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

 

 

  4、测试

    ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");

    @Test
    public void test1() {
        //1、从ioc容器中拿到目标对象
        //注意:如果想要用类型获取,一定要用他的接口类型,不要用他的本类
        Calculator calculator = ioc.getBean(Calculator.class);

        calculator.add(1, 2);
    }

 

 

二、AspectJ

  1、简介

    AspectJ:Java社区里最完整最流行的AOP框架。

    在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。

  2、在 Spring 中启用 AspectJ 注解支持

    ① 导入jar包依赖

aopalliance.jar

aspectj.weaver.jar

spring-aspects.jar

  

    ② 开启基于注解的 AOP

      (1)引入AOP名称空间

      (III)AOP:第三节:AOP概述

 

 

       (2)配置文件

        在配置文件中开启自动生成代理。

 

<!-- 开启 aspectJ 的自动代理功能 -->
<aop:aspectj-autoproxy />
作用:当 Spring IOC 容器侦测到 bean 配置文件中的 <aop:aspectj-autoproxy> 元素时,会自动为与 AspectJ 切面匹配的 bean 创建代理。

 

 

 

 

 

 

 

        

 

  3、用AspectJ注解声明切面

  (1)要在  Spring 中声明 AspectJ 切面,只需要在 IOC 容器中将切面声明为 bean 实例;   (2)当在 Spring IOC 容器中初始化 AspectJ 切面之后,Spring IOC 容器就会为那些与 AspectJ 切面想匹配的 bean 创建代理;   (3)在 AspectJ 注解中,切面只是一个带有 @Aspect 注解的 Java 类,它往往包含很多通知;

 

  (4)通知是标注有某种注解的简单的 Java 方法;
try{
    @Before
    method.invoke(obj,args);
    @AfterReturning
}catch(e){
    @AfterThrowing:在目标方法抛异常之后
}finally{
    @after:在目标方法运行结束之后
}

 

 

 

  4、切点表达式:

execution(访问权限符 返回值类型 方法签名)

  5、通知注解

AspectJ 支持 5 种类型的通知注解:
告诉Spring每个方法,都什么时候运行

① @Before:前置通知,在方法执行之前执行;
② @After:后置通知,在方法执行之后执行(finally里面,永远都会执行);
③ @AfterRunning:返回通知,在方法返回结果之后执行;
④ @AfterThrowing:异常通知,在方法抛出异常之后执行;
⑤ @Around:环绕通知,围绕这方法执行;

 

 

三、完整代码

  计算器核心业务:

  

// 计算器接口
public interface Calculator {

    public int add(int i, int j);
    public int sub(int i, int j);
    public int mul(int i, int j);
    public int div(int i, int j);
}

//计算器接口实现类
@Service
public class MyMathCalculator implements Calculator{

    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }

}

 

 

  切面类:

/**
 * 如果将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
 */
@Aspect
@Component
public class LogUtils {

    /**
     * 告诉 Spring 每个方法都什么时候运行
     *
     * try {
     *     @Before
     *     method.invoke(obj, args);
     *     @AfterReturning
     * }catch(e) {
     *     @AfterThrowing
     * }finally {
     *     @After
     * }
     *
     *
     * @Before:在目标方法运行之前              前置通知
     * @After:在目标方法运行结束之后           后置通知
     * @AfterReturning:在目标方法正常放回之后  返回通知
     * @AfterThrowing:在目标方法抛异常之后     异常通知
     * @Around:环绕                           环绕通知
     */

    //想在执行目标方法之前
    //execution(访问权限符 返回值类 方法签名)
    @Before("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    public static void logStart(){
        System.out.println("【XXX】方法执行了,参数为【XXX】");
    }

    //想在目标方法正执行完毕之后
    @AfterReturning("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    public static void logReturn(){
        System.out.println("【XXX】方法执行完成,他的结果为是:");
    }

    @AfterThrowing("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    //想在目标方法出现异常时执行
    public static void logException(){
        System.out.println("【XXX】方法出现了异常,异常为: ");
    }

    //想在目标方法结束时执行
    @After("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
    public static void logEnd(){
        System.out.println("【XXX】方法执行最终完成");
    }
}

 

 

  配置文件:

    <!-- 扫描让 IOC 容器管理的 bean -->
    <context:component-scan base-package="com.njf.aop"></context:component-scan>
     
     <!-- 当Spring IOC容器侦测到bean配置文件中的该元素时,会自动为与AspectJ切面匹配的bean创建代理 -->
     <!-- 开启 aspectJ 的自动代理功能 -->
     <aop:aspectj-autoproxy />

 

 

四、

五、

 
开启基于注解的AOP功能
上一篇:leetcode反转字符串中的单词 III


下一篇:剑指 Offer 32 - III. 从上到下打印二叉树 III