当前位置: 首页 > news >正文

Spring学习-Ioc

一、IOC核心理论

1.Ioc理念概要

对象A如何调用对象B

类别 描述 时间点 案例
外部传入 构造方法传入 创建引用对象时 private A(B b)
外部传入 属性设置传入 设置对象状态时 A a = new A(); a.setB(b)
外部传入 运行时作为参数传入 调用时 A类中,function(B b) {}
内部创建 属性中直接创建 创建引用对应 private A()
内部创建 初始化方法创建 创建引用对应 private B b = new B();
内部创建 运行时动态创建 调用 A类中,function()

实际项目依赖关系很复杂,如果通过上述方法注入对象会很麻烦。

2.实体Bean的创建

2.1.基于Class构建

<bean class="com.test.spring.User"></bean>

在spring底层会基于class属性,通过反射进行构建。

2.2.构造方法构建

<bean class="com.test.spring.User"><constructor-arg name="name" type="java.lang.String" value ="yixiao"/><constructor-arg index="1"  value ="2"/>
</bean>

基于构造方法构建,其对应的属性如下:

  • name: 构造方法参数名称
  • type: 参数类型
  • index: 参数索引,从0开始
  • value: 参数值,spring 会自动转换成参数实际类型值
  • ref:引用容串的其它对象

2.3.静态工厂方法创建

public class User {public static User build() {return new User();}
}
<bean class="com.test.spring.User" factory-method="build">
</bean>
public static void main(String[] args) {context  = new ClassPathXmlApplicationContext("spring.xml");context.getBean(User.class);
}

2.4.FactoryBean创建

<bean id="driver" class="com.test.spring.DrivaerFactoryBean"><property name="jdbcUrl" value="jdbc:mysql://localhost:3306"></property>
</bean>
public class DriverFactoryBean implements FactoryBean {private String jdbcUrl;public String getJdbcUrl() {return jdbcUrl;}public void setJdbcUrl(String jdbcUrl) {this.jdbcUrl = jdbcUrl;}@Overridepublic Object getObject() throws Exception {return DriverManager.getDriver(jdbcUrl);}@Overridepublic Class<?> getObjectType() {return java.sql.Driver.class;}@Overridepublic boolean isSingleton() {return true;}
}
public static void main(String[] args) {ClassPathXmlApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");context.getBean("driver");
}

context.getBean("driver"); 获取到的bean是 com.mysql.jdbc.Driver,而不是DriverFactoryBean

自定义的创建我们的Bean

3.Bean的基本特性

3.1.作用范围

​ 无状态的对象可以设置单例模式(scope="singleton"),有状态对象必须设置多例模式(scope="prototype")

<bean class="com.test.spring.User" scope="prototype">
</bean>

如果一个Bean设置成protype 我们可以通过BeanFactoryAware 获取 BeanFactory 对象即可每次获取的都是新对象。

3.2.生命周期

​ Bean对象的创建、初始化、销毁即时Bean的生命周期,通过init-method、destory-method属性可以分别指定构建方法和初始方法

<bean class="com.test.spring.User" init-method="init" destory-method="destory">
</bean>

​ 另外可以通过让Bean去实现InitializingBean.afterPropertiesSet()、DisposableBean.destroy()方法。分别指定自定义构建方法和初始方法

3.3.加载机制

单个Bean配置 Lazy-init

true: 为懒加载;

false: 非懒加载,容器启动时即创建对象

default: 默认,采用default-lazy-init 中的指定值,default-lazy-init 未指定就是false

使用懒加载容器启动快,但不能及时发现项目中的问题。

4.依赖注入

4.1.set方法注入

<bean class="com.test.spring.User"><property name="account" ref="UserAccount"></property>
</bean>

4.2.构造方法注入

<bean class="com.test.spring.User"><constructor-arg name="account"><bean class="com.test.spring.UserAccount"></constructor-arg>
</bean>

4.3.自动注入(byName、byType)

<bean class="com.test.spring.User" autowaire="byName">
</bean>
  • byName : 会根据 UserAccount 属性(bean id/ bean name ),去Bean容器中查找Bean然后注入到User这个Bean当中。根据 属性名 与 Spring 容器中 bean 的 id/name 是否一致查找。
  • byType : 会根据 com.test.spring.UserAccount 属性,去Bean容器中查找Bean然后注入到User这个Bean当中。根据 属性类型 与 Spring 容器中 bean 的 Class 类型 是否一致

4.4.方法注入(lookup-method)

单例Bean依赖了多例Bean,不推荐使用lookup-method方式。

建议实现BeanFactoryAware接口完成单例Bean依赖了多例Bean。

public class UserAccount {}public class User implements BeanFactoryAware {private BeanFactory beanFactory;public void printUserAccount() {beanFactory.getBean(UserAccount.class);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}
}

二、IOC 设计原理与实现

1.Bean的构建过程

1.1BeanDefinition

xml中的bean属性都会在BeanDefinition中体现

xml-bean BeanDefinition
class beanClassName
scope scope
lazy-init lazy-init
constructor-arg constructorArgument
property MutablePropertyValues
factory-method factoryMethodName
destory-method AbstractBeanDefinition.destoryMethodName
init-method AbstractBeanDefinition.initMethodName
autowire AbstractBeanDefinition.autowireMode
id
name

1.2.BeanDefinitionRegistry

xml bean 中的id的作用 是id 作为 key,将当前 Bean 注册到BeanDefinitionRegistry 注册器中。

xml bean 中的 name 作为别名 key ,将当前 Bean 注册到 aliasRegistry 注册器中。

最后通过id或者name都可以获取 BeanDefinition

1.3.BeanDefinitionReader

image-20260518161500890

public static void main(String[] args) {// 创建资源读取器DefaultResourceLoader loader = new DefaultResourceLoader();// 获取资源Resource resource = loader.getResource("spring.xml");// 创建一个简单注册器SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();// 创建一个bean定义读取器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);// 装载Bean的定义reader.loadBeanDefinitions(resource);// 打印构建的Bean 名称String[] beanDefinitionNames = registry.getBeanDefinitionNames();for (String beanDefinitionName : beanDefinitionNames) {System.out.println(beanDefinitionName);}// 获取Bean的别名String[] users = registry.getAliases("user");// 根据BeanName 获取BeanDefinitionBeanDefinition user = registry.getBeanDefinition("user");}

1.4.BeanFactory(Bean工厂)

有了BeanDefinition(Bean的定义),可以通过BeanFactory 创建Bean

  • getBean(String): 基于id或name 获取一个Bean
  • Object getBean(String name, Object ... args): 基于名称获取一个Bean,并覆盖默认的构造参数

当用户调用getBean的时候就会触发 Bean的创建动作

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)>org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean>org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String) 从缓存中获取单例Bean,如果存在就返回Bean,如果不存在就返回null缓存中存在单例Bean>org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance  查看是否是FactoryBean,如果是FactoryBean的话,需要通过FactoryBean 的getObject方法获取实际的Bean,因为FactoryBean是创建了一个自定义的Bean缓存中不存在单例Bean,从ParentBeanFactory查看是否存在Bean>org.springframework.beans.factory.support.AbstractBeanFactory#getParentBeanFactoryParentBeanFactory不存在要查找的Bean,就创建Bean。根据Scope创建单例的Bean,还是多例的Bean>org.springframework.beans.factory.support.AbstractBeanFactory#createBean>org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>) 如果Bean存在就返回Bean,如果Bean不存在就创建Bean>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])  创建Bean

Snipaste_2026-05-18_18-12-50

2.BeanFactory 与 ApplicationContext 区别

2.1. 核心区别速览表

特性 BeanFactory ApplicationContext
加载方式 懒加载(每次获取Bean时才创建) 预加载(启动时创建单例Bean)
国际化支持 有(MessageSource)
事件发布/监听 有(ApplicationEventPublisher)
AOP支持 需手动配置 自动支持(如@Transactional
资源访问 较少 丰富(ResourceLoader)
Web应用集成 需额外配置 内置WebApplicationContext
注册方式 手动注册 自动扫描、注解、Java Config

2.2. 最关键的实战区别

① 加载时机不同

BeanFactory:懒加载

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
// 此时Bean没有被创建
MyBean bean = factory.getBean(MyBean.class); // 这一刻才创建Bean

ApplicationContext:预加载

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// 所有单例Bean在此行代码执行时就已经创建完成
MyBean bean = ctx.getBean(MyBean.class); // 直接返回已有实例

影响ApplicationContext启动慢但首次请求快,BeanFactory启动快但首次请求可能慢。

② 功能丰富度

ApplicationContext 开箱即用支持:

  • 国际化ctx.getMessage("user.name", null, Locale.CHINA)
  • 事件ctx.publishEvent(new MyEvent(this)) + @EventListener
  • AOP:自动代理 @Aspect@Transactional
  • 资源加载ctx.getResource("classpath:config.xml")

BeanFactory 均不支持,需要手动添加额外组件。

2.3. 继承关系与本质

BeanFactory (根接口,定义IoC容器基本能力)↑
ApplicationContext (继承BeanFactory,并扩展多个接口)

ApplicationContext 继承的接口包括:

  • MessageSource → 国际化
  • ApplicationEventPublisher → 事件机制
  • ResourcePatternResolver → 资源加载
  • EnvironmentCapable → 环境配置

99%的实际项目用 ApplicationContext,尤其Spring Boot默认就是它。

http://www.jsqmd.com/news/839863/

相关文章:

  • 从零到一:IPMI远程管理实战指南与典型问题排查
  • 基于Python的企业微信AI机器人SDK开发实战:从原理到部署
  • 从Log看懂nRF Connect:一次完整的BLE属性读取与参数请求调试分析
  • 首驱电动车售后体验如何?保修、网点、报修流程完整解析 - 资讯速览
  • AI应用安全网关:基于MCP协议构建智能体工具调用的安全防线
  • 基于ESP32-S3与CircuitPython的智能邮箱监控器:从传感器到云端通知的完整物联网实践
  • 在多模型聚合平台观测API调用延迟与用量数据的体验
  • SillyTavern完整指南:打造智能对话AI前端的终极解决方案
  • 构建LLM知识库:从文档处理到RAG检索的完整实践指南
  • TVA系统赋能轴承制造智能检测
  • 终极B站会员购抢票神器:5分钟掌握自动化抢票完整攻略
  • 利用Taotoken多模型能力为智能客服场景选型
  • SystemVerilog仿真入门:用Questasim跑通HelloWorld后,我建议你立刻试试这3个调试技巧
  • 从模型保密到快速仿真:深入聊聊AVL Cruise与Simulink的MATLAB DLL联合仿真到底怎么用
  • 英文AI率92%降至7%!实测3款降ai工具+3个技巧助你顺利通关 - 殷念写论文
  • 避坑指南:PCIe Configuration状态下的Lane Number分配,为什么你的设备协商会失败?
  • 从零到一:Metasploitable2靶机实战渗透全流程解析
  • YimMenu:GTA5玩家的终极安全防护与游戏增强指南
  • 半导体市场二季度环比下滑5%:库存调整与结构性分化下的产业链应对
  • 2026最新降AI攻略:实测10款免费降ai率工具(附工具优缺点总结) - 殷念写论文
  • GitHub民间优质代码清单:发现、评估与高效使用指南
  • PyTorch张量拼接与升维实战:torch.cat与unsqueeze的核心技巧解析
  • TS3440,TS8220,TS6150,TS538,g3800,g4800,ib4180,ts8180报错5B00,P07,E08,5b02,1704,1700,5b04佳能V6.200,亲测有用。
  • 告别公网IP和路由器设置:用cpolar套件10分钟搞定群晖NAS外网访问
  • 终极指南:5分钟免费搞定Windows和Office永久激活的专业方案
  • TS8220,TS3440,ix6580,ix6780,ix6880,ix6700,ix6800,G5080,TS8380,IP2780报错5B00,P07,E08,1700,5b04废墨垫清零,好用
  • 为内部知识库问答系统选择并接入 Taotoken 上合适的大模型
  • 基于QT Py RP2040的USB MIDI主机互连方案:打破音乐设备通信壁垒
  • 龙芯2K3000在轨道交通AFC系统的国产化迁移实战
  • 【靶场部署】保姆级指南——DVWA靶场本地化部署与实战环境配置