一. Spring 是什么 ?
我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,有着活跃⽽ 庞⼤的社区,这就是它之所以能⻓久不衰的原因。Spring ⽀持⼴泛的应⽤场景,它可以让 Java 企业级 的应⽤程序开发起来更简单。
- 以下是 Spring 框架的一些核心特点:
- 轻量级:Spring 框架采用了松耦合的设计原则,仅依赖于少量的第三方库,因此它是一个轻量级的框架。开发人员可以根据需要选择使用 Spring 的特定功能,而无需引入整个框架。
- 控制反转(IoC):Spring 框架通过控制反转(IoC)容器管理应用程序中的对象及其依赖关系。通过 IoC 容器,开发人员可以将对象的创建、组装和生命周期管理交给 Spring 框架处理,从而实现了松耦合和可测试性。
- 面向切面编程(AOP):Spring 框架支持面向切面编程,可以通过 AOP 在应用程序中实现横切关注点的模块化。例如,日志记录、事务管理和安全性等横切关注点可以通过 AOP 进行集中处理,而不会侵入业务逻辑的代码。
- 声明式事务管理:Spring 框架提供了声明式事务管理的支持。通过使用注解或 XML 配置,开发人员可以将事务管理逻辑与业务逻辑分离,并且可以轻松地在方法或类级别上应用事务。
- 框架整合:Spring 框架可以与许多其他开源框架和技术无缝集成,如 Hibernate、MyBatis、JPA、Struts 和 JSF 等。这使得开发人员可以使用 Spring 框架来整合和协调不同的技术,构建全面的企业应用程序。
- 测试支持:Spring 框架提供了广泛的测试支持,包括单元测试和集成测试。它提供了一个专门的测试上下文,可以轻松地编写和执行单元测试,以验证应用程序的行为和功能
如果要使用一句话来概括 Spring , 那就是 Spring是包含了众多工具方法的 IoC 容器
何为 IoC ? , IoC 的全称叫做 Inversion of Control , 即为控制反转 ,也就是说 Spring 是一个控制反转的容器 , 那么怎样理解上述的内容呢 ?
二. 何为 IoC ?
准确来说 , **IoC 指的并不是一种具体的技术, 而是一个实现对象解耦的思想 **
耦合 : 当两个或者两个以上的对象存在依赖,一方修改之后就会影响另外一方,就说明这两个对象之间存在这耦合关系 , 而解耦, 就是为了解除这两个对象之间的依赖关系。
那么 IoC 是如何实现对象的解耦呢 ?
下面通过一个具体的示例来进行讲解 :
在传统的开发思想中 , 当我们要构建一辆车时 , 而车又依赖于车身, 车身又依赖于底盘,底盘又依赖于轮胎,他们之间的依赖关系如下图所示 :
当我们使用代码进行实现时 ,所有类之间的调用链如下所示:
// Car类
public class Car {
// car 进行初始化时 , 需要调用 framework
public void init(){
System.out.println("do car");
Framework framework = new Framework();
framework.init();
}
public static void main(String[] args){
Car car = new Car();
car.init();
}
}
// Framework类
public class Framework {
// framework 进行初始化时, 调用了Bottom
public void init(){
System.out.println("do framework");
Bottom bottom = new Bottom();
bottom.init();
}
}
// Bottom 类
public class Bottom{
// Bottom 进行初始化时,调用了 Tire
public void init(){
System.out.println("do bottom");
Tire tire = new Tire();
tire.init();
}
}
// Tire 类
public class Tire {
private int size = 10;
public void init(){
System.out.println("size -> "+size);
}
}
在上述的代码当中,如果轮胎的尺寸 size 发生了改变,相对应的 底盘,车身,再到整车都要发生一定的变化,也就是当我们在自身类创建下级类时,当下级类发生改变操作,自己也要跟着修改,代码的耦合程度较高,不利于后续的更新和添加元素,所以如何实现程序的解耦呢?
那么如何解决传统开发中的缺陷呢 ?
答案是我们在创建类时,不在每个类中创建下级类,而是改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类中即使发生变化,当前类也无需修改任何代码,这样就完成了程序的解耦。
下面我们将参数传递的方式进行修改:
- 通过将对象进行传递而并非 new 对象的方式来进行解决:
# car类
public class Car {
private Framework framework;
// 将 framework 注入 car
public Car(Framework framework) {
this.framework = framework;
}
public void init() {
System.out.println("do car...");
framework.init();
}
}
# framework 类
public class Framework {
private Bottom bottom;
// bottom 注入 framework
public Framework(Bottom bottom){
this.bottom = bottom;
}
public void init(){
System.out.println("do framework");
bottom.init();
}
}
# bottom类
public class Bottom {
private Tire tire;
// tire 注入 bottom
public Bottom(Tire tire) {
this.tire = tire;
}
public void init() {
System.out.println("do bottom...");
tire.init();
}
}
# trie 类
package newCar;
public class Tire {
private int size = 17;
private String color = "红色";
public Tire(int size, String color) {
this.size = size;
}
public void init() {
System.out.println("size -> " + size + " | color -> " + color);
}
}
# 测试类
public class Test {
public static void main(String[] args) {
Tire tire = new Tire(20, "黑色");
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
car.init();
}
}
代码经过上述的调整之后,无论底层的类如何进行改变,整个调用链都不会发生变化,这样就完成了代码之间的解耦。
在传统的代码中对象的创建顺序是 : Car -> Framework -> Bottom -> Tire
改进之后解耦的代码创建顺序是: Tire -> Bottom -> Framework -> Car
再举一个开发中比较简单的例子 :
当我们在开发过程中, A 对象要使用 B对象的 某个方法, 我们通常的实现方法如下 :
class A{
public void init(){
// new一个B类对象,调用 init()方法
B b = new B();
b.init();
}
}
class B{
public B(){
}
public void init(){
System.out.println("hello world!");
}
}
此时,A 和 B对象是相互进行耦合的, 当修改了B中构造方法的参数时,A对象也要随之发生改变。
class B {
public B(String name){
System.out.println("姓名 :"+name);
}
public void init(){
System.out.println("Hello word!");
}
}
那么实际业务中,如何解决上述的问题呢?
与上一个例子类似, 也是通过将对象进行传递(注入)的方式 , 代码如下 :
class A {
// 先定义一个需要依赖的 B 对象
private B b;
// 通过构造方法实现赋值(初始化)
public A(B b) {
this.b = b;
}
public void init() {
// 调用 B 类中的 init 方法
b.init();
}
}
class B {
public B(String name) {
System.out.println("姓名:" + name);
}
public void init() {
System.out.println("Hello World!");
}
}
这样修改之后,无论B的构造方法怎么修改,而调用他的A类不需要做任何修改 ,这样就实现了对象的解耦,那么对象的解耦 和 IoC 又有什么关系呢?
通过上边的两个例子,究其原因还是控制权反转的问题 ,A对象对于B对象的管理权交出,交给其他程序来管理,此时A对象对于B对象的管理权发生了反转和改变,这就是 IoC
三. 如何理解 Spring IoC ?
在 Spring 中, 将 对象交给了 IoC 容器来进行管理 , 不需要关注怎么去创建对象,而是关注创建对象之后的操作, 把对象的创建,初始化,销毁交给了 Spring IoC 容器来管理 。
既然 Spring 是一个IoC容器 ,那么他就具有两个最基础的功能 :
- 将对象存入到容器
- 从容器中取出对象
也就是说, 对象的创建和销毁都交给了Spring来管理了,它本身又具备了存储对象和获取对象的能力 。
Spring IoC 的优点有哪些 ?
- 实现对象解耦
- 使用更加方便(不需要手动去new创建,和关注对象背后的依赖问题,只关注使用权)
- 更加高效(从容器中取出对象,不需要重新new)
四. IoC 与 DI
DI 是 Dependency Injection 的缩写,翻译成中文是“依赖注入”的意思。依赖注入不是一种设计实现,而是一种具体的技术,它是在 IoC 容器运行期间,动态地将某个依赖对象注入到当前对象的技术就叫做 DI(依赖注入)。
在上述的两个例子当中,对象的传递通过构造方法被动的获取对象,在Spring 中 DI 的实现一般通过注解来主动的获取对象, IoC 是一种设计思想,而 DI 是一种具体的实现技术,比如想吃顿好的是一种思想,但是吃火锅还是串串是一种具体的实现。
Spring中DI有三种 常用的注入方式,后边会详细介绍,下面简单介绍演示一下属性注入:
@Service
public class FrameWork{
@Autowired
private Bottom bottom;//通过属性注入
}
五 . 总结
IoC 和 DI 都是 Spring 框架中的重要概念,它们都是用来实现对象解耦的,其中 IoC(控制反转)是一种设计思想,而 DI(依赖注入)是一种具体的实现手段,Spring IoC 中最基础的功能就是对对象的存取。
版权归原作者 署前街的少年 所有, 如有侵权,请联系我们删除。