也来聊聊Spring中的IOC和AOP

举报
ChillRay 发表于 2020/11/30 21:47:20 2020/11/30
【摘要】 作为一名Java开发的程序猿,Spring可以说是每天都要打交道的东西,从最一开始基于xml配置文件的Spring再到Spring Boot或是Spring Cloud,可以明显感觉到的就是业务的搭建变得日益简单,配置由复杂变得越来越轻量,甚至只需要在网页上点一点就能初始化一个可以运行的Spring项目。网上讨论Spring核心概念IOC和AOP的文章也有很多,今天我也想来聊聊在我看来Spr...

作为一名Java开发的程序猿,Spring可以说是每天都要打交道的东西,从最一开始基于xml配置文件的Spring再到Spring Boot或是Spring Cloud,可以明显感觉到的就是业务的搭建变得日益简单,配置由复杂变得越来越轻量,甚至只需要在网页上点一点就能初始化一个可以运行的Spring项目。网上讨论Spring核心概念IOC和AOP的文章也有很多,今天我也想来聊聊在我看来Spring IOC和AOP的一些特点和使用时需要注意的地方。

IOC

IOC是构成Spring常用模块中最核心的模块BeanFactory使用到的最重要的技术,通过控制反转,应用程序的配置和依赖规范可以很好的与应用程序代码分离开。我们不再需要从一个类引用另一个类时显式地初始化对方,而是可以单纯的通过某个配置文件就能描述组成Spring应用的各个类之间的依赖关系。通过Java语言的反射功能就可以实例化各个Bean并建立他们之间的依赖关系。IOC除了这些功能以外,还提供了Bean实例缓存、生命周期管理、Bean实例代理发布、事件发布、资源装载等等高级功能。

说起IOC,最重要的就是BeanFactory,这是面向Spring框架基础本身的一个类,而我们的开发者更多的使用ApplicationContext。

Bean的类型有两种,一种是单例Singleton,一种是prototype,分别会在使用的过程中共享同一个Bean或者每次分别创建不同的Bean。在Web场景下Bean还有request、session和global session三种额外的作用域。

Spring Bean的生命周期大概是:

  • 实例化
  • IOC依赖注入
  • setBeanName
  • BeanFactoryAware
  • ApplicationContextAware
  • postProcessBeforeInitialization
  • init-method
  • postProcessAfterInitialization
  • Destory过期自动清理
  • Destory-method

依赖注入的四种方式:

  1. 构造器注入
  2. setter注入
  3. 静态工厂注入
  4. 实例工厂注入

AOP

核心概念:

切面:对横切关注点的抽象

横切关注点:对哪些方法进行拦截,拦截后进行什么样的处理

连接点:被拦截到的点

切入点:对拦截点进行拦截的定义

增强:进行拦截之后要进行的处理,分别有-前置,后置,异常,返回值,环绕

目标对象:要进行代理的目标

织入:将切面应用于目标对象并创建代理对象的过程

引入:不改变代码的前提下运行期修改类,动态添加方法或者字段

两种代理方式:

JDK动态接口代理:

要求横切逻辑必须是接口定义的,通过反射调用目标类的代码,动态的将横切逻辑和业务逻辑进行编织

CGLib动态代理:

高性能的代码生成类库,不受被代理对象是否实现了接口的限制,可以默认关闭JDK动态代理而完全使用CBLib动态代理

循环依赖问题

  • Spring 为了解决单例的循环依赖问题,使用了 三级缓存 ,递归调用时发现 Bean 还在创建中即为循环依赖
  • 单例模式的 Bean 保存在如下的数据结构中:
/** 一级缓存:用于存放完全初始化好的 bean **/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** 三级级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/**
bean 的获取过程:先从一级获取,失败再从二级、三级里面获取

创建中状态:是指对象已经 new 出来了但是所有的属性均为 null 等待被 init
*/

检测循环依赖的过程如下:

  • A 创建过程中需要 B,于是 A 将自己放到三级缓里面 ,去实例化 B

  • B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了!

    • 然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A
    • B 顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
  • 然后回来接着创建 A,此时 B 已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面

  • 如此一来便解决了循环依赖的问题

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。