网站首页 > 技术文章 正文
目录
- Spring IoC 概述
- IoC:Inverse of Control(控制反转)
- 一个例子
- Spring IoC 的好处
- IoC实例
- Spring IoC 容器的设计
- 设计
- BeanFactory
- ApplicationContext
- ApplicationContext 常见实现类:
- Bean的定义与初始化
- 依赖注入(DI)
- 什么是依赖
- 什么是依赖注入
- IoC和DI的关系
- 如何自己实现一个的IoC容器
- SpringBoot中IoC的使用案例
- 总结
Spring IoC 概述
IoC:Inverse of Control(控制反转)
控制反转不是一种技术,而是一种思想。
既然说是反转就说先明白什么是正,什么是反
- 正控:就是我们平时最常见的那种使用形式,要使用某个对象,需要自己去负责对象的创建,属于自力更生。
- 反控:若要使用某个对象,无需自己创建,只需要从IoC容器中去获取,创建对象的过程交给Spring来处理,Spring来维护这个IoC容器,属于富二代,需要啥找管家。
所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,通过描述反转给容器来帮忙实现。
在 Java 中可以是 XML 或者注解,通过Spring去产生或获取特定对象
Spring 会提供 IoC 容器来管理和容纳我们所开发的各种各样的 Bean,并且我们可以从中获取各种发布在 Spring IoC 容器里的 Bean,并且通过描述可以得到它。
一个例子
比如我想要一个机器人,我有两种方法:
- 造出来
- 买过来
正控的方式其实就是需要机器人的时候自己造,显然它不如买的方便,开销也不见得比买的小,造出来的未必比买的好。
IoC其实就相当于是买,这个过程中我们没有去创造机器人,但是最终也得到了机器人,而且大概率要比我们自己造的好。
最终的结果都是得到机器人,关键的区别就在于,机器人是谁创造的。如果我们还需要其他的东西例如、汽车、电视等等,自己就造就显得很蠢,找人买显然更聪明。
Spring IoC 的好处
当上面的例子作用于庞杂的软件工程中的时候,自己造的方式显然是难以维护的。
好处显而易见:
- 降低对象之间的耦合
- 不需要理解一个类的具体实现,直接向 IoC 容器拿
IoC实例
ClassPathXmlApplicationContext是ApplicationContext的子类,ApplicationContext下面有所介绍
我们先来看一个最简单例子
- 创建一个实体类
public class Source {
private String taste;
private String sugar;
private String size;
/**setter and getter **/
}
- 先在src目录下创建一个 bean.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 通过 xml 方式装配 bean -->
<bean name="source" class="pojo.Source">
<property name="taste" value="苹果味"/>
<property name="sugar" value="糖"/>
<property name="size" value="中杯"/>
</bean>
</beans>
- 上面定义了一个 bean ,这样 Spring IoC 容器在初始化的时候就能找到它们,然后使用 ClassPathXmlApplicationContext 容器就可以将其初始化:
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Source source = (Source) context.getBean("source", Source.class);
System.out.println(source.getTaste());
System.out.println(source.getSugar());
System.out.println(source.getSize());
这样就会使用 Application 的实现类 ClassPathXmlApplicationContext 去初始化 Spring IoC 容器,然后开发者就可以通过 IoC 容器来获取资源了。
bean的装配还可以通过注解的方式,SpringBoot中常用注解来装配,文末有案例
Spring IoC 容器的设计
设计
Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务。
Spring提供了多个IoC容器可供使用。
Spring IoC 容器的设计主要是基于以下两个接口:
- BeanFactory(Spring IoC 容器所定义的最底层接口)
- ApplicationContext
ApplicationContext 是 BeanFactory 的子接口之一,并对 BeanFactory 功能做了许多的扩展大多数时候,都是使用它来作为IoC容器
BeanFactory
- 是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。
- 在应用中,一般不使用 BeanFactory,而推荐使用ApplicationContext(应用上下文)。
从上图可以看到, BeanFactory 位于设计的最底层,它提供了 Spring IoC 最底层的设计,下面简单说下它所定义的方法
- getBean() 对应了多个方法来获取配置给 Spring IoC 容器的 Bean。按照类型拿 bean(有多个type Spring 就懵了,不知道该获取哪一个)按照 bean 的名字拿 bean按照名字和类型拿 bean(推荐)
单例就是无论获取多少次,都是同一个对象。原型就是每次获取都是一个新创建的对象。一般默认是单例的
- isSingleton() 用于判断是否单例
- isPrototype() 用于判断是否为原型
- isTypeMatch() 是否匹配类型
- getType() 获取bean的类型
- getAliases()方法是获取别名的方法
- containsBean() 是否包含bean
所有关于 Spring IoC 的容器将会遵守BeanFactory所定义的方法。
ApplicationContext
根据 ApplicationContext 的类继承关系图,可以看到 ApplicationContext 接口扩展了许许多多的接口,因此它的功能十分强大。
- 继承了 BeanFactory,拥有了基本的 IoC 功能;
- 支持国际化;
- 支持消息机制;
- 支持统一的资源加载;
- 支持AOP功能;
ApplicationContext 常见实现类:
1.ClassPathXmlApplicationContext
读取classpath中的资源
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
2:FileSystemXmlApplicationContext
读取指定路径的资源
ApplicationContext ac = new FileSystemXmlApplicationContext("/projact/applicationContext.xml");
3.XmlWebApplicationContext
需要在Web的环境下才可以运行
XmlWebApplicationContext ac = new XmlWebApplicationContext(); // 这时并没有初始化容器
ac.setServletContext(servletContext); // 需要指定ServletContext对象
ac.setConfigLocation("/WEB-INF/applicationContext.xml"); // 指定配置文件路径,开头的斜线表示Web应用的根目录
ac.refresh(); // 初始化容器
Bean的定义与初始化
Bean 的定义和初始化是两个步骤
定义:
- Resource 定位
Spring IoC 容器先根据开发者的配置,进行资源的定位,通过 XML 或者注解,定位的内容是由开发者提供的。 - BeanDefinition 的载入
这个时候只是将 Resource 定位到的信息,保存到 Bean 定义(BeanDefinition)中,此时并不会创建 Bean 的实例 - BeanDefinition 地注册这个过程就是将 BeanDefinition 的信息发布到 Spring IoC 容器中,此时仍然没有对应的 Bean 的实例。
做完了以上 3 步,Bean 就在 Spring IoC 容器中被定义了,但是没有被初始化、没有完成依赖注入,它还不能使用。
初始化和依赖注入:
Bean 有一个配置选项——lazy-init,作用在于是否懒加载。
懒加载的意思就是,如果不获取它,就不创建实例,当获取它时才创建实例。通俗理解就是,不到饭点不起床。
在没有任何配置的情况下,它的默认值为 false,也就是 默认会自动初始化 Bean。
如果将其设置为 true,那么只有当我们使用 Spring IoC 容器的 getBean() 方法获取它时,它才会进行 Bean 的初始化,完成依赖注入。
依赖注入(DI)
依赖注入就是将实例变量传入到一个对象中去(Dependency injection means giving an object its instance variables)。
什么是依赖
例如
public class Human {
...
Father father;
...
public Human() {
father = new Father();
}
}
上面这段代码中,Human就是依赖于Father,如果Father出错,Human类就无法正常运行。
什么是依赖注入
上面将依赖在构造函数中直接初始化是一种硬编码,弊端在于两个类不够独立。
public class Human {
...
Father father;
...
public Human(Father father) {
this.father = father;
}
}
我们将 father 对象作为构造函数的一个参数传入,再调用 Human 的构造方法之前外部就已经初始化好了 Father 对象。
这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。
这种方式的好处显而易见,那就是降低了耦合。
IoC和DI的关系
有些人会把控制反转和依赖注入等同,但实际上它们有着本质上的不同。
- 控制反转是一种思想
- 依赖注入是一种设计模式
IoC框架使用依赖注入作为实现控制反转的方式,Spring中的IoC就是使用DI的方式来实现的
但控制反转不止这一种实现方式,只是这种应用的更为广泛。
如何自己实现一个的IoC容器
简单聊一下,大概就分成三步:
- 读取注解或者配置文件,查看依赖,拿到类名
- 使用反射,基于类名实例化对应的对象实例
- 将对象实例,通过构造函数或者 setter,传递出去
Spring的IoC大致就是这样一个路数,这其中还有更多的细节,但大致的思路就是如此。
SpringBoot中IoC的使用案例
在Spring Boot当中我们主要是通过注解来装配Bean到Spring IoC容器中。
- 首先定义一个Java简单对象
public class User {
private Long id;
private String userName;
private String note;
/**setter and getter **/
}
- 再定义一个Java配置文件
- @Configuration代表这是一个Java配置文件,Spring的容器会根据它来生成IoC容器去装配Bean;
- @Bean代表将initUser()方法返回的POJO装配到IoC容器中,而其属性name定义这个Bean的名称,如果没有配置它,则将方法名称“initUser”作为Bean的名称保存到Spring IoC容器中。
@Configuration
public class AppConfig {
@Bean(name = "user")
public User initUser() {
User user = new User();
user.setId(1L);
user.setUserName("user_name_1");
user.setNote("note_1");
return user;
}
}
- 调用测试
public class IoCTest {
private static Logger log = Logger.getLogger(IoCTest.class);
public static void main(String[] args) {
ApplicationContext ctx
= new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class);
log.info(user.getId());
}
}
......
17:53:03.018 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'user'
17:53:03.018 [main] INFO com.springboot.chapter3.config.IoCTest - 1
显然,配置在配置文件中的名称为user的Bean已经被装配到IoC容器中,并且可以通过getBean()方法获取对应的Bean,并将Bean的属性信息输出出来。
当然这只是很简单的方法,而注解@Bean也不是唯一创建Bean的方法,还有其他的方法可以让IoC容器装配Bean
总结
IoC不是什么技术,而是一种设计思想。在 Spring 开发中,由 IOC 容器控制对象的创建、初始化、销毁等。这也就实现了对象控制权的反转,由我们对对象的控制转变成了Spring IOC 对对象的控制。
猜你喜欢
- 2024-10-15 BATJ面试必会之 Spring 篇(30题) 面试spring的面试题
- 2024-10-15 Spring知识点提炼 spring题
- 2024-10-15 springmvc的核心是啥,请求的流程怎么处理,控制反转怎么实现
- 2024-10-15 spring源码分析——spring大纲 spring源码分析和总结简书
- 2024-10-15 Spring思维导图,让Spring不再难懂(ioc篇)
- 2024-10-15 Spring框架介绍及使用 spring框架的使用步骤
- 2024-10-15 架构师必知必会:Java内置的控制反转机制-Service Provider
- 2024-10-15 什么是控制反转(ioc),通过解释总结告诉你
- 2024-10-15 搞透IOC,Spring IOC看这篇就够了
- 2024-10-15 Spring IOC,看完这篇文章,我才算是懂了
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)