ssm框架之spring的动态代理,AOP,和声明式事务

1、动态代理

  • 什么是动态代理

    • 动态代理是一种设计模式(GOF23设计模式之一),在框架中使用居多,在spring中扩展出了AOP切面编程
    • 动态代理可以这么理解,有一个类,它主要实现一些具体的逻辑操作,其中大量方法实现不同逻辑,现在想要为每一个方法都配置一个秘书(同一个人),当方法执行之前,做一些处理,比如当方法执行前,记录一下执行的开始时间,方法执行完后再记录一下结束时间
    • 如果没有这位秘书,就需要每一个方法都自己实现时间的记录,如果有10000个方法,就需要20000条代码实现记录,如果日后需要修改,也需要改20000行代码
    • 但如果这些都交给一个代理者,就是秘书来做的话,每个方法执行时告诉秘书即可,秘书会帮我们记录,如果日后想要修改记录,只要告诉秘书怎么修改即可
    • 那么秘书始终只需要执行两行代码,修改时也只需要修改两行代码,
    • 这位秘书就是我们的代理者,而方法就是被代理者,这种设计模式就是动态代理
  • 动态代理的好处

    • 不用修改被代理者(方法)的代码就可以扩展新的功能(秘书帮我们做),也就符合开闭原则
    • 维护方便,试想改20000行和改2行的区别即可
  • 如何实现动态代理

    首先动态代理涉及到大量基础语法,反射,匿名函数等等,思路较复杂,所以spring帮我们基于动态代理实现了AOP,我们主要学习AOP,这里动态代理只需理解即可,如果想掌握,以下动态代理讲解也比较详细
    • 通过JDK实现动态代理
      • JDK动态代理需要继承接口来实现
      • Proxy类:
        • 所有动态代理类的父类,专门用来生成代理类或代理对象
        • 下图中第一个方法用于生成代理类(代理者)的Class对象
        • 第二个方法用于生成代理类的代理对象(后面会用到)
          在这里插入图片描述
      • InvocationHandler接口:
        • 用来完成我们动态代理的整个过程
        • 完成动态代理我们需要知道
          • 需要代理的对象是谁
          • 如何获取代理对象
          • 我们要为被代理者完成那些操作
        • 此接口有一个invoke方法,完成动态代理的代码都会在这里编写,但是它不是反射的invoke方法,只是同名而已,不要混淆
          在这里插入图片描述
    • 实现步骤
      • 1、创建一个接口和它的实现类,当做被代理类 (前面例子中有大量方法的类)
        在这里插入图片描述
        在这里插入图片描述
    • 2、创建一个类,当做代理类(前面例子中的秘书)
      在这里插入图片描述
    • 3、确定需要代理的对象是谁
      在这里插入图片描述
    • 4、获取代理对象
      我们在获取代理对象时,会将方法的执行拦截下来,转到代理类,这时原来方法的执行就转到代理类了
      在这里插入图片描述
    • 5、为你的代理对象执行那些操作
      因为上一步将我们被代理对象的方法拦截,无法继续向下执行,所有我们一定要将方法的执行转回给原来的对象,这就需要用反射
      在这里插入图片描述
      那么既然我们可以通过反射执行目标方法,那么我们就可以在这里编写时间的记录
      在这里插入图片描述
    • 6、测试
      在这里插入图片描述

2、AOP(Aspect Oriented Programming)面向切面编程

AOP在我们未来开发中也用的比较少,我们学习动态代理是为了学习AOP,AOP底层是用动态代理实现的,而我们学习AOP是为了学习声明式事务,它是spring中十分强力的一个功能,而声明式事务的底层是用AOP实现的

  • 什么是面向切面编程

    面向切面编程,就是动态代理的升级版,它是spring将原生的实现动态代理的JDK代码重新封装的产物。
    面向切面就是将某个方法当成一个平面,可以通过注解,在这个平面的上面切入一个平面,下面切入一个平面,如果这个平面碎了(方法出错了),立即补上一个平面。而不断为某个方法提供切面的类就叫切面类,这就是面向切面编程
  • AOP术语(专业名词)

    • 横切关注点
      指的是一些具有横越多个模块的行为,传统方式到达不了的一个特殊关注点,就是关注我们切面往哪横切。
    • 切面(Aspect)
      切面就是通知方法,就是实现功能的方法,这些方法会根据横切关注点,横切到指定位置
    • 通知(Advice)
      每个切面具体需要完成的工作
      • @Before(value=“切入点表达式”)前置通知:在目标方法执行前执行
      • @AfterReturning(“切入点表达式”)返回通知:目标方法正常执行完成后执行
      • @AfterThrowing(“execution(…)”)出错通知:目标方法出错后执行
      • @After(“execution(…)”)后缀通知:目标方法执行结束,无论对错都执行
      • @Around(“execution”)环绕通知:前面所有的结合形式
    • 目标(Target)
      被通知对象,被横切对象或者说被代理对象
    • 代理(Proxy)
      目标对象应用通知后创建的代理对象
    • 连接点(Joinpoint)
      横切关注点的具体实现,就是规定切面往哪横切,比如某个方法开始,结束,捕获异常后,这些就是连接点,连接点就是实现了横切关注点,可以当做连接点就是你需要代理的方法
    • 切入点(pointcut)
      就是规定何时何地,定位哪个连接点,比如我们规定通知方法的切入点,是目标方法执行之前执行,那么就会找到对应的连接点,将方法切入。会通过切入点表达式找到对应连接点
  • AspectJ

    java社区最完整最流行的AOP框架,我们都是使用这个框架来使用AOP的,早期spring原生的AOP我们不用,后来spring2.0以后的版本,spring用AspectJ框架整合了自己原生的AOP模块,所有我们现在用到的springAOP实际是spring整合AspectJ框架的产物
  • 需要的jar包(spring基础的4个包别忘记导)

    前面介绍过,spring使用第三方AspectJ框架整合实现AOP,所有我们需要导入的包除了spring的还有AspectJ的
    • spring的切面jar包,aop包一定要有,否则无法使用注解在这里插入图片描述在这里插入图片描述
    • Aspectj的jar包,官网下载即可,https://www.eclipse.org/aspectj/
      在这里插入图片描述
    • Aop切面注解包,https://sourceforge.net/projects/aopalliance/files/aopalliance/在这里插入图片描述
    • cglib包用来实现cglib动态代理:https://github.com/cglib/cglib在这里插入图片描述
  • 基于注解的AOP

    • 开启需要的命名空间在这里插入图片描述
    • 配置xml文件在这里插入图片描述
    • 使用注解创建切面类在这里插入图片描述
    • 编写前置通知并将被代理对象注入容器
      当我们通知方法的切入点表达式正确,那么此方法就可以找到指定连接点,并将方法切入进去,方法前面会有一个箭头类型图标提示,切入成功。在这里插入图片描述
      在这里插入图片描述
    • 测试在这里插入图片描述
    • 定义公有的切入点表达式,以及表达式通配符,测试出错通知和后置通知在这里插入图片描述在这里插入图片描述
    • 切入点表达式的逻辑运算,通知方法获取方法信息,返回通知和获取返回值,异常通知和获取异常信息。在这里插入图片描述在这里插入图片描述
    • 环绕通知
      如果想要指定通知方法的执行顺序可以使用@Order(index)来指定切面的切入顺序,就是当我们有两个切面类时,为这些类指定此注解,index值越小优先级越高在这里插入图片描述
  • 基于xml配置

在这里插入图片描述在这里插入图片描述

3、声明式事务

  • 什么是事务

    • 事务就是为了保证数据的完整性和一致性的一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行,要么不执行
  • 事务的关键4个属性

    • 原子性:原子本意为不可再分,事务中多个操作在逻辑上缺一不可,原子性要求要么都执行,要么都不执行
    • 一致性:指数据一致,一致性要求,事务无论执行多少操作,必须全程保证数据正确一致,若某个操作出错,必须立即回到执行事务之前的数据状态,也就是回滚
    • 隔离性:要求多个事务并发执行时,不会互相干扰,保证不同事务之间的隔离性,
    • 持久性:要求事务执行完毕后,对数据的修改永久保留到持久化存储器中
  • 事务隔离级别

事务隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED
READ COMMITTED ×
REPEATABLE READ(MySQL默认) × ×
SERIALIZABLE × × ×
  • @Transactional注解属性

    • isolation:指定事务的隔离级别
      • 示例:@Transactional(isolation=Isolation.REPEATABLE_READ)
    • propagation:指定事务传播行为(就是决定当一个事务调用另一个事务时,被调事务是和调用者共用一个事务,还是自己开启一个新事务)
      属性 解释
      ropagation=Propagation.REQUIRED 若其它事务调用本事务,则在相同事务运行,子事务出错则全部回滚,若没有其他事务调用,就自己启动一个新事务
      ropagation=Propagation.REQUIRES_NEW 无论是否被调用都自己重新启动一个事务,当整个事务流程中出现错误时,若自己还未执行事务,就会影响自己运行结果,相对自己出错,也会影响后续事务,但若自己以经执行完毕,将不受影响
    • rollbackFor:指定异常回滚(异常分运行时异常(默认回滚),编译时异常(默认不回滚)此属性指定当发生某个默认不回滚异常时,指定的异常也必须回滚)
      • 示例@Transactional(rollbackFor={Exception.class,IOException.class})遇到指定异常回滚
    • noRollbackFor:指定异常不回滚,和rollbackFor正好相反
    • readOnly:设置事务为只读事务,不进行修改数据操作,专心与读取数据操作,会提升读取效率
    • timeout:事务超时终止,单位秒,timeout=3表示事务执行超过3秒就终止并回滚
  • 基于注解的声明式事务

    在这里插入图片描述
    在这里插入图片描述
    在事务方法上写注解即可在这里插入图片描述
    在这里插入图片描述
  • 基于XML的声明式事务

    替换xml文件配置,并将@Transactional的配置全部移入xml在这里插入图片描述
发布了23 篇原创文章 · 获赞 0 · 访问量 601

猜你喜欢

转载自blog.csdn.net/grd_java/article/details/104740069