【Spring】Spring核心与设计思想-创新互联
- Spring核心与设计思想
- 什么是框架
- Ioc容器
- 汽车示例
- Spring IoC
- DI
- Spring创建和使用
- 创建Spring项目
- 将Bean注册到容器
- 取出Bean对象
- Application Context 和 BeanFactory
Spring其实就是我们java中的一个框架,不过这是之前流行的框架,现在比较流行的框架是SpringBoot。那什么是框架呢?
🔑框架其实就相当于脚手架,让我们开发起来更方便,比如之前用servlet实现网站的后端,步骤比较繁琐,又是创建目录,又是引入依赖,还需要配置SmartTomcat,也就是除了业务逻辑之外我们需要关注的东西比较多。那框架其实就是为了简化开发的,让我们尽量少关注这些环境问题,我们只需要实现业务逻辑就行了。
Ioc容器那Spring具体是一个什么样的框架呢?用一句话来总结就是:
🔑Spring是一个包含了众多工具方法的IoC容器。
1️⃣首先包含了众多工具方法:这个好理解,就比如java中的一些工具类,向Arrays,Collections这些集合类,提供了很多方法,方便了我们的开发,Spring也是一样,提供了很多工具方法,有需要的时候直接调用就行了。
2️⃣什么是容器:比如在数据结构中的那些集合类,比如ArrayList,LinkedList,HashMap。这些类就可以称作存储数据的容器;再比如Tomcat是存储webapp的容器。
3️⃣Ioc:Inversion Of Control:控制反转的意思。在Spring中就是把控制权交到Spring手中。这句话并不好理解,下面我们用示例解释说明这句话。
🍎Spring核心功能:Spring是包含了众多工具方法的IoC容器,最核心的功能是容器管理。
汽车示例比如我们要建造一辆汽车,传统开发思路是:造一辆车,汽车(car)依赖车身,车身(framework)依赖底盘,底盘(bottom)依赖轮胎(tire)。
🔑代码实现:
public class NewCar {public static void main(String[] args) {Car car = new Car();
car.init();
}
static class Car{public void init(){//汽车需要依赖车身
Framework framework = new Framework();
framework.init();
}
}
static class Framework{public void init(){//车身需要依赖底盘
Bottom bottom = new Bottom();
bottom.init();
}
}
static class Bottom{public void init(){//底盘需要依赖轮胎
Tire tire = new Tire();
tire.init();
}
}
static class Tire{private int size = 20;
public void init(){System.out.println(size);
}
}
}
🍎按照传统的开发思路,造汽车需要车身,那就在Car类中的init方法中创建FrameWork,而车身又需要底盘,那就在FrameWork的init方法中创建底盘,造底盘需要轮胎,那就在底盘的init方法中创建轮胎。不过这时候轮胎尺寸是固定的,如果更改了需求,轮胎尺寸由用户自定义,那就需要改动代码:
import java.util.Scanner;
public class NewCar {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
Car car = new Car();
car.init(size);
}
static class Car{public void init(int size){//汽车需要依赖车身
Framework framework = new Framework();
framework.init(size);
}
}
static class Framework{public void init(int size){//车身需要依赖底盘
Bottom bottom = new Bottom();
bottom.init(size);
}
}
static class Bottom{public void init(int size){//底盘需要依赖轮胎
Tire tire = new Tire();
tire.init(size);
}
}
static class Tire{private int size = 20;
public void init(int size){this.size = size;
System.out.println(size);
}
}
}
需要从Car到FrameWork再到Bottom再到Tire,把尺寸size一级一级地向下传递。也就是说整个调用链都需要发生改变。那对于复杂的项目,可能调用链更多,那这时候更改了业务需求,需要的改动就会更多。这就叫做代码的耦合度太高。下面改进一下代码,就可以降低耦合度:
import java.util.Scanner;
public class NewCar {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
Tire tire = new Tire(size);
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
}
static class Car{private Framework framework = null;
public Car(Framework framework) {this.framework = framework;
}
}
static class Framework{private Bottom bottom = null;
public Framework(Bottom bottom){this.bottom = bottom;
}
}
static class Bottom{private Tire tire = null;
public Bottom(Tire tire) {this.tire = tire;
}
}
static class Tire{private int size = 20;
public Tire(int size){init(size);
}
public void init(int size){this.size = size;
System.out.println(size);
}
}
}
🔑改进的策略是将new实例这部操作提取出来,之前是Car需要Framework,就在Car类中new出Framework实例,Framework需要Bottom就在Framework中new出Bottom实例。现在把new实例提取出来,也就是将控制权交出去。让类和类之间的关联降低,让代码的耦合度降低。
🔑之前的代码是我当前类需要底层类的实例,就在当前类中new底层类的实例,现在是我需要底层类的实例,就给我传一个底层类的实例。我的车身需要底盘,我不自己建造了,我外包给别人建造,建造好之后把底盘给我就行了。这样当再发生需求变更的时候就无需一级一级的修改代码了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zt7Ytq4d-1669874585317)(https://hao-typora.oss-cn-beijing.aliyuncs.com/img/image-20221121112735320.png)]
🍊改进前:由上级类创建下级类的实例,改进后:将下级类实例传入上级类。下级的控制权不再交给上级。即使下级类发生任何改变,上级都是不受影响的。
🍎控制反转(IoC):控制反转就是控制权反转。比如A类需要B类对象,如果在A类中new出B类实例,那B类控制权就是在A类中。控制权反转就是如果A类对象需要B类对象,B类对象交由Spring来管理,对象的控制权交给Spring了,A类对象需要B类对象就从Spring来获取,Spring相当于是一个第三方。
Spring IoCSpring是一个包含了众多工具方法的IoC容器,既然是个容器,Spring存储的其实是对象。它具备两个最基本的功能:将对象存入容器和从容器中取出对象。
说Spring是一个IoC容器是因为:对象的创建和销毁的权利都交给Spring来管理了,它本身又具备了存储对象和获取对象的能力。控制权交给了Spring,所以符合IoC的思想。
==将对象存入容器的好处:==将对象存入容器后,以后再需要直接取就行了,而new对象的方式是每次需要都需要工具都现做,用完就丢掉,下次用的时候还得重新做。
DIDI:Dependency Injection (依赖注入)
所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中 ,就比如要创建一个Car需要先有一个FrameWork,此时FrameWork就是Car的依赖,创建Car对象的时候需要先把Framework传给Car对象。
Ioc和DI其实是具有相似之处的:Ioc是思想,而DI是这种思想的一种具体实现方式。
Spring创建和使用Spring创建和使用总共分为三部分:
- 创建一个Spring项目
- 将Bean注册到容器(Spring中的Bean就是java中的对象)
- 获取并使用Bean
一:创建一个Spring项目:
总共三个步骤:
1️⃣创建一个Maven项目
2️⃣引入Spring依赖:
org.springframework spring-context 5.2.3.RELEASE org.springframework spring-beans 5.2.3.RELEASE
3️⃣创建启动类(类名自己定)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GuBG3y4r-1669874585318)(https://hao-typora.oss-cn-beijing.aliyuncs.com/img/image-20221121170951814.png)]
将Bean注册到容器二:将Bean注册到容器
1️⃣先有一个Bean,Bean可以理解为就是java中的对象。但是并不是真的创建出一个对象,然后存到Spring容器中。我们只需要一个类就行了,并不需要真的创建出对象,创建对象是Spring的工作。实际上是向Spring中注册一个类,将来有需要的时候Spring用这个类实例出对象。
2️⃣添加配置文件spring-config.xml(文件名自定义)到resources根目录下
3️⃣注册Bean到容器中
- 注册Bean到容器中其实是在spring-config.xml配置文件中添加一个标签,标识一个Hello类,class属性是包名+类名,id属性是标识符,可以自定义。id是唯一的,存储的多个Bean的id不能重复
- 这里的注册Bean到容器中,并没有真正创建对象,因为Spring的创建对象机制是懒汉模式,也就是当你用的时候,也就是取对象的时候才真正创建对象。这里注册只是告诉Spring今后可能会用这个类创建对象,id和class让Spring能找到这个类并创建出对象。
从Spring中取出Bean对象:
🍎这个取对象的过程其实就是Spring帮我们创建好了对象,然后把对象的引用交给自己的程序,这里有个关键点就是:注册到Spring中的类的构造方法要么是无参的,要么是有参的且参数是存储于Spring中的对象(这个在构造方法注入中会讲到),不能是自己任写的,如果自己任写一个构造方法,参数是一个String类型,那Spring自然就不知道要给构造方法传什么字符串了,这时候就会报异常。
1️⃣获取Spring上下文对象:因为我们要从Spring中取出Bean,所以必须得先有个Spring上下文对象。构造方法的参数是resources根目录下的配置文件名
2️⃣获取对象:getBean方法的参数是之前在配置文件中存储的Bean的id。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
//获取Spring上下文对象
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-config.xml");
//获取对象
Hello hello = (Hello) applicationContext.getBean("hello");
//使用对象
hello.sayHi();
}
}
其中第二步获取对象常用的有三种方式,上面代码中通过id来获取是第一种,
第二种是通过类型来获取:
Hello hello = applicationContext.getBean(Hello.class);
- 这种方式获取的对象不需要类型强转
不过这种方式有可能会出现bug,因为在Spring中可以对同一个类注册两次:(但是注册两次的id是不能相同的,否则会报错)
✅如果是第一种方式,根据id获取对象,那没有任何问题,但如果是第二种通过类型来获取,就会报错(因为此时在Spring中对同一个类注册了两次,而这两个Bean将会来产生两个对象,这两个对象又属于同一个类),如果这个类只注册了一次,那这两种获取对象的方式都不会报错。
第三种方式:使用id+类名
Hello hello = applicationContext.getBean("hello",Hello.class);
Application Context 和 BeanFactory
除了第二步创建对象有三种方式之外,获取Spring上下文对象还有另外一种方式:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
✅面试问题:Application Context 和 BeanFactory的区别:
1️⃣Application Context属于BeanFactory的子接口,BeanFactory提供了基础的访问容器的能力,而Application Context还提供了除此之外的其他能力,比如还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持。
2️⃣ApplicationContext 是⼀次性加载并初始化所有的 Bean 对象,⽽ BeanFactory是需要那个才去加载那个,因此更加轻量。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章名称:【Spring】Spring核心与设计思想-创新互联
转载注明:http://myzitong.com/article/iocsi.html