关于Spring中IoC的一些理解

本文详细探讨了Spring框架中的IoC(控制反转)概念,解释了为何使用Spring,其核心技术如IOC和AOP,以及Spring的优点。文章进一步阐述了IoC的实现方式,包括构造器注入、setter注入和字段注入,强调了构造器注入的推荐性。同时,讨论了Spring中Bean的作用域、生命周期和容器的延迟加载与预加载机制。最后提到了BeanFactory与ApplicationContext的区别,以及PostProcessor在Spring中的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring

为什么用spring

解决企业开发的难度,减轻对项目模块之间的管理,类和类之间的管理,帮助开发人员创建对象,管理对象之间的关系。

spring核心技术

IOC,AOP主要目的是为了实现模块之间的解耦合。

spring的优点

  • 轻量
  • 针对接口编程,解耦合
  • AOP编程支持
  • 方便集成各种优秀的框架

spring体系结构

Spring体系结构图

什么是IoC

IoC(Inversion of Control):控制反转,意思是将对象创建,赋值,管理的工作都交给代码之外的容器进行实现,也就是对象的创建是由其他外部资源完成的

控制:创建对象,对象属性的赋值,对象之间的关系管理
反转:把原来的开发任意创建对象的权限,转移给代码之外的容器进行实现。由容器代替开发人员管理对象,创建对象,给对象赋值。
正转:由开发人员使用new构造方法创建对象,开发人员主动管理对象。

IoC的技术实现

Spring容器帮我们管理着一系列的类,我们只需要在使用时向Spring去索取对应的类。

IoC是通过DI(Dependency Injection): 依赖注入来实现的

Spring是使用DI(Dependency Injection)来实现IoC的功能

  • 主要方式:1.set方式注入 2.构造器注入 3.字段注入
  • 注入类型:1.值类型注入 2.引用类型注入

在使用字段注入时,弹出警告Field injection is not recommended

这是因为Spring官方和IDEA都并不推荐使用字段注入。因为字段注入存在一些缺陷

对象的外部可见性

在一个类中通过字段注入其中的私有变量,那这个私有变量仅仅能在该类中被使用,脱离了容器环境无法访问该实例。
字段注入类和容器的耦合度过高,我们无法脱离容器来使用目标对象。

可能导致潜在的循环依赖

循环依赖是指两个类之间互相进行注入
在这里插入图片描述

在这里插入图片描述

不允许声明不可变域

即字段注入对于final修饰不起作用,因为这些字段必须在类实例化时实例化。声明不可变域唯一的方法是构造器注入

构造器注入是spring官方推荐的依赖注入类型,它有哪些特性

spring官方原文对构造器注入的描述

The Spring team generally advocates constructor injection as it enables one to implement application components as `immutable objects` and to ensure that required dependencies are not null.
Furthermore constructor-injected components are always returned to client(calling) code in a fully initialized state.

核心意思为,构造器注入能保证注入组件不可变,并且确保需要的依赖不为空。即解决字段注入外部不可见性的问题。
另外,使用构造器注入能在运行前报错,从而提醒避免循环依赖。

Setter方法注入

虽然构造器注入能解决字段注入的问题但是,当构造器参数过多时,会使得代码显得冗长,降低可读性和可维护性。这时可以引入set方法注入。
Setter方法注入更加灵活,能够实现按需注入。

Spring中Bean作用域(scope属性)

Spring中Bean的作用域主要有五种作用域

单例作用域Singleton不管Bean的引用有多少个,都只创建一个Bean实例。对于无状态的Bean应该使用单例
原型作用域Prototype每次请求Bean时,Spring IoC都会创建一个心得Bean实例。对于有状态的Bean应该使用原型
Request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。
session同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。
application限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。

request,session和application这三个作用域都是基于web的Spring WebApplicationContext实现的,只有在web环境下(比如XmlWebApplicationContext)中才能使用。
如果开发者仅仅在常规的Spring IoC容器中比如ClassPathXmlApplicationContext在中使用这些作用域,那么将会抛出一个IllegalStateException来说明使用了未知的作用域。

Spring生命周期

Bean生命周期描述的是Spring中一个Bean创建过程和销毁过程中所经历的步骤,其中Bean创建过程是重点。

主要分为:1. 获得BeanDefinition信息 2.实例化Bean对象,3. 注入属性,4. 初始化Bean,5. 使用后Bean,6. 销毁Bean

1.获得BeanDefinition信息

Spring容器启动时会去调用ConfigurationClassPostProcessor这个Bean工厂的后置处理器完成扫描,将扫描到的信息保存到一个实例化的BeanDefinition对象中(每一个符合规范的类,都会被实例化一个BeanDefinition对象,Spring会根据命名规则生成一个对应的名字)。然后,Spring将生成的BeanDefinition对象和它对应的名字保存到一个BeanDefinitionMap当中。

当Spring把类对应的BeanDefinition对象存到map之后,Spring会继续调用程序员提供的Bean后置工厂处理器。(即实现了BeanFactoryPostProcessor的程序,实际上ConfigurationClassPostProcessor也实现了BeanFactoryPostProcessor)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HGLQFV09-1631452706166)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210911155711896.png)]

值得注意的是再BeanDefinition信息加载的过程中,是先调用BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,再调用BeanFactoryPostProcessor的postProcessBeanFactory。
所以如果程序想在第四步前运行自己的代码,需要实现BeanDifinitionRegistryPostProcessor.(据说mybatis的最新源码是扩展了BeanDIfinitionRegistryPostProcessor类,之后有时间去看看)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kcCkgY9W-1631452706169)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210911153810518.png)]

我们可以理解bean工厂的后置处理器(这里只讨论直接实现BeanFactoryPostProcessor的后置处理器,不包括实现BeanDefinitionRegistryPostProcessor的后置处理器)其实是spring提供的一个扩展点(spring提供很多扩展点,学习spring源码的一个非常重要的原因就是要学会这些扩展点,以便对spring做二次开发或者写出优雅的插件),可以让程序员干预bean工厂的初始化过程(重点会考);这句话最重要的几个字是初始化过程,注意不是实例化过程 ;初始化和实例化有很大的区别的,特别是在读spring源码的时候一定要注意这两个名词;翻开spring源码你会发现整个容器初始化过程就是spring各种后置处理器调用过程;而各种后置处理器当中大体分为两种;一种关于实例化的后置处理器一种是关于初始化的后置处理器,这里不是笔者臆想出来的,如果读者熟悉spring的后置处理器体系就可以从spring的后置处理器命名看出来spring对初始化和实例化是有非常大的区分的。
————————————————
版权声明:本文为优快云博主「shadow?s」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/java_lyvee/article/details/102633067

Bean的实例化过程

实例化阶段主要通过反射对Bean进行实例化,这个阶段Spring也暴露了一些可扩展点:

  1. Aware接口,如:BeanFactoryAware,MassageSourceAware,ApplicationContextAware

    对于实现了这些的Bean,在实例化Bean时Spring会帮我们注入到对应的BeanFactory,MassageSource,ApplicationContext实例

  2. BeanPostProcessor接口

    实现了BeanPostProcessor接口的Bean,会在实例化Bean时Spring帮我们调用接口中的方法

Spring IoC容器的延迟加载Lazy Loading和预加载Preloading机制

延迟加载在请求时动态加载Bean。

预加载在使用Bean之前加载Bean,Spring IoC默认使用预加载。

BeanFactory与ApplicationContext

spring源码对BeanFactory的描述

The root interface for accessing a Spring bean container.

BeanFactory是SpringBean容器的根接口,提供了最简单的容器的功能,使用时才创建Bean,提供了如下接口,功能和名称相符:

Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);

ApplicationContext是由BeanFactory派生而来,并且扩展了很多高级特性,每次容器启动时就会创建所有的对象。

ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,初始化应用上下文时就实例化所有单实例的Bean ,ApplicationContext包还提供了以下的功能:

  • MessageSource, 提供国际化的消息访问
  • 资源访问,如URL和文件
  • 事件传播
  • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层;

PostProcessor

后置处理器,是Spring主要是为了我们提供了扩展点,例如BeanFactoryPostProcessor这可以留给了我们空间在Bean实例化时候去干预这个过程。对于用Spring做二次开发和写插件是很有用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值