Spring AOP详解

AOP产生背景

使用面向对象编程 ( OOP )有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了。

所以就有了一个对面向对象编程的补充,即面向方面编程 ( AOP ), AOP 所关注的方向是横向的,区别于 OOP 的纵向。

什么是AOP

什么是面向方面编程,3个过程:

  • 找到横切点:首要目标确定在程序的哪个位置进行横切逻辑

  • 横切逻辑(业务代码):横切逻辑代码,这个就是横切业务代码,与aop无关

  • 织入:将横切逻辑织入到横切点

开发者主要关心的是横切逻辑的编写,只需要很少的代码编写确定横切点有哪些,而不需要去为每个横切点添加横切逻辑,不然就是面向对象编程了。

既然是横向的编程,那么在我们的程序中,哪些可以作为横线切入点呢?

看下示例代码:

public class Test {
    public static void main(String[] args) {
        //@1
       B b = new B();
       //@2
       b.method();

       //@3
        B.say();
    }

    static class B {
        //字段
        //@4
        private String name;
        //构造方法
        public B() {
            //@1.1
            }
        //对象方法
        public void method(){
            //@2.2
        }
        //静态方法
        static void say(){
            //@3.3
        }
    }
}

所以我们可以将横切点主要分为两大类:字段、方法。方法又分为很多种,

Spring AOP详解_第1张图片

横切点有很多地方,从代码上看得见的,有如下几个地方:

  • 使用构造函数创建对象

  • 构造函数执行
     

  • 对象方法调用

  • 对象方法执行
     

  • 静态方法调用

  • 静态方法执行
     

  • 反射读写对象字段

AOP中的核心概念【理解】  

引入:加入我有一个类中有四个方法,update,save,save,select

public class StudentDaoImpl implements StudentDao {
    @Override
    public void save() {
        System.out.println("Student dao save ...");
    }

    @Override
    public void update() {
        System.out.println("Student dao update ...");
    }

    @Override
    public void save() {
        System.out.println("Student dao delete ...");

    }
    @Override
    public void select() {
        System.out.println("Student dao select ...");

    }

现在有一个需求:对save方法进行增强,循环输出1000次语句到控制台,并计算运行时间,那么我们可能这样

    @Override
    public void save() {
        //开始时间
        Long start =System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            System.out.println("Student dao save ...");
        }
        //结束时间
        Long end =System.currentTimeMillis();
        System.out.println("耗时: "+ (end-start)+" ms");
    }

现在问题来了,假设我需要将类中的save,select,update这三个方法都统计一下耗时,我该怎么做?

可以对每一个需要统计的方法都按照save方法一样进行修改代码,那么这样写麻不麻烦大家自己想一下。

答案是肯定的,所以我们就要使用新的方式去解决这个问题,这就是AOP(面向切面编程) 

Spring AOP详解_第2张图片

  • 连接点(JoinPoint):正在执行的方法,例如:update()、delete()、select()等都是连接点。

  • 切入点(Pointcut):进行功能增强了的方法,例如:update()、delete()方法,select()方法没有被增强所以不是切入点,但是是连接点。

    • 一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法

    • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法

    • 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法

  • 通知(Advice):在切入点前后执行的操作,也就是增强的共性功能

    • 在SpringAOP中,功能最终以方法的形式呈现

  • 通知类:通知方法所在的类叫做通知类

  • 切面(Aspect):描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。

 AOP工作流程

问题导入

什么是目标对象?什么是代理对象?

AOP工作流程

  1. Spring容器启动

  2. 读取所有切面配置中的切入点

  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

    • 匹配失败,创建原始对象

    • 匹配成功,创建原始对象(目标对象)的代理对象

  4. 获取bean执行方法

    • 获取的bean是原始对象时,调用方法并执行,完成操作

    • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

 AOP核心概念

  • 目标对象(Target):被代理的对象,也叫原始对象(StudentDaoImpl),该对象中的方法没有任何功能增强。

  • 代理对象(Proxy):代理后生成的对象,由Spring帮我们创建代理对象。

Spring AOP详解_第3张图片

在测试类中验证代理对象 

    @Test
    public void testAop() {
        System.out.println("也对对象类型: "+studentDao.getClass());
        studentDao.update();
    }

 Spring AOP详解_第4张图片

你可能感兴趣的:(spring,java,后端)