难度:★★★★
重点:★★★★
Spring目前是Java技术体系中最核心的框架,没有之一,不管是SpringBoot也好还是SpringCloud,都是建立在Spring的基础之上的(这句话别不当回事,后面讲SpringBoot和SpringCloud的时候,你们就会真正理解Spring的重要性)。
概念:它其实就是一个轻量级的应用框架。
作用:最最核心功能就是帮程序员管理Bean对象的(IoC)。面向切面编程(AOP)。
1、IOC:
举个最简单的例子来感受一下它的核心功能:如果没有Spring的话,我们开发的时候都需要自己去创建Bean对象,就比如在Controller层会调用某些Service,那这个时候我们需要通过new关键字创建大量的Service对象,如果换一个Controller类的话,我们又得重新创建(一般情况下是这样的),这极大的增加了我们程序员的工作量,对象之间的耦合性还高,同时还不方便做扩展。
自从有了Spring之后,程序员不需要自己去创建一些核心对象了,只需要在类上面加一些注解,例如@Controller、@Service或者@Component等,Spring自动会帮我们创建对象,然后将这些对象存在一个全局的缓存里面,在当前项目的任何地方,都可以通过缓存去拿到它。这就减少了程序员的工作量了。
同时Spring在帮我们创建对象的整个流程中,还给我们提供了各种接口,这些接口都是用来做扩展或者功能增强的。只需要你的类实现这些接口并重写相应的方法,那当你的类被实例化的时候,Spring就会去执行你重写的方法,这就是扩展。
2、AOP:
就是在执行真正的业务代码之前或者之后,先做一下功能增强,执行一下别的功能,比如打印日志啊,系统监控啊,流量统计啊、事务管理啊等等。说到功能增强立马就要想到代理,没错,AOP的核心就是代理了,然后代理对象搞定之后,还要实现一下拦截点,拦截之后,你可以去做一些你想要的功能,说的形象一点AOP就好比一把刀把所有的请求全部切断,让他们全部暂停执行,先来执行我定义的逻辑。
1、spring是一个开源的轻量级JavaBean容器框架。
2、作用:
帮程序员管理Bean对象,减轻工作量
能够降低对象与对象之间的耦合性
提供多种扩展接口,增加系统的鲁棒性
能够将系统功能和业务功能开发分开,同时现在市面上Java技术都能很好的集成Spring,让开发变得简单灵活
(作用说了一大堆,其实不用背,关键是要自己能理解)
难度:★★★
重点:★★
Spring的整体架构实际上是比较庞大的,对于初级程序员而言,只要理解几个比较重要的模块就好了。
1、Web:提供一些集成的特性,主要为处理前端请求提供支持。
2、Data Access/Integration:跟数据库打交道的:
JDBC:封装那堆JDBC代码的。
ORM:提供标准,然后让Mybatis或者Hibernate这些框架集成的。
Transactions:Spring统一管理事务的,支持编程和声明式事务管理。
3、AOP:提供了面向切面编程实现。
4、Aspects:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。
5、Core Container(Spring 的核心容器)
Beans 模块:提供了框架的基础部分,包括控制反转(IoC)和依赖注入(DI)。
Core 核心模块:封装了 Spring 框架的底层部分,包括资源访问、类型转换及一些常用工具类。
Context 上下文模块:建立在 Core 和 Beans 模块的基础之上。
5、Test:为测试提供支持的。
1、Web模块
2、JDBC模块
3、AOP模块
4、Aspects模块
5、Beans、Core、Context模块
6、Test模块。
难度:★★★
重点:★★
搞明白Spring的概念和组成架构之后,接下来就是明确它在设计上的艺术性了,Spring的作者Rod Johnson不仅是搞技术的,这哥们还是个搞音乐的,他获得过音乐博士学位,所以他创造Spring的时候也带了艺术性的。设计模式这块我们先记住,后面在中级篇的时候还会系统讲的。Spring中的设计模式比较多,不需要都记住,简单的理解加黑的那几个就好了。
1、简单工厂模式:IoC容器中的BeanFactory就是一个简单工厂,用来创建对象的。
2、工厂方法模式:FactoryBean就是典型的工厂方法模式。
3、单例模式:Bean默认为单例模式。
4、原型模式:Bean可以手动设置成prototype,表示每次拿到的都是不同的bean对象。
5、代理模式:这种模式就是用来做功能增强的,比如在执行真正的业务逻辑之前先打印日志啊,执行完业务逻辑之后再统计啊等等,AOP用到了JDK的动态代理和CGLIB字节码生成技术。
6、模板方法:用来解决代码重复的问题。比如把JDBC的那几行重复代码抽象提出来。
7、观察者模式:比如监听器:ApplicationListener,它会观察监听某些事件,一旦发生了某些事件,ApplicationListener的实现类就会被调用。
8、策略模式:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。
9、适配器模式:作为两个不兼容的接口之间的桥梁,实际上相当于中介。
10、装饰器模式:动态给一些对象增加额外的功能。
11、建造者模式:拿到一个简单对象,然后把简单对象一步步建造成具有复杂功能的对象。
12、责任链模式:比如WebFilterChain,就是把一次请求要执行的逻辑封装成一条链路,一步步执行。
1、简答工厂、工厂方法模式
2、单例模式
3、代理模式
4、模板方法模式
5、观察者模式
6、装饰器模式
难度:★★
重点:★★★★
IoC可以说是Spring框架中最重要的内容之一了,它贯穿整个Spring的生命周期;今后学习到任何要集成进Spring的技术组件,几乎都离不开IoC。
1、IoC是什么:IoC是Inversion of Control的简写,也叫控制反转;Spring出现以前是由程序员来控制创建对象的,Spring出现以后,程序员把创建对象的权利交给了IoC容器,控制权反转了。
而IoC容器说白了就是一些Map啊、List啊甚至一些对象等,用来缓存Bean对象、参数什么的。例如BeanFactory啊、ApplicationContext啊都可以理解成IoC容器。
2、IoC工作大致流程:
程序员通过 XML 配置文件、注解(@Component)、Java 配置类(@Bean)等方式,对 Java 对象进行定义。
Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并缓存到IoC容器中。
当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。
难度:★
重点:★★★
这道题其实没什么难度,关键是两个单词顺序换来换去,容易混淆。
1、BeanFactory是Bean工厂,而FactoryBean是一个Bean接口。
2、BeanFactory是一个IoC容器,实际上是所有IoC容器中管理对象容器的顶级接口;它其实作为一个Bean工厂,提供了一套统一的创建、存储、管理、获取Bean对象的流水线一样的规范方法(当然实现是由它的子类完成)。 BeanFactory 在产生 Bean 的同时,还提供了解决 Bean 之间的依赖注入的能力,也就是所谓的 DI。
FactoryBean实际上就是让我们在流水线生产Bean对象之外,还可以自定义一个Bean并且加载到 IOC 容器里面。它里面有一个重要的方法叫 getObject(),这个方法里面就是用来实现动态构建 Bean的过程。如果你想做一些羞羞的定制,你就可以让你的类实现FactoryBean接口,然后重写getObject方法。
总结起来就一句话,BeanFactory是做流水线工作的,FactoryBean是做私人订制的。
难度:★
重点:★★
这两个都是Spring中的容器,只不过BeanFactory是顶级的,而ApplicationContext是BeanFactory的子接口。从这一层去理解,ApplicationContext肯定具备了BeanFactory的所有功能,同时还提供了一些属于自己的附加功能。
1、他们两都是Spring的核心容器接口,BeanFactory是顶级的,ApplicationContext是BeanFactory的子接口。
2、BeanFactory提供了对Bean的创建、存储、管理、获取等一系列规范化的方法;ApplicationContext在具备这些方法之外,它还继承了EnvironmentCapable、MessageSource等接口(这里就不写了,反正不需要去记),这样使得它拥有了更完善的功能,例如支持国际化、统一资源文件访问方式、加载多配置文件、载入多个上下文等其他功能。
难度:★★
重点:★★★★
前面已经介绍了IoC,它就是控制反转,它的实现方式主要有两种:依赖注入(DI)和依赖查找(DL)。
先给一段代码:
- public class Girl{
- Boy boy;
- }
依赖查找:Girl对象依赖Boy,当它实例化的时候,Girl会通过容器的 API 来查找Boy对象;需要手动去查找。
依赖注入:Girl和Boy对象统一由容器进行管理,由IoC Service Provider 来自动完成依赖关系的绑定。当Girl要依赖Boy的时候,IoC Service Provider会从容器中拿到相应的Boy对象,并通过Girl的构造方法或者set方法把Boy对象设置进Girl。
Denpendency Injection的简写,也叫依赖注入。在IoC容器创建对象的时候进行属性注入的。
难度:★★
重点:★★
理解了IoC和DI的概念之后,接下来要搞明白依赖注入属性的使用方式了。现在XML方式已经属于淘汰行列了,所以不再介绍XML方式的依赖注入了,只讲基于注解的方式。
注解方式注入有三个注解:
1、@Value:注入普通属性的,例如配置文件application.properties文件中配置的属性,就能通过@Value注入。
2、@Resource:Java原生注解,用来注入对象类型的,默认按照名称进行注入。
3、@Autowired:Spring框架提供的注解,也是用来注入对象类型,默认按照类型注入。
如果一个接口有两个或者多个实现类,此时通过Autowired进行注入的时候会报错,此时我们可以通过@Qualifier来解决,例如:
- @Configuration
- public class ConfigurationDemo{
- @Bean("demo01")
- public ServiceDmeo serviceDmeo01(){
- return new ServiceDmeo();
- }
- @Bean("demo02")
- public ServiceDmeo serviceDmeo02(){
- return new ServiceDmeo();
- }
- }
-
- public class UseDemo{
- @Autowired
- @Qualifier("demo01")
- private ServiceDmeo serviceDemo;
- }
它可以对类的成员属性,方法和构造方法进行修饰。
构造器注入
- @Service
- public class Girl{
- private Boy boy;
- @Autowired
- public Girl(Boy boy){
- this.boy = boy;
- }
- }
- @Service
- public class Girl {
- @Autowired
- public void test(Boy boy){
- System.out.println(boy);
- }
- }
-
- @Service
- public class Girl {
- private Boy boy;
- @Autowired
- public void setBoy(Boy boy){
- this.boy = boy;
- }
- }
- @Service
- public class Girl{
- @Autowired
- private Boy boy;
- }
1、构造器注入
2、普通方法注入
3、属性注入
难度:★★★★
重点:★★★
这道题能理解死循环的形成和如何打破就能回答出来。
想必依赖注入的概念大家都已经明确了,那在依赖注入的时候会存在一种死循环的概念,我们通过代码看看:
- public class Girl{
- @Autowired
- private Boy boy;
- }
-
- public class Boy{
- @Autowired
- private Girl girl;
- }
这个时候你中有我,我中有你,那在初始化Girl的时候,会进行属性注入,但是此时Boy如果还没初始化好呢,那这个时候Spring又去初始化Boy,但是Boy也需要属性注入Girl,但是Girl也没有初始化好啊,完犊子了,死循环了。
Spring肯定考虑到这个问题了,所以提出了通过三级缓存的概念来解决它。
1、先明确三级缓存的概念:
一级缓存:用来存完整的Bean对象。
二级缓存:存已经实例化,但是还没有初始化的Bean对象。
三级缓存:用来存Bean工厂对象,这个工厂对象的功能就是生产Bean对象的并存到二级缓存中。
2、然后再来通过图解释三级缓存解决循环依赖的流程
概念:循环依赖的意思就是Girl中有Boy,Boy中有Girl,他们相互依赖,在实例化之后进行属性注入的时候会造成死循环。
解决方案:通过三级缓存去解决。核心思想就是用一个替代的Girl工厂对象先存到三级缓存里面去,然后Boy在属性注入的时候就能找到Girl的这个工厂,然后通过工厂创建一个不成熟的Girl作为一个替代先进行注入,然后就把这个死循环打破了。
难度:★★★
重点:★★★
1、二级缓存:
从上面那道题我们理解了循环依赖的概念,但是你们有没有觉得二级缓存有点多余啊,从图上看到,其实二级缓存没起到什么实质性的作用,那把它干掉可不可以呢?
答案肯定是不可以的。我这里举个例子,假设现在Girl同时依赖了Boy和Man,然后Boy和Man也依赖了Girl。
2、三级缓存
那又有问题了,可以不可以不要三级缓存,直接在二级缓存里面创建不成熟的Girl,让Boy和Man直接去二级缓存里面拿就好了。
我觉得如果你不用代理做增强的话,理论上是可以的。但是要用代理的话,必须要用三级缓存;
因为在工厂创建对象的时候能给我们创建代理(AbstractAutowireCapableBeanFactory#doCreateBean方法中)。
1、二级缓存必须要有,如果没有二级缓存,当Girl类依赖注入多个其他类的,且其他类也都依赖Girl的时候,会出现注入的不是同一个Girl的情况。
2、三级缓存:需要用代理的时候必须要有,如果不用代理可以不需要。