spring中IOC相关介绍

引言

1. 春之始:Spring框架的诞生与成长

在软件开发的广阔天地中,Spring框架以其优雅和强大的功能,成为了Java开发领域的一股春风。自2003年首次发布以来,Spring框架不断演进,逐渐成为企业级应用开发的首选。Spring的核心哲学是简化企业级应用的复杂性,通过提供一套丰富的基础设施支持,让开发者能够专注于业务逻辑的实现。

2. 何为IoC:控制反转的哲学

在传统的程序设计中,对象的创建和依赖关系管理是由开发者手动控制的。这种方式虽然直观,但随着应用规模的增长,会导致代码的耦合度增加,难以维护和扩展。控制反转(IoC)是一种设计原则,它将对象的创建和依赖关系管理的控制权从应用代码转移到外部容器,从而实现解耦和模块化。

3. Spring与IoC:一场美丽的邂逅

Spring框架将IoC概念发挥到了极致,通过其IoC容器,Spring能够自动管理对象的生命周期和依赖关系。这种自动化的依赖注入机制,不仅简化了代码,还提高了代码的可测试性和可维护性。Spring IoC容器是整个框架的心脏,它负责维护对象的创建、配置、组装和销毁。

4. 为什么IoC如此重要

在现代软件开发中,IoC的重要性不言而喻。它不仅是一种编程模式,更是一种思维模式,引导开发者从更高的层次设计和思考软件架构。IoC使得应用组件更加独立和可重用,为构建模块化、可扩展和易于维护的系统提供了坚实的基础。

第2部分:IoC的基本概念

1. 定义IoC:控制反转的内涵

控制反转(Inversion of Control, IoC)是一种软件设计原则,其核心思想是将传统编程中的控制流程反转。在传统的编程模式中,组件之间的依赖关系由组件自身在运行时决定。而在IoC中,这种控制权被反转,由外部容器在运行前配置和决定。简单来说,IoC就是一种让对象的创建和依赖关系由外部控制的机制。

2. IoC的实现方式

IoC通常通过以下几种方式实现:

  • 依赖注入(Dependency Injection, DI):容器在创建对象时,将依赖的对象注入到对象中。
  • 服务定位器模式(Service Locator pattern):通过一个全局访问点来请求需要的对象。
  • 回调机制:对象在需要时,通过回调函数来获取依赖。
3. IoC的优势
  • 降低耦合度:组件之间的依赖通过接口或抽象类定义,实现了解耦。
  • 提高模块化:组件更加独立,便于重用和测试。
  • 增强灵活性:依赖关系可以在不修改代码的情况下通过配置改变。
4. IoC在Spring中的实现:依赖注入

Spring框架通过依赖注入(DI)来实现IoC。DI有两种主要的注入方式:

  • 构造器注入:依赖通过构造器传递给对象。
  • Setter注入:依赖通过Setter方法传递给对象。
5. 示例:构造器注入
@Component
public class MyService {private Dependency dependency;@Autowiredpublic MyService(Dependency dependency) {this.dependency = dependency;}
}

在这个示例中,MyService的实例在创建时,Spring容器会自动注入一个Dependency的实例。

6. 示例:Setter注入
@Component
public class MyService {private Dependency dependency;@Autowiredpublic void setDependency(Dependency dependency) {this.dependency = dependency;}
}

在这个例子中,MyService通过Setter方法接收依赖注入。

7. 依赖注入的高级特性
  • 自动装配(Autowiring):Spring可以根据类型自动装配依赖。
  • 条件装配:依赖的注入可以根据条件进行,例如@Profile@Conditional
8. 示例:自动装配
@Component
public class MyService {private Dependency dependency;@Autowiredpublic MyService() {// 依赖自动注入}
}

在这个例子中,Spring容器会查找与构造器参数类型匹配的Bean,并自动注入。

9. 依赖注入的局限性
  • 过度依赖:如果不正确使用,可能会导致过度依赖容器。
  • 性能问题:在某些情况下,依赖注入可能会引入性能开销。

第3部分:Spring IoC容器

1. 容器的基本概念

Spring IoC容器是一个运行时环境,负责管理Spring应用中的所有对象。容器使用配置元数据来创建对象,管理对象之间的依赖关系,并配置对象。

2. 容器的启动过程
  • 加载配置:容器从XML文件、注解或Java配置类中加载配置信息。
  • 注册Bean定义:解析配置信息,并将Bean的定义注册到容器中。
  • 创建Bean:根据注册的Bean定义,容器创建并初始化Bean。
3. 容器的两种实现
  • BeanFactory:Spring IoC容器的基本接口,延迟依赖注入,直到请求Bean时才进行。
  • ApplicationContext:扩展了BeanFactory,提供了更多的高级特性,如事件发布、国际化消息支持等。
4. 示例:使用XML配置Bean
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="myService" class="com.example.MyService"><property name="dependency" ref="dependencyBean"/></bean><bean id="dependencyBean" class="com.example.Dependency"/>
</beans>

在这个XML配置示例中,定义了两个Bean,myService依赖于dependencyBean

5. 示例:使用注解配置Bean
@Configuration
public class AppConfig {@Beanpublic MyService myService() {return new MyService(dependency());}@Beanpublic Dependency dependency() {return new Dependency();}
}

在这个Java配置示例中,使用@Configuration@Bean注解来定义Bean。

6. 容器的Bean作用域
  • singleton:默认作用域,对于定义的每个Bean,容器只创建一个实例。
  • prototype:每次请求都会创建一个新的Bean实例。
  • request:每个HTTP请求都会创建一个新的Bean,仅适用于Web应用程序。
  • session:在一个HTTP Session中,一个Bean定义对应一个实例。
7. 示例:定义prototype作用域的Bean
@Bean
public MyService myServicePrototype() {return new MyService();
}

在这个示例中,每次请求myServicePrototype都会创建一个新的MyService实例。

8. Bean的生命周期
  • 初始化:Bean创建后,容器会调用初始化方法(如@PostConstruct注解的方法)。
  • 使用:Bean被注入到其他Bean或被应用程序使用。
  • 销毁:容器关闭前,会调用销毁方法(如@PreDestroy注解的方法)。
9. 示例:使用初始化和销毁回调
@Component
public class MyService {@PostConstructpublic void init() {// 初始化代码}@PreDestroypublic void cleanup() {// 清理代码}
}

在这个示例中,MyService定义了初始化和销毁的回调方法。

10. 容器的自动装配

Spring容器可以自动装配Bean的依赖,而不需要显式指定依赖Bean的名称或类型。

11. 示例:自动装配
@Component
public class MyService {private Dependency dependency;@Autowiredpublic MyService() {// 依赖自动注入}
}

在这个示例中,MyService的构造器使用了@Autowired注解,Spring容器会自动装配Dependency类型的Bean。

12. 容器的高级特性
  • Bean的后处理:通过实现BeanPostProcessor接口,可以在Bean初始化前后执行自定义逻辑。
  • 事件驱动:Spring支持事件发布和监听机制,允许Bean之间进行松耦合的通信。

第4部分:依赖注入(DI)

1. 依赖注入的定义

依赖注入是一种实现控制反转(IoC)的模式,它允许开发者将组件的依赖关系从组件本身转移到外部容器。Spring框架通过依赖注入来管理组件的生命周期和依赖关系,从而提高代码的可维护性和可测试性。

2. 依赖注入的两种主要类型
  • 构造器注入:依赖通过构造函数参数传递。
  • Setter注入:依赖通过Setter方法传递。
3. 构造器注入的优点
  • 不可变性:对象一旦构造,其依赖关系就固定不变。
  • 线程安全:由于依赖关系在构造时就确定,避免了多线程环境下的并发问题。
4. 示例:构造器注入
public class MyService {private final Dependency dependency;@Autowiredpublic MyService(Dependency dependency) {this.dependency = dependency;}// MyService的其他方法
}

在这个示例中,MyService通过构造器接收其依赖Dependency,并且由于使用了final关键字,确保了依赖的不可变性。

5. Setter注入的优点
  • 灵活性:可以在运行时改变依赖关系。
  • 可选性:某些依赖可以设置为可选,不是必须的。
6. 示例:Setter注入
public class MyService {private Dependency dependency;@Autowiredpublic void setDependency(Dependency dependency) {this.dependency = dependency;}// MyService的其他方法
}

在这个示例中,MyService通过Setter方法接收其依赖Dependency,允许在运行时注入或更改依赖。

7. 依赖注入的自动装配

Spring框架提供了自动装配功能,可以自动匹配并注入依赖,而不需要显式指定依赖的来源。

8. 示例:自动装配byType
@Component
public class MyService {private Dependency dependency;@Autowiredpublic MyService() {// 依赖自动注入,根据类型匹配}
}

在这个示例中,Spring容器会查找与MyService构造器参数Dependency类型匹配的Bean,并自动注入。

9. 示例:自动装配byName
@Component("myService")
public class MyService {private Dependency dependency;@Autowiredpublic void setDependency(Dependency dependency) {this.dependency = dependency;}
}

在这个示例中,如果存在一个名为myService的Bean定义,Spring容器将自动将Dependency类型的Bean注入到myServicesetDependency方法中。

10. 依赖注入的条件装配

Spring允许根据条件来装配Bean,例如,只有在特定的配置文件激活时才注入某个依赖。

11. 示例:条件装配
@Configuration
public class AppConfig {@Bean@Profile("dev")public Dependency devDependency() {return new DevDependency();}@Bean@Profile("prod")public Dependency prodDependency() {return new ProdDependency();}
}

在这个示例中,根据激活的配置文件(devprod),Spring容器将注入相应的Dependency实现。

12. 依赖注入的局限性
  • 过度依赖框架:过度使用依赖注入可能导致代码与框架紧密耦合,降低可移植性。
  • 难以跟踪的依赖关系:在大型项目中,自动装配的依赖关系可能难以追踪和理解。

第5部分:Spring Bean的生命周期

1. Spring Bean生命周期概述

Spring Bean的生命周期是指从创建到销毁的整个过程。Spring提供了丰富的接口和注解,允许开发者介入Bean的创建、初始化、使用和销毁过程。

2. Bean的创建
  • 实例化:Spring容器根据Bean的定义创建Bean实例。
  • 属性填充:将配置的属性值注入到Bean的字段中。
3. 示例:自定义Bean的创建
@Bean
public MyBean createMyBean() {return new MyBean();
}

在这个示例中,通过@Bean注解定义了一个自定义的Bean创建方法。

4. Bean的初始化
  • 初始化方法:使用@PostConstruct注解的方法,在Bean的所有属性设置之后执行。
  • 初始化回调:实现InitializingBean接口的afterPropertiesSet方法。
5. 示例:使用@PostConstruct注解
@Component
public class MyComponent {private final Dependency dependency;@Autowiredpublic MyComponent(Dependency dependency) {this.dependency = dependency;}@PostConstructpublic void init() {// 进行初始化操作}
}

在这个示例中,MyComponent在依赖注入完成后,会调用init方法进行初始化。

6. Bean的使用
  • 依赖注入:Bean被注入到其他Bean中,成为它们的依赖。
  • 应用逻辑:Bean被应用程序使用,执行其业务逻辑。
7. Bean的销毁
  • 销毁方法:使用@PreDestroy注解的方法,在Bean销毁前执行。
  • 销毁回调:实现DisposableBean接口的destroy方法。
8. 示例:使用@PreDestroy注解
@Component
public class MyComponent {@PreDestroypublic void cleanup() {// 进行清理操作}
}

在这个示例中,MyComponent在销毁前会调用cleanup方法进行资源释放。

9. Bean的作用域
  • singleton:默认作用域,对于定义的每个Bean,容器只创建一个实例。
  • prototype:每次请求都会创建一个新的Bean实例。
  • request:每个HTTP请求都会创建一个新的Bean,仅适用于Web应用程序。
  • session:在一个HTTP Session中,一个Bean定义对应一个实例。
10. 示例:定义request作用域的Bean
@Bean
public MyBean myBean(@RequestScope Scope scope) {scope.register(MyBean.class);return new MyBean();
}

在这个示例中,MyBean的实例会在每个HTTP请求中创建。

11. Bean的后处理
  • BeanPostProcessor:在Bean的初始化前后执行自定义逻辑。
  • 示例:自定义BeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 在Bean初始化前执行操作return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 在Bean初始化后执行操作return bean;}
}

在这个示例中,实现了BeanPostProcessor接口,可以在Bean初始化前后进行自定义处理。

12. 事件驱动
  • ApplicationEvent:定义自定义事件。
  • ApplicationListener:监听并响应事件。
13. 示例:使用事件驱动
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent event) {// 处理事件}
}

在这个示例中,MyEventListener监听并响应自定义的MyEvent事件。

第6部分:Bean的作用域和作用域代理

1. 作用域的概念

在Spring框架中,Bean的作用域定义了Bean的生命周期和它在Spring容器中的可见性。不同的应用场景可能需要不同的Bean作用域。

2. 常见的Bean作用域
  • singleton:在Spring IoC容器中,对于定义为singleton的Bean,只创建一个实例。
  • prototype:每次请求都会创建一个新的Bean实例。
  • request:每个HTTP请求都会创建一个新的Bean,仅适用于Web应用程序。
  • session:在一个HTTP Session中,一个Bean定义对应一个实例。
  • application:在一个Web应用的生命周期内,只创建一个Bean实例。
  • websocket:在WebSocket生命周期内,每个WebSocket都会创建一个Bean实例。
3. 示例:定义prototype作用域的Bean
@Bean
@Scope("prototype")
public MyBean prototypeBean() {return new MyBean();
}

在这个示例中,每次请求prototypeBean都会创建一个新的MyBean实例。

4. 请求作用域的Bean

请求作用域的Bean与HTTP请求相关联,每个请求都会创建一个新的Bean实例。

5. 示例:定义request作用域的Bean
@Bean
@Scope("request")
public MyRequestBean myRequestBean() {return new MyRequestBean();
}

在这个示例中,每个HTTP请求都会创建一个新的MyRequestBean实例。

6. 会话作用域的Bean

会话作用域的Bean与HTTP会话相关联,在整个会话期间只创建一个实例。

7. 示例:定义session作用域的Bean
@Bean
@Scope("session")
public MySessionBean mySessionBean() {return new MySessionBean();
}

在这个示例中,每个HTTP会话都会创建一个新的MySessionBean实例。

8. 应用作用域的Bean

应用作用域的Bean与整个Web应用程序相关联,在整个应用程序的生命周期内只创建一个实例。

9. 示例:定义application作用域的Bean
@Bean
@Scope("application")
public MyApplicationBean myApplicationBean() {return new MyApplicationBean();
}

在这个示例中,整个Web应用程序只创建一个MyApplicationBean实例。

10. 作用域代理

Spring提供了作用域代理功能,允许在保持相同接口的情况下,为Bean创建一个代理,以处理不同作用域的Bean的特殊行为。

11. 示例:使用作用域代理
@Bean
@Scope("prototype")
@ScopeProxyMode(ScopedProxyMode.TARGET_CLASS)
public MyPrototypeBean myPrototypeBean() {return new MyPrototypeBean();
}

在这个示例中,MyPrototypeBean被定义为prototype作用域,并使用目标类代理模式。

12. 作用域代理的模式
  • ScopedProxyMode.INTERFACES:为Bean的接口创建代理。
  • ScopedProxyMode.TARGET_CLASS:为目标类创建代理。
13. 示例:使用ScopedProxyMode.INTERFACES
@Bean
@Scope("request")
@ScopeProxyMode(ScopedProxyMode.INTERFACES)
public MyRequestBean myRequestBean() {return new MyRequestBean();
}

在这个示例中,如果MyRequestBean实现了某个接口,Spring将为这个接口创建一个代理。

14. 作用域的局限性
  • prototype作用域:由于每次请求都会创建新实例,可能会增加内存消耗和创建成本。
  • request和session作用域:仅适用于Web应用程序,限制了Bean的使用场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/40068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

unity对于文件夹的操作

1、获取目标文件夹内所有文件夹 string[] directories Directory.GetDirectories(Path);for (int i 0; i < directories.Length; i){print(directories[i]);}2、获取目标文件夹内指定文件 public List<string> GetAllTxt(string path){//只获取文件名string[] files…

linux命令行操作

一、看二进制文件 od -t x1 1.txt | less 二、看信号 kill -l man 7 signal 三、查看当前进程的pid号 echo $$

Python绘制动态股价曲线图并保存视频

用akshare库获取英伟达(股票代码&#xff1a;105.NVDA) 在2014年6月19日到2024年6月19日期间的股票的收盘价数据&#xff08;用后复权的收盘价&#xff09;&#xff1b; 基于后复权的收盘价数据&#xff0c;做一个动态股价曲线图&#xff0c;逐日显示英伟达股价的动态变化情况&…

PHP反序列化字符逃逸详解

这段时间遇到几个关于反序列化的字符逃逸的程序&#xff0c;今天来分享一下经验。 <?php function filter($str){ return str_replace(bb, ccc, $str); } class A{ public $nameaaaa; public $pass123456; } $AAnew A(); $resfilter(serialize($AA)); $cunserialize($res)…

【每日一练】python字符串

接受用户输入的字符串&#xff0c;然后反转字符串并输出。 str input("Enter a string: ") print(str[::-1])接受用户输入的字符串和一个字符&#xff0c;然后统计该字符在字符串中出现的次数。 str input("Enter a string: ") character input("…

Vue报错:Component name “xxx” should always be multi-word vue/multi-word-component

问题&#xff1a;搭建脚手架时报错&#xff0c;具体错误如下&#xff1a; ERROR in [eslint] E:\personalProject\VueProjects\vueproject2\src\components\Student.vue10:14 error Component name "Student" should always be multi-word vue/multi-word-compon…

【办公类-52-01】20240703计划小结的缩略版制作(获取字符最多的3个字,删除字后面的内容)

背景需求&#xff1a; 每学期写完“信息计划”“信息小结”都需要上传园所“圆圆通”的信息公开&#xff0c;领导要求使用缩略版&#xff08;就是删掉一些内容&#xff0c;不能整篇都发布出去&#xff0c;以免被抄袭&#xff1f;&#xff09; 2023年第二学期的信息小结有16页 …

CX1概念车空气动力学设计,打造典型“美式肌肉车”风格

Altair CX1概念车的设计 CX1是Altair公司为了满足汽车行业的设计和虚拟仿真需求而开发的一款概念车型。该车总长接近5米&#xff0c;外观具有典型的美式肌肉车的风格&#xff0c;具有视觉冲击力。 车辆的外形设计过程就是风险管理&#xff0c;设计师想要一个大胆而富有表现力的…

西门子IPC477C工控机6AV7884-2AA10-2BA0

西门子IPC477C工控机6AV7884-2AA10-2BA0 西门子IPC477C工控机6AV7884-2AA10-2BA0 工控机&#xff08;Industrial Personal Computer—IPC&#xff09;是一种加固的增强型个人计算机&#xff0c;它可以作为一个工业控制器在工业环境中可靠运行。西门子工业业务领域是工业生…

赢麻了!苹果再获OpenAI董事会观察员席位!0元白嫖ChatGPT,比肩微软

今年&#xff0c;苹果和OpenAI的合作有点密切。 据最新消息&#xff0c;苹果获得OpenAI的董事会观察员席位。 苹果应用商店负责人、前营销主管菲尔席勒&#xff08;Phil Schiller&#xff09;将担任这一职位&#xff0c;但Schiller迄今为止尚未出席任何OpenAI的会议。 观察员…

C语言刷题小记

前言 本篇博客和大家分享一些C语言的OJ题目&#xff0c;希望大家可以通过这些题目进一步提升自己的编程能力&#xff0c;如果你对本篇内容感兴趣&#xff0c;可以一键三连&#xff0c;多多关注&#xff0c;下面进入正文部分。 题目1 十六进制转十进制 描述 BoBo写了一个十六…

firewalld(6)自定义services、ipset

简介 在前面的文章中我们已经介绍了zone、rich rule 、--direct等功能和基本配置。在前面文章中&#xff0c;我们提到过firewalld内置了很多服务&#xff0c;可以通过firewall-cmd --get-services来查看服务&#xff0c;也可以通过配置文件查看这些服务/var/lib/firewalld/ser…

【Unity 角色控制器组件】

【Unity 角色控制器组件】 Character Controller&#xff1a; Unity 内置的一个组件&#xff0c;用于提供高级的物理控制&#xff0c;允许开发者控制角色的移动、跳跃和碰撞。 csharp csharp // 假设你已经有了一个带有Character Controller组件的游戏对象// 获取Character Co…

In Ictu Oculi: Exposing AI Created Fake Videos by Detecting Eye Blinking

文章目录 In Ictu Oculi: Exposing AI Created Fake Videos by Detecting Eye Blinking背景关键点内容预处理Long-Term Recurrent CNNsLSTM-RNN模型训练实验data启示In Ictu Oculi: Exposing AI Created Fake Videos by Detecting Eye Blinking 会议:2018 IEEE International…

容嬷嬷给紫薇过生日:鬼畜搭台,AI带货

刚入7月&#xff0c;短视频平台已被AI视频续写占领。 类似于紫薇在地牢里被容嬷嬷喂西瓜、喂鸡翅、喂蛋糕。张学友在《旺角卡门》的经典镜头突然给你微笑、嘟嘴、甚至祝你生日快乐。甚至&#xff0c;还有吴京从打斗戏变成亲吻戏。 在AI续写的短视频里&#xff0c;你永远也想象…

【最新综述】医学图像分割深度半监督学习(上)

摘要&#xff1a; 最近&#xff0c;深度学习在各种计算机视觉任务中展现出了巨大的前景。然而&#xff0c;在许多实际应用中&#xff0c;没有大规模的标记数据集&#xff0c;这限制了深度学习的应用。为了解决这个问题&#xff0c;半监督学习引起了计算机视觉界的广泛关注&…

二叉树的前中后序遍历(递归法、迭代法)leetcode144、94/145

leetcode144、二叉树的前序遍历 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[] 示例 3&#xff1a; 输…

Torch中`Transformer`的中文注释

解析torch官方代码脚本文件&#xff1a;transformer.py。版本&#xff1a;1.9.1cu111。 首先查看《Torch中多头注意力MultiheadAttention的中文注释》解析&#xff1b; 最后查看下方transformer解析。 话不多说&#xff0c;看代码吧&#xff01; import copy from typing imp…

CesiumJS【Basic】- #057 绘制纹理填充多边形(Primitive方式)

文章目录 绘制纹理填充多边形(Primitive方式)1 目标2 代码2.1 main.ts绘制纹理填充多边形(Primitive方式) 1 目标 使用Primitive方式绘制绘制纹理填充多边形 2 代码 2.1 main.ts import * as Cesium from cesium;const viewer = new Cesium.Viewer

测试Andrew NG的语言翻译Agent

我正在测试 Andrew Ng 的语言翻译 A​​I 代理系统及其在逆变换下的稳定性。 给定源语言的文本&#xff0c;我们应用翻译函数 f&#xff0c;然后应用 f 的逆。它应该是不变的&#xff1a; 但是&#xff0c;数学与语言翻译有什么关系&#xff1f; 在完美的系统中&#xff0c;从…