Spring AOP

一、AOP(概念)

1. 什么是AOP

  • 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

  • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

  • 使用登录例子说明AOP:

2. AOP底层原理

  • AOP底层使用动态代理

    1. 有接口情况,使用JDK动态代理:创建接口实现类的代理对象,增强类的方法

    2. 没有接口情况,使用CGLIB动态代理:创建子类的代理对象,增强类的方法

3. AOP(JDK动态代理)

  • 使用JDK动态代理,使用Proxy类里面的方法创建代理对象

    1. 调用newProxyInstance静态方法,里面有3个参数:

      public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

      第一个参数:类加载器

      第二个参数:增强方法所在的类,这个类实现的方法,支持多个接口

      第三个参数:创建的代理对象要实现InvocationHandler这个接口,里面写逻辑代码,就是增强的部分

    2. 编写JDK动态代理代码

      1. 创建接口,定义方法

        public interface UserDao {
        int add(int a, int b);
        String update(String id);
        }
      2. 创建接口实现类,实现方法

        public class UserDaoImpl implements UserDao {
        @Override
        public int add(int a, int b) {
        System.out.println("add方法执行了......");
        return a + b;
        } @Override
        public String update(String id) {
        System.out.println("update方法执行了......");
        return id;
        }
        }
      3. 使用Proxy类创建接口代理对象

        public class JDKProxy {
        public static void main(String[] args) {
        // 创建接口实现类代理对象
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1, 2);
        System.out.println("result: " + result);
        }
        }
      4. 创建代理对象代码

        class UserDaoProxy implements InvocationHandler {
        
            private Object obj;
        public UserDaoProxy(Object obj) {
        this.obj = obj;
        } // 增强的逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 方法之前
        System.out.println("方法之前执行......" + method.getName() + ", 传递的参数" + Arrays.toString(args)); // 被增强的方法执行
        Object res = method.invoke(obj, args); // 方法之后
        System.out.println("方法之后执行......" + obj); return res;
        }
        }

4. 关于AOP的术语

  1. 连接点:类里面哪些方法可以被增强,这些方法称为连接点
  2. 切入点:实际被增强的方法,称为切入点
  3. 通知(增强):实际增强的逻辑部分,称为通知
    • 通知有多种类型:

      • 前置通知
      • 后置通知
      • 环绕通知
      • 最终通知
      • 异常通知
  4. 切面:把通知应用到切入点的过程称为切面(是一个动作过程)

5. AOP操作

  • Spring框架一般都是基于AspectJ实现AOP操作的

    • AspectJ不是Spring框架的组成部分,是一个独立的AOP框架,一般把Spring喝AspectJ一起使用,进行AOP的操作
  • 基于AspectJ实现AOP操作

    • 基于XML配置文件实现
    • 基于注解方式实现(常用)
  • 引入相关jar包

  • 切入点表达式(重要):

    • 切入点表达式的作用:知道对哪个类里面的哪个方法进行增强

    • 语法表达式:execution([权限修饰符] [返回类型] [全类名] [方法名称]([参数列表]))

      • 其中权限修饰符可以省略,但是返回值类型(可以用*代替)必写!!!
      • 参数列表可以使用..代表自动匹配参数列表
    • 例子如下:

      // 对 com.atguigu.dao.BookDao 类里面的 add 进行增强
      execution(* com.atguigu.dao.BookDao.add(..))
      // 对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
      execution(* com.atguigu.dao.BookDao.* (..))
      // 对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
      execution(* com.atguigu.dao.*.* (..))

二、AOP操作(AspectJ注解)

1. 创建类,在类里面定义方法

public class User {
public void add() {
System.out.println("add......");
}
}

2. 创建增强类(编写增强逻辑)

  • 在增强类里面创建方法,让不同的方法代表不同的通知类型
public class UserProxy {
// 前置通知
public void before() {
System.out.println("before......");
}
}

3. 进行通知的配置

  1. 在Spring配置文件中,开启注解扫描

    • 要添加这两个标签:context和aop:
    <?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.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
    <!-- 开启Aspect生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>A
  2. 使用注解创建User和UserProxy

    // 被增强的类
    @Component
    public class User {
    ...
    } // 增强的类
    @Component
    public class UserProxy {
    ...
    }
  3. 在增强类的注解上添加@Aspect注解

    // 增强的类
    @Component
    @Aspect
    public class UserProxy {
    ...
    }
  4. 在Spring配置文件中开启生成代理对象

    <!-- 开启Aspect生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

4. 配置不同类型的通知

  • 在增强类的里面,在作为通知方法的上方添加通知类型的注解,只用切入点表达式配置

    @Component
    // 生成代理对象
    @Aspect
    public class UserProxy {
    // 前置通知
    @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void before() {
    System.out.println("before......");
    } // 后置通知(返回通知)
    @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void after() {
    System.out.println("after......");
    } // 最终通知
    @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void afterReturning() {
    System.out.println("afterReturning......");
    } // 异常通知
    @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void afterThrowing() {
    System.out.println("afterThrowing......");
    } // 环绕通知
    @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    System.out.println("环绕之前......");
    proceedingJoinPoint.proceed();
    System.out.println("环绕之后......");
    }
    }

5. 相同的切入点抽取

  • 提取切入点表达式

    @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void pointdemo() {
    } @Before(value = "pointdemo()")
    public void before() {
    System.out.println("before......");
    }

6. 有多个增强类对同一个方法进行增强,设置增强的优先等级

  • 在增强类上面添加注解@Order(数字类型值),数字小说明优先等级越高

    @Component
    @Aspect
    @Order(3)
    public class PersonProxy {
    } @Component
    @Aspect
    @Order(1) // 优先级1比3高
    public class UserProxy {
    }

7. 完全注解开发

  • 创建配置类,不需要创建XML配置文件

    @Configuration
    @ComponentScan(basePackages = {"com.atguigu"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAOP {
    }

三、AOP操作(AspectJ配置文件)

1. 创建两个类,增强类和被增强类,在类里面创建方法

2. 在Spring配置文件中创建两个对象

<!-- 创建对象 -->
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>

3. 在Spring配置文件中配置切入点和切面

<!-- 配置aop增强 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!-- 配置切面 -->
<aop:aspect ref="bookProxy">
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>

Spring笔记(三)的更多相关文章

  1. Spring笔记三

    Spring-03 1. AOP 1.1 概念 ​ AOP为Aspect Oriented Programming的缩写,意为:面向切面编程.他是一种可以在不修改原来的核心代码的情况下给程序动态统一进 ...

  2. Spring笔记(三)AOP前篇之动态代理

    AOP思想是将程序中的业务代码与服务代码进行分离,在运行时进行结合.比较强调程序的层次结构,是一种面向切面的编程.而在AOP实现的底层主要用到了动态代理,而动态代理又分为JDK动态代理和CGLIB动态 ...

  3. spring笔记(三)

    Spring 第二天: 1. 代理模式 2. Aop编程 3.Spring对Jdbc的支持 JdbcTemplate工具类 思考: 程序的“事务控制”, 可以用aop实现! 即只需要写一次,运行时候动 ...

  4. Spring笔记01_下载_概述_监听器

    目录 Spring笔记01 1.Spring介绍 1.1 Spring概述 1.2 Spring好处 1.3 Spring结构体系 1.4 在项目中的架构 1.5 程序的耦合和解耦 2. Spring ...

  5. 响应式编程笔记三:一个简单的HTTP服务器

    # 响应式编程笔记三:一个简单的HTTP服务器 本文我们将继续前面的学习,但将更多的注意力放在用例和编写实际能用的代码上面,而非基本的APIs学习. 我们会看到Reactive是一个有用的抽象 - 对 ...

  6. Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven)

    Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven) 本篇和 Spring 没有什么关系,只是学习 Spring,必备一些知识,所以放在这里了. 本篇内容: (1)M ...

  7. Spring笔记:AOP基础

    Spring笔记:AOP基础 AOP 引入AOP 面向对象的开发过程中,我们对软件开发进行抽象.分割成各个模块或对象.例如,我们对API抽象成三个模块,Controller.Service.Comma ...

  8. Spring笔记:IOC基础

    Spring笔记:IOC基础 引入IOC 在Java基础中,我们往往使用常见关键字来完成服务对象的创建.举个例子我们有很多U盘,有金士顿的(KingstonUSBDisk)的.闪迪的(SanUSBDi ...

  9. 学习spring第三天

    Spring第三天笔记 今日内容 Spring的核心之一 -  AOP思想 (1) 代理模式- 动态代理 ① JDK的动态代理 (Java官方) ② CGLIB 第三方代理 (2) AOP思想在Spr ...

  10. Spring笔记(6) - Spring的BeanFactoryPostProcessor探究

    一.背景 在说BeanFactoryPostProcessor之前,先来说下BeanPostProcessor,在前文Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析中讲解了Be ...

随机推荐

  1. web 存储方式汇总:Cookies,Session, Web SQL; Web Storage(LocalStorage ,SessionStorage),IndexedDB,Application Cache,Cache Storage

    1 1 1 web 存储方式汇总: 旧的方式: Cookies; Session; Web SQL; 新的方式 HTML5 : Web Storage(LocalStorage ,SessionSto ...

  2. Vue Big Changes All in One

    Vue Big Changes All in One Vue 重大更新 Vue Versions Vue 版本变更 Vue 3.x Vue 2.x refs vue lifecycle https:/ ...

  3. js regular expression & email checker

    js regular expression & email checker const isValidEmail = (email = ``) => /^([\w+\.])+@(\w+) ...

  4. CSS3 & Grid Layout All In One

    CSS3 & Grid Layout All In One W3C https://www.w3.org/TR/css-grid-1/ Grid Layout is a new layout ...

  5. TYLER ADAMS BRADBERRY:人到中年,要学会戒掉这三点

    在一些国家的一些人当中,总会出现这样一个问题"中年危机".而到了中年,人与人间的差距似乎也变得越来越大.有人说,人到中年,是一个门槛,有的人迈过去了,有的人没迈过去.但是,其实实话 ...

  6. PAA子公司在印度印度成立

    近日PAA房产又有大动作啦!在一片期待中,印度分公司正式成立!这是集团继泰国.越南.韩国.上海.成都.中国香港.中国台湾等分公司成立之后的又一扛鼎力作,更是PAA集团全球化战略布局的重要举措. 印度分 ...

  7. Mybatis-04 日志、分页

    Mybatis-04 日志.分页 日志 1.日志工厂 如果数据库操作出现异常,就需要打印日志来排错. 日志工厂会把日志工作委托实现: SLF4J Apache Commons Logging Log4 ...

  8. 手写一个webpack,看看AST怎么用

    本文开始我会围绕webpack和babel写一系列的工程化文章,这两个工具我虽然天天用,但是对他们的原理理解的其实不是很深入,写这些文章的过程其实也是我深入学习的过程.由于webpack和babel的 ...

  9. 为什么Linux默认页大小是4KB

    本文转载自为什么 Linux 默认页大小是 4KB 导语 我们都知道 Linux 会以页为单位管理内存,无论是将磁盘中的数据加载到内存中,还是将内存中的数据写回磁盘,操作系统都会以页面为单位进行操作, ...

  10. WPF 之绘画(十一)

    一.WPF 绘画 WPF 可以绘制线段(Line).矩形(Rectange).椭圆(Ellipse).路径(Path).具体使用如下所示: <!--(1)线段:Line--> <Li ...