🎈个人公众号:🎈 :✨✨✨ 可为编程✨ 🍟🍟
🔑个人信条:🔑 知足知不足 有为有不为 为与不为皆为可为🌵
🍉本篇简介:🍉 本篇记录Spring中的核心概念,如有出入还望指正。关注公众号【可为编程】回复【面试】领取年度最新面试题!!!
Spring中有3个核心的概念:控制反转(Ioc)、依赖注入(DI)、面向切面编程(AOP),spring中其他的技术都是依靠3个核心的技术建立起来的,所以玩spring需要先对这3个概念有个深入的理解。其实这个话题已经是老生常谈的问题了,那为啥还要拿出来说,因为一直想做一个Spring系列,切入点只能是先从理论着手,然后逐步深入,因此作为Spring系列的开局,先要知道Spring是什么,有什么,能干什么,然后在逐步深入去剖析。
本文我们先介绍其中的两个:控制反转IOC容器和依赖注入DI,而AOP我们后面有专门的文章进行详解。先通过原来的非Spring形式编码引出Spring,然后通过该例子介绍Spring到底帮我们做了哪些工作,能帮我们提升哪方面的效率。
引出spring
这里创建2个类,A类和B类,如下:
public class A{
public void a1(){}
}
public class B{
public void b1();
}
上面两个类都有各自的方法。现在我们调用B的b1方法,而B中的b1方法需要调用A中的a1方法才可以完成整个类直接的调用,所以B的代码变成了下面这样:
public class B{
private A a;//1
public B(){
this.a = new A();//2
}
public void b1(){
this.a.a1(); //3
}
}
分析一下上面代码:
//1:B类中声明了一个A类型的属性a
//2:new了一个A对象,赋给了a属性
//3:B类中的b1方法中去调用a.a1()完成业务操作
上面代码中B的b1方法需要调用A的a1方法,说明B对象依赖于A对象,B中的b方法依赖于A中的a方法。但是上面代码存在一些问题:
B类中a对象的创建写死在B的构造方法中,通过B对象在创建时同时创建A对象实例,如果我们想在创建不同的B对象的时候,使用不同的A对象实例,肯定是无法实现的,同时代码也不利于测试和维护,由于B中a的创建被写死在构造方法中,想测试一下B中不同a对象的效果,此时只能去修改B中的构造方法。那我们能不能把它拆出来,每次先去创建A对象的实例然后再交给B对象呢?
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
上面代码优化后,B中a对象的创建不能写死,外部创建好传入到B对象中,变成了下面这样:
public class B{
private A a;
public B(A a){
this.a = a;
}
public void b1(){
this.a.a1();
}
}
上面代码可以在创建B对象的时候,将外部创建好的a对象传入进去,此时a的控制权交给了使用者B对象,创建B对象如下:
A a = new A();
B b = new B(a);
b.m1();
我们再扩展一下,如果B类中还需要依赖多种类似于A的对象,比如需要依赖于C、D、E、F或者更多对象,那就需要调整B的构造方法,新增加一个构造方法,可以支持多种不同的对象。
但是使用B的时候就变成了下面这样:
A a = new A();
C c = new C();
D d = new D();
E e = new E();
F f = new F();
...
B b = new B(a,c,d,e,f,...);
b.b1();
在使用B对象之前,需要先创建B依赖的所有对象,并将这些对象传递给B对象。如果多个地方都需要用到B类型的对象,使用这种new的方式会导致代码冗长且不易维护。如果B中新增了依赖,还需要先创建被依赖的对象,然后将其填充给B对象。
以上过程需要用户自己去完成,所有对象的创建都由用户控制,这样的方式有一些缺点,比如代码冗长、耦合度高(依赖调整时需要大幅改动)、不易扩展等。这与常说的“高内聚,低耦合”原则相违背。那就需要采用更加优雅的方式来解决这个问题。
举个例子,比如存在一个第三方来负责对象的创建和组装工作。在对象调用的时候,只需要告诉第三方我需要哪些对象,向第三方提供一个清单,清单中告诉第三方需要使用B对象及其依赖的哪些对象。然后由这个第三方来创建和组装B对象。注意这里,这里是创建和组装,说明第三方并不是单一帮我们创建B对象所依赖的其他对象,而是整个B对象。当用户需要使用B对象时,只需向第三方查询。如果第三方已经创建好了B对象,就直接返回给用户。整个系统中需要使用的对象都可以列在清单中,让第三方来创建。这样就减少了用户外部创建对象的数量和代码量,当B的依赖对象有新增或删除时,只需调整清单即可。那这个第三方就是目前的Spring。
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
spring容器
spring的概念,其实它本质上就是一个容器,容器可以放很多东西,在容器里面的都是我们要用的JavaBean。程序启动的时候会创建spring容器,会给spring容器一个清单,清单中列出了需要创建的对象以及对象之间的依赖关系,spring容器会创建和组装好清单中的对象,然后将这些对象存放在spring容器中,当程序中需要使用的时候,可以到容器中查找获取,然后直接使用。
spring容器的的启动过程简要如下几步:
1、初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
2、将配置类的BeanDefinition注册到容器中
3、调用refresh()方法刷新容器
后面会单独拿出一篇文章进行详细讲解。
IOC:控制反转
用户在之前使用B对象时,都要自己去创建和组装对象,而现在创建和组装都交给spring容器去做,用户只需要去spring容器中查找需要使用的对象就可以了,在上面例子中,用户就相当于调用B对象的一方。这个过程中B对象的创建和组装过程被反转了,由原来的使用者自己主动控制并主导,现在转变成了Spring主动去创建和组装,对象的构建过程被反转了,所以叫做控制反转。IOC是面相对象编程中的一种设计原则,主要是为了降低系统代码的耦合度,可以即插即拔的使用,有利于系统的维护和扩展。Spring 中的 IoC 的实现原理就是工厂模式加反射机制。后面可以针对其进行文章输出。工厂相对应的就是beanfactory的getBean()方法,反射就是Spring底层实例化对象所采用的机制。Spring IOC 负责创建对象,管理对象(通过依赖注入(DI)装配对象、配置对象)并且管理这些对象的整个生命周期,同时可以在其生命周期内定义一些行为。后面也会单独拿出一篇文章讲解ioc的具体功能作用,包括如何创建bean,bean生命周期等等。在Spring中BeanFacotry是IOC容器的实际代表者。Spring 提供了两种不同类型的容器:ApplicationContext和BeanFactory。后面会进行详细讲解。
DI:依赖注入
依赖注入是Spring容器在创建对象时设置其依赖对象的方法。我们可以向Spring提供一个清单,清单中列出了需要创建的B对象以及其他对象(可能包含B类型所需的依赖对象)。当Spring创建B对象时,会查看B对象需要依赖哪些对象,然后在清单中查找是否包含这些被依赖的对象。如果存在,Spring将先创建这些对象,并将它们传递给B对象;B可能需要依赖多个对象,在创建B之前,无需事先了解其他对象是否存在、在哪里以及它们的创建方式。Spring容器会主动创建B所依赖的对象,并将其注入到B中。例如,当Spring容器创建B时,如果发现B依赖于A,在清单中找到A的定义后,Spring会先创建A对象,并将其注入到B对象中。
总结
-
IOC控制反转,是一种设计理念,将对象创建和组装的主动控制权利交给了spring容器去做,控制的动作被反转了,降低了系统的耦合度,利于系统维护和扩展,主要就是指需要使用的对象的组装控制权被反转了,之前是自己要做的,现在交给spring容器做了。
-
DI依赖注入,表示spring容器中创建对象时给其设置依赖对象的方式,通过某些注入方式可以让系统更灵活,比如自动注入等可以让系统变的很灵活,这个后面的文章会细说。
-
spring容器:主要负责容器中对象的创建、组装、对象查找、对象生命周期的管理等操作。
欢迎大家关注公众号【可为编程】,回复【加群】进入微信群,右边为Q群:761374713,成长,进步,编程,技术、掌握更多知识!