Spring IOC与AOP

目录

1 IOC

2 AOP

2.1 什么是AOP

2.2 代理模式

2.3 AOP日志中方法互相调用日志答应问题

2.4 AOP事务


1 IOC

  • IOC是什么

    IOC就是控制反转,这是一种设计思想,简而言之就是将我们程序中手动创建的对象交由我们的外部框架来完成,在Spring中这个就是交由Spring的IOC容器来完成,这个IOC容器实际上就是一个map,里面保存了我们的对象

  • IOC有什么作用?

    IOC有以下作用:

    • 使得对象之间的耦合度降低

    • 使得我们的资源变得容易管理,因为我们将对象的生成与管理权利交给了我们的IOC容器

    举个例子来说明以下IOC的强大之处:

    就比如我们在开发的过程一个service可能要依赖许许多多的mapper和其他service来实现相应的功能,在没有IOC的情况下,我们要手动在service中new一个对应的mapper或service对象,这就需要我们对于这些对象的构造器要十分清除,并且倘若现在要加入新的业务逻辑,也就是说有些mapper或者service的代码发生变化,那么我们就需要一一去对这些对象创建时的代码进行修改,而这是我们不愿意看到的,同时也违背了开放封闭的设计原则。而通过IOC容器,我们只需要去修改配置文件或者配置类就能够实现新的service或mapper的注入,而不用再去修改依赖这些类的源代码,从而实现了松耦合。

  • DI?

    IOC是一种设计思想,DI依赖注入是对这种设计思想的一种实现,我们的Spring就是通过DI来实现IOC容器的。依赖注入的方式有两种,分别是构造器注入与set方法注入

2 AOP

2.1 什么是AOP

  • 什么是AOP

    AOP也就是面向切面编程,是对OOP思想的一种延伸。要说明AOP和OOP的区别 ,我们来讲一个例子吧。

    现在有三个人,分别是老师teacher,student和worker,这三个人都有一个共同的run()方法,姑且称这个方法是跑步吧。然后根据OOP的编程思想,我们就可以抽象出来一个Person类或者接口,然后里面有一个run()方法,然后我们编teacher,student,worker三个类去继承并实现person中的run方法即可。这样的OOP编程确实帮我们解决了代码复用的问题,但是还存在一个问题没有解决。就是三个不同的实现类中的run()方法中可能有大量重复的代码,这会使得我们的代码看起来很臃肿。比如,我们的三个person实现类,要调用run()方法跑步了,三个人在跑步前需要做一些准备运动,这些准备运动都是一样的,然后就是跑步(也就是我们代码中的实际业务逻辑),这部分三个人是不一样的,比如速度之类的,然后仨人跑完了都要坐着休息,喝水干啥的,这部分代码又是同样的。可以看到三个来的run()方法中也有很多重复的逻辑。这是传统的OOP编程解决不了的。这时也就有了AOP编程。所谓的面向切面编程,我们可以在三个人的run方法中只实现真正的跑步逻辑,但是准备和结束时的相同动作可以将其通过动态代理的方式插入到run()方法的前后就行了。

  • AOP的概念 

  • 底层实现

    动态代理+反射API

2.2 代理模式

代理模式共有三种,分别是静态代理,动态代理和cglib代理。比如说现在我们有一个接口a,一个接口A的实现类,然后一个代理类B,我们用户访问A中的方法时通过B可以对方法做一些扩展。

静态代理

静态代理就是我们的接口B也实现接口a,然后同时实现a中方法,并在B中注入A,并在相应的方法中调用A中的方法,这样在B的相应方法中能够在A的方法调用的前后加入一些其他逻辑。这就是静态代理,静态代理的缺点是我们的代理类也需要实现接口a中的全部方法,耦合度较高。

动态代理

动态代理就是我们的代理类B不再去实现接口a,而是通过JDK提供的api动态生成代理对象,这样我们就可以只对我们想代理的接口a中的方法进行代理了

//调用下面方法就能获得我们的代理对象
代理对象的接口 代理 = Proxy.newProxyInstance(需要代理的对象的类加载器,代理对象实现的接口,invocationHandler);
//InvocationHandler是一个接口,实现这个接口的invoke方法可以加入我们代理对象时的扩展功能

cglib代理

动态代理要求我们的代理类A要实现某一个接口,但如果我们要代理的A并没有实现相应的接口,则需要通过cglib进行代理,即通过构造一个子类对象来实现对A的代理,这种方法的缺点就是不能代理final类,且代理的方法不能是static的。该代理模式是在通过在字节码层面生成一个代理对象的子类来实现的

需要导入Cglib的包,同时需要实现MethodInterceptor接口中的intercept()方法,这个方法中写代理对象的方法

2.3 AOP日志中方法互相调用日志答应问题

问题:使用AOP实现了一个调用,如果方法A引用了方法B,那么调用方法A时方法B的日志会打印吗?

首先说答案吧,方法B并不会打印,场景:需要代理的类的A方法调用了该类中的B方法

AOP是基于动态代理来实现的,是通过java.lang.Proxy类的newProxy()方法来帮助我们生成一个代理类,这个类和我们的代理对象一样,都实现了对应的接口,然后在相应方法中调用了代理对象的方法,并在该方法前后加入了我们的日志逻辑。之后若我们调用代理类的A方法,会先打印日志,然后进入到我们代理对象的A方法,执行时会调用B方法,这个B方法时this的B方法,也就是代理对象的B方法,而代理对象的B方法是没有加入日志相关逻辑的,所以也就不会打印相应的日志,若必须要打印相关的日志,我们在原来代理对象中调用B方法时,应该去调用代理对象的B方法,这样才会执行我们的日志逻辑

2.4 AOP事务

当我们使用原生的JDBC来实现事务,我们需要手动写开启事务,事务提交和事务回滚的代码,这些事务相关的代码和业务代码耦合在了一起,并且当我们使用的数据库访问技术发生变化的时候,事务相关的代码也要发生变化,显然这样做代码的耦合度较高。

Spring AOP事务就解决了上述的问题,我们通过aop直接将事务相关的代码封装到切面中,这样我们编写程序的时候只需要编写业务代码即可,将事务的开启,回滚,提交的管理交给spring来帮助我们进行。

spring事务在使用的时候只需要在相应的方法上加上一个@Transactional()注解即可,在这个注解中我们可以需要声明事务的隔离级别,事务的传播特性等信息,这里说一下事务的传播特性:

  • 支持当前事务

    • REQUIRED 如果当前存在事务则加入当前事务,如果不存在事务则创建新事务(默认的传播行为)

    • SUPPORTS 如果当前存在事务则加入当前事务,如果不存在则以非事务的方式运行

    • MANDATORY 如何当前存在事务则加入当前事务,如果不存在则抛出异常

  • 不支持当前事务

    • REQUIRES_NEW 创建一个新事务,若当前存在事务则将其挂起

    • NOT_SUPPORTED 以非事务的方式运行,若当前存在事务则将其挂起

    • NEVER 以非事务的方式运行,若当前存在事务则抛出异常

  • 其他

    • NESTED 若当前存在事务则创建一个事务作为当前事务的嵌套事务运行,若不存在当前事务,则该取值等价于REQUIRED

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值