本篇内容核心:
1、Spring 是什么,如何理解Spring
2、IoC和DI是什么,有什么区别?
3、Spring最核心的功能是什么?
Spring Framework(Spring 框架)通常指的是 Spring,Spring是一个开源框架,有着活跃庞大的社区,Spring支持广泛的应用场景,他可以让java企业级的应用程序开发起来更简单。
Spring是一个容器,何为容器?(指用来容纳某种物品的装置)
Spring是IoC的一个容器 ,IoC(Inversion of Control)“控制反转” ,也就是说Spring是一个 “控制反转” 的容器!!!
举一个栗子说明:
以构建一辆 车 的程序,传统的实现思路是:
构建一辆车首先 需要依赖车身,车身需要依赖底盘,底盘需要依赖轮胎;程序代码如下:
public class CarDemo {
public static void main(String[] args) {
Car car = new Car();
car.run();
}
/**
* 汽车对象
*/
static class Car {
public void run() {
// 需要依赖车身
Framework framework = new Framework();
framework.run();
}
}
/**
* 车身类
*/
static class Framework {
public void run() {
// 需要依赖轮胎
Bottom bottom = new Bottom();
bottom.run();
}
}
/**
* 底盘类
*/
static class Bottom {
public void run() {
// 依赖轮胎
Tire tire = new Tire();
tire.run();
}
}
/**
* 轮胎类
*/
static class Tire {
// 尺寸
private int size = 20;
public void run() {
System.out.println("轮胎尺寸:"+ size);
}
}
}
这上面的代码虽说可以实现这个车的构造,但是耦合性太强了,随时要依赖另一个对象,再者加上轮胎的需求尺寸是会越来越多,改变也会越来越频繁,然而上面的代码是固定尺寸,如果说需要修改尺寸,先看看修改尺寸的代码:
public class CarDemo {
public static void main(String[] args) {
Car car = new Car(30);
car.run();
}
/**
* 汽车对象
*/
static class Car {
private Framework framework;
public Car (int size) {
// 需要依赖车身
framework = new Framework(size);
}
public void run() {
framework.run();
}
}
/**
* 车身类
*/
static class Framework {
public Bottom bottom;
public Framework (int size) {
// 需要依赖轮胎
bottom = new Bottom(size);
}
public void run() {
bottom.run();
}
}
/**
* 底盘类
*/
static class Bottom {
private Tire tire;
public Bottom (int size) {
// 依赖轮胎
tire = new Tire(size);
}
public void run() {
tire.run();
}
}
/**
* 轮胎类
*/
static class Tire {
// 尺寸
private int size;
public Tire(int size) {
this.size = size;
}
public void run() {
System.out.println("轮胎尺寸:"+ size);
}
}
}
可见,一旦需要改需求那么整个程序都会受到影响,都要整体改一遍,增加工作量,增加错误率。
解决传统开发的缺陷:
其中重要的思想就是 解藕 。由上面代码可知,我们在每个类里面都创建了下级类,当发生需求改变,就会整个代码改变;此时我们只需要将原来自己创建下级类,改为传递的方式(注入的方式),如果需求改变,就不需要在当前类中创建修改下级类,故下级类即使发生改变也不需要在当前类本身上面修改,这样就可以完成 “解耦”
基于以上思想 “解耦” ,我们把创建子类的方式,改为注入传递的方式,具体代码如下:
public class CarDemo {
public static void main(String[] args) {
Tire tire = new Tire(40);
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
car.run();
}
/**
* 汽车对象
*/
static class Car {
private Framework framework;
public Car (Framework framework) {
this.framework = framework;
}
public void run() {
framework.run();
}
}
/**
* 车身类
*/
static class Framework {
public Bottom bottom;
public Framework (Bottom bottom) {
this.bottom = bottom;
}
public void run() {
bottom.run();
}
}
/**
* 底盘类
*/
static class Bottom {
private Tire tire;
public Bottom (Tire tire) {
this.tire = tire;
}
public void run() {
tire.run();
}
}
/**
* 轮胎类
*/
static class Tire {
// 尺寸
private int size;
public Tire(int size) {
this.size = size;
}
public void run() {
System.out.println("轮胎尺寸:"+ size);
}
}
}
经过了代码的调整,无论底层如何变化,中间的程序都没有发生任何改变,这样就可以完成解耦,让需求,程序更加灵活了。
对比总结:
传统代码对象创建顺序是:car->Framework->Bottom->Tire
改进之后解耦代码对象创建顺序:Tire->Bottom->Framework->car
现在就可以发现一个规律,类的创建是相反的,经过解耦的改变,控制权发生了改变,之前的控制权是以车car为主,现在是先以轮胎Tire为主;不再是上级对象创建控制下级对象,而是下级对象把需求注入将 当前对象中 ,这样下级的控制权不再是上级控制了,即使下级类发生了改变,当前类也不会受影响的,这就是典型的“控制反正(IoC)”,也就是IoC的实现思想。
Spring最核心的总结:Spring是包含了多个工具方法的IoC容器 。
❓❓如何理解“Spring 是一个IoC(控制反转) 容器”
重点还是在 容器 二字,这个容器具有两个最基础的功能。
那么学Spring最核心的功能,就是学如何将对象存入Spring中,再从Spring中获取对象的过程
好处:
new对象相当于纯手工制作,每次需要工具现做,用完扔掉也不会保存,下次用还要重新做,很麻烦。这就是IoC容器和普通重新开发的区别。
最后总结:
Spring是一个IoC容器,对象的创建和销毁的权利都交给Spring来管理,它本身又具备了存储对象和获取对象的能力
DI(Dependency Injection),翻译成中文是**“依赖注入” ** ;依赖注入,就是由IoC容器在运行期间,动态的将某种依赖关系注入到对象之中。指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的“解耦”。
乍一看 DI和IoC好像说的是同一件事情,实则从不同角度来描述的同一件事情。
就好比日常生活中的内存,大家都说手机内存256G或者说128G,实则说的是手机总的外存储容量,内存是指运行内存一般是8G或者16G。
栗子:
目标指:晚上出去是去吃好吃的。
可实现的思路指:海底捞,火锅,烧烤…
这篇文章重点(也是面试容易问的):
1、Spring是什么,如何理解Spring
答:Spring是包含众多工具方法的IoC容器。
2、IoC和DI是啥,有什么区别
答:IoC是“控制反转”,DI是“依赖注入”
3、Spring最核心的功能是什么?
答:具备了存储对象和获取对象的能力(存,取)。
在项目pom.xml 中添加Spring框架的支持
重要的依赖:
xml配置如下:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.3.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.2.3.RELEASEversion>
dependency>
dependencies>
Bean 也称为 “对象” ,提到Bean就是对象的意思。
就是创建一个对象:
a)、在 Maven项目中的resources 底下创建一个 xxx(名字可以随意取).xml
里面Spring的配置文件是可以保存的,是固定格式,保存到自己能找到的地方
<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">
beans>
b)、在xml中添加一个 bean,就是将刚刚创建的User对象注册到Spring中,具体操作是在 中添加。
这里面有两个重要的属性:
到这里就是Spring Ioc容器里面核心重要的一个“存”操作
ApplicationContext获取上下文
1、获取Spring 上下文对象。对象都交给了Spring管理,故获取对象要从Spring中获取,那么首先需要先创建Spring上下文,再得到Spring上下文。
//1 .创建上下文需要配置spring配置信息(得到 Spring上下文)
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring.xml");
2、使用上下文对象获得一个bean。
User user = (User) applicationContext.getBean("user");//根据 bean id来获取
这段代码没有 new 对象,是从Spring里面拿出的bean,这里就体现了Spring的价值了
3、使用 bean
user.对象的方法;
BeanFactory获取上下文
这是获取 Spring 上下文的第二种方法
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
里面的参数也是与 resources 里面的xml对应的,这是最古老的方式。
BeanFactory beanFactory1 = new ClassPathXmlApplicationContext("spring.xml");
用 ClassPathXmlApplicationContext
也是可以的
完整代码:
public class App {
public static void main(String[] args) {
//第二种获取Spring 上下文的方法是 BeanFactory
BeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("spring.xml")
); //这是最古老的方式
User user = (User) beanFactory.getBean("user");
user.saihi();
}
}
尽然都是一样的获取上下文对象,那他们的区别又是哪里尼?
**1、**性能方面:ApplicationContext 是 一次性加载并初始化 xml 里面所有 bean 对象(在当前的 Spring 项目里面);BeanFactory 是按需求进行初始化(按照代码的调用,getBean(bean id))。故ApplicationContext 就会初始化慢,但是调用快(都初始化好了直接取出就行),BeanFactory 初始化快,但是调用慢。
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring.xml"); // 创建并初始化所有 bean 对象
ApplicationContext 在这里就已经创建并初始化所有 bean 对象。
BeanFactory beanFactory1 = new ClassPathXmlApplicationContext("spring.xml");
User user = (User) beanFactory.getBean("user"); //真正创建 User 对象
BeanFactory 在下一步去 getBean 的时候采取创建对象。
**2、**二者的归属关系不同:ApplicationContext 输入 BeanFactory 的子类。
3、 二者的功能不同:BeanFactory 提供了基础操作 Bean 访问容器的功能: ApplicationContext 继承了BeanFactory,它除了有操作 Bean 的基础功能之外,还提供了更多的功能,如国际化的支持,事件的传播,资源访问等功能。
总结:“取”操作
getBean() 主要有三种使用的方法:
User user = (User) beanFactory.getBean("user");
User user = beanFactory.getBean(User.class);
特点:写法简单,但是如果 Spring 里面将一个对象注入多次,那么使用此方法就会导致程序异常。
User user = beanFactory.getBean("user",User.class);
这种方法就解决了上面两种方法的缺点,不用强转类型,也不用担心一个对象在 Spring 里面注入多次而报错,大多数使用的就是第三种方法。