IOC&DI&AOP含义、区别及应用

IOC控制反转

  • 生活的例子:我想做一件事,但是我不想自己做,所以委托给第三方。家里清洁卫生,委托家政公司,家政公司派清洁阿姨,我只是暂时把清理卫生权利给阿姨,但是我还拥有对我家的所有控制器,阿姨只是暂时打扫,打扫完把干净的家给我。
  • 控制反转:控制的什么被反转了?就是获得依赖对象的方式反转了。(由主动new–>被动注入)
  • IOC概念:创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IOC容器,它是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象。有了 IOC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IOC容器了,通过IOC容器来建立它们之间的关系。
  • IOC意义:在传统应用程序中,我们要实现某一个至少需要两个或以上的对象来协作完成的功能时,这个合作对象是由自己主动通过new创建出来的,这样就会使得对象间的耦合度高了;而使用了Spring之后,有了IOC容器,把创建和查找依赖对象的控制权交给了IOC容器,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到IOC容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用(至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题)

IOC与DI依赖注入的区别

  • 控制反转IOC是概念/思想,依赖注入是具体实现。

  • 具体可参考:https://blog.csdn.net/fuzhongmin05/article/details/55802816

AOP面向切面是什么

  • 将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性
  • 将一个类切开,在合适的地方插入一些功能,使得类的功能更丰富/完善

AOP核心概念

1、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象(通知和切入点的组合)

/**
 * @author xiongyongshun
 * @version 1.0
 * @created 16/9/9 13:13
 */
@Component
@Aspect
public class BeforeAspectTest {
    // 定义一个 Pointcut, 使用 切点表达式函数 来描述对哪些 Join point 使用 advise.
    @Pointcut("execution(* com.xys.service.UserService.*(..))")
    public void dataAccessOperation() {
    }
}

切面由切入点和通知构成,只要某个连接点满足切入点的规则,该规则下的通知就会被织入到该连接点,而通知有5种类型,不同类型表示它织入到连接点的不同位置。

2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。

3、连接点(joinpoint被拦截到的点):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。

4、切入点(pointcut配置拦截规则 ):对连接点进行拦截的定义

5、通知(advice被拦截到的连接点要执行的代码):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为

  • 前置:在连接点前被执行的 advice. 虽然 before advice 是在 连接点前被执行, 但是它并不能够阻止 连接点 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行连接点中的代码)
  • 后置:在一个连接点正常返回后执行的 advice
  • 异常:当一个连接点抛出异常后执行的 advice
  • 最终:无论一个 连接点是正常退出还是发生了异常, 都会被执行的 advice.(类似finally)
  • 环绕通知:在 连接点前和 连接点退出后都执行的 advice. 这个是最常用的 advice.

6、目标对象:代理的目标对象
织入 advice 后的目标对象——不是原来的类, 而是织入 advice 后所产生的代理类.。
Spring AOP 使用运行时代理(动态代理织入)的方式来实现 aspect, 因此目标对象总是一个代理对象

7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
将 aspect 和其他对象连接起来, 并创建 目标对象的过程.
根据不同的实现技术, AOP织入有三种方式:

  • 编译器织入, 这要求有特殊的Java编译器.
  • 类装载期织入, 这需要有特殊的类装载器.
  • 动态代理织入, 在运行期为目标类添加增强(Advice)生成子类的方式.

Spring 采用动态代理织入, 而AspectJ采用编译器织入和类装载期织入.

8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。

总结:连接点(被拦截的点)只要满足了切入点(拦截规则),那么由 aspect 织入通知(一段代码)到该连接点——Advice 是和特定的切入点关联的, 并且在切入点相匹配的连接点中执行.

切入点和连接点区别

在 Spring AOP 中, 所有的方法执行都是连接点. 而切入点是一个描述信息, 它修饰的是连接点, 通过 切入点, 我们就可以确定哪些 连接点可以被织入 Advice. 因此连接点和切入点本质上就是两个不同纬度上的东西.
即advice 是在连接点上执行的, 而切入点 规定了哪些 连接点可以执行哪些 advice

AOP proxy

  • 一个类被 AOP 织入 advice, 就会产生一个结果类, 它是融合了原类和增强逻辑的代理类.
  • 在 Spring AOP 中, 一个 AOP 代理是一个 JDK 动态代理对象(默认)或 CGLIB 代理对象
  • 如果需要为一个类实现代理, 那么可以使用 CGLIB 代理。当一个业务逻辑对象没有实现接口时, 那么Spring AOP 就默认使用 CGLIB 来作为 AOP 代理了. 即如果我们需要为一个方法织入 advice, 但是这个方法不是一个接口所提供的方法, 则此时 Spring AOP 会使用 CGLIB 来实现动态代理. 鉴于此, Spring AOP 建议基于接口编程, 对接口进行 AOP 而不是类.
    (接口提供的方法–JDK动态代理,非接口(类)提供的方法用CGLIB动态代理)

AOP应用例子

生活例子
  • 假设一下, 从前有一个叫爪哇的小县城, 在一个月黑风高的晚上, 这个县城中发生了命案. 作案的凶手十分狡猾,现场没有留下什么有价值的线索. 不过万幸的是, 刚从隔壁回来的老王恰好在这时候无意中发现了凶手行凶的过程, 但是由于天色已晚, 加上凶手蒙着面, 老王并没有看清凶手的面目, 只知道凶手是个男性, 身高约七尺五寸. 爪哇县的县令根据老王的描述, 对守门的士兵下命令说:凡是发现有身高七尺五寸的男性, 都要抓过来审问. 士兵当然不敢违背县令的命令,只好把进出城的所有符合条件的人都抓了起来.来让我们看一下上面的一个小故事和 AOP 到底有什么对应关系.
  • 首先我们知道, 在 Spring AOP 中 join point 连接点指代的是所有方法的执行点, 而 point cut切入点 是一个描述信息,它修饰的是 join point, 通过 point cut, 我们就可以确定哪些 join point 可以被织入 Advice.对应到我们在上面举的例子, 我们可以做一个简单的类比。
    join point连接点 就相当于 爪哇的小县城里的百姓(所有可能被拦截的点)
    point cut切入点就相当于 老王所做的指控, 即凶手是个男性, 身高约七尺五寸(拦截规则)
    advice 则是施加在符合老王所描述的嫌疑人的动作: 抓过来审问(对被拦截的点要做什么处理).

为什么可以这样类比呢?

  • join point --> 爪哇的小县城里的百姓: 因为根据定义, join point 是所有可能被织入 advice 的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是 join point. 而在我们上面的例子中, 命案发生在小县城中, 按理说在此县城中的所有人都有可能是嫌疑人.
  • point cut --> 男性, 身高约七尺五寸: 我们知道, 所有的方法(joint point) 都可以织入 advice, 但是我们并不希望在所有方法上都织入 advice, 而 pointcut 的作用就是提供一组规则来匹配joinpoint, 给满足规则的 joinpoint 添加 advice. 同理, 对于县令来说, 他再昏庸, 也知道不能把县城中的所有百姓都抓起来审问, 而是根据凶手是个男性, 身高约七尺五寸, 把符合条件的人抓起来. 在这里 凶手是个男性, 身高约七尺五寸 就是一个修饰谓语, 它限定了凶手的范围, 满足此修饰规则的百姓都是嫌疑人, 都需要抓起来审问.
  • advice --> 抓过来审问, advice 是一个动作, 即一段 Java 代码, 这段 Java 代码是作用于 point cut 所限定的那些 join point 上的. 同理, 对比到我们的例子中, 抓过来审问 这个动作就是对作用于那些满足 男性, 身高约七尺五寸 的爪哇的小县城里的百姓.
  • aspect: aspect 是 point cut(拦截规则) 与 advice(处理) 的组合, 因此在这里我们就可以类比: “根据老王的线索, 凡是发现有身高七尺五寸的男性, 都要抓过来审问” 这一整个动作可以被认为是一个 aspect.

那么整个 aspect 就可以描述为: 满足 pointcut 规则的 joinpoint 会被添加相应的 advice 操作.

应用例子

我们可以为每个使用 RequestMapping 标注的方法织入advice,RequestMapping(“url”)是请求的路径映射地址,当 HTTP请求到来,就会先进入advice,里面写的代码相等于拦截器,拦截后,进行分析这个http请求是否有相应的权限, 如果有, 则执行Controller, 如果没有, 则抛出异常

代码实例

(1)基于xml配置方式
在这里插入图片描述
由上图可知beforeAdvice前置通知与afterAdvice后置通知这两个通知的切入点都是任何包任何类任何方法

在这里插入图片描述
因此上面这两个方法(连接点)是会被拦截的,
在这里插入图片描述

  • 前置:在连接点前被执行的 advice. 虽然 before advice 是在 连接点前被执行, 但是它并不能够阻止 连接点 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行连接点中的代码)
  • 后置:在一个连接点正常返回后执行的 advice

对于每个通知(5种类型,不同类型织入连接点的不同位置)都会关联一个切入点,如果连接点满足这些切入点的规则,就会将通知织入到连接点的不同位置(可以同时满足多个切入点,即同时织入多个通知)。

由于前置通知与后置通知关联的切入点都是"execution(* (…))",因此对于insertUser()同时匹配两个切入点,则织入两个通知,将他们放在不同位置。因此 上面测试中执行连接点,即insertUser()之前会执行前置通知,输出"beforeAdvice",接着执行连接点输出“插入用户成功”,然后会执行后置通知"afterAdvice"。

同理,在执行updateUser() 之前会先执行前置通知,输出"beforeAdvice",接着执行连接点输出“更新用户成功”,然后会执行后置通知"afterAdvice"。
在这里插入图片描述
(2)基于注解配置方式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可见环绕型通知是比前置通知和后置通知先执行的

截图来源:https://blog.csdn.net/weixin_43611145/article/details/89084019

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值