Spring高频面试题大总结(一)——IOC

目录

一、什么是Spring? 

二、Spring的优缺点是什么?

Spring的优点

Spring的缺点

三、什么是Spring IOC 容器?有什么作用?

什么是IOC?IOC的作用?

IOC的优点

四、Spring IoC 的实现机制是什么?

五、IOC和DI的区别是什么?

六、紧耦合和松耦合有什么区别?

七、BeanFactory的作用​

八、BeanDefinition的作用

九、BeanFactory 和 ApplicationContext有什么区别?

十、BeanFactory 和FactoryBean有什么区别?

十一、Spring IOC容器的加载过程(超重点!!!)


一、什么是Spring? 

Spring是一个生态,可以构建java应用所需要的一切设施。

通常Spring指的是Spring Framework

Spring是一个轻量级的开源容器框架

Spring是为了解决企业级应用开发的业务逻辑层 和 其他各级对象和对象之间的耦合问题

Spring是一个IOCAOP的容器框架

IOC:控制反转

AOP:面向切面编程

容器:包含并管理应用对象的生命周期(Spring可以解决对象与对象之间的耦合问题,所以Spring集中管理了对象的生命周期——创建、销毁...)

二、Spring的优缺点是什么?

Spring的优点

(1)方便解耦,简化开发

通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制避免硬编码所造成的过度程序耦合
集中管理对象,对象和对象之间的耦合度减低,方便维护对象。

(2)AOP编程的支持

通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用.
在不修改代码的情况下可以对业务代码进行增强减少重复代码,提高开发效率,维护方便

(3)声明事物的支持

在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
提高开发效率,只需要一个简单注解@Transactional

(4)方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
Spring实现测试使我们可以结合junit非常方便测试Spring Bean 、SpringMVC

(5)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架 (如Struts,Hibernate、Hessian、Quartz)等的直接支持。
拥有非常强大粘合度集成能力非常强,只需要简单配置就可以集成第三方框架

(6)降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层通过Spring的简易封装,这些Java EE API的使用难度大为降低
简化开发, 帮我封装很多功能性代码

Spring的缺点

应用层面(使用上)来说是没有缺点的!

简化开发, 如果想深入到底层去了解就非常困难(上层使用越简单、底层封装得就越复杂

由于spring 大而全(要集成这么多框架、提供非常非常多的扩展点,经过十多年的代码迭代) 代码量非常庞大,一百多万对于去深入学习源码带来了一定困难,Spring体量大,对于Spring的开发者后期的维护存在挑战。

三、什么是Spring IOC 容器?有什么作用?

什么是IOC?IOC的作用?

IOC就是控制反转,它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配管理。所谓“控制反转”的概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。

Spring IOC 负责创建对象管理对象(通过依赖注入(DI)装配对象配置对象)并且管理这些对象的整个生命周期

管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的。

解耦,由容器去维护具体的对象

托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的。

简单的来说就是:

我们自己new一个对象,可能会导致程序耦合度过高,后期可能维护不便。引入IOC,将创建对象的控制权交给Spring的IOC容器;如果要去使用对象,通过DI(依赖注入)@Autowired注解 自动注入,就可以使用对象了!

IOC的优点

集中管理对象、方便维护 、降低耦合度

最小的代价和最小的侵入性使松散耦合得以实现

IOC容器支持加载服务时的饿汉式初始化的懒加载

四、Spring IoC 的实现机制是什么?

Spring 中的 IoC 的实现原理就是工厂模式反射机制

工厂相对应的就是beanfactorygetBean()方法,反射就是Spring底层实例化对象所采用的机制

interface fruit{
    public abstract void eat();
}

class Apple implements fruit {
    @Override
    public void eat() {
        System.out.println("Apple");
    }
}

class Orange implements fruit {
    @Override
    public void eat() {
        System.out.println("Orange");
    }
}

class Factory {
    public static fruit getInstance(String ClassName) {
        fruit f = null;
        //通过反射创建对象 
        try {
            // 相当于Spring中new了一个ClassPathXmlApplicationContext
            f = (fruit)Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}

class Test {
    public static void main(String[] args) {
        //getInstance时静态的,直接调用即可Factory.getInstance()
        fruit f = Factory.getInstance("Apple");
        if(f != null)
            f.eat();
    }
}

//输出 Apple

注意点:

  • Class.forName(“”)返回的是
  • Class.forName(“”).newInstance()返回的是object 

五、IOC和DI的区别是什么?

很多人把IOC和DI说成一个东西,笼统来说的话是没有问题的,但是本质上还是有所区别的,希望大家能够严谨一点,IOC和DI是从不同的角度描述的同一件事IOC是从容器的角度描述,而DI是从应用程序的角度来描述,也可以这样说,IOC是依赖倒置原则的设计思想,而 DI是具体的实现方式(没有DI在Spring中你就拿不到对象)。

我们可以举一个例子来说明:

在面向对象设计的软件系统中,底层的实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。

一个对象出了问题,就可能会影响到整个流程的正常运转。

现在,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。

大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,对象和对象之间没有了耦合关系。本来我需要找一个女朋友,然后往后余生都是她;但是现在有了“容器”,我只要到洗浴中心,点一个小姐(依赖注入)我就有女人了。

它起到了一种 类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此 失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来

六、紧耦合和松耦合有什么区别?

紧耦合:是指类之间的高度依赖。即 我们之前在代码中直接new一个对象,这样子的代码过多,就会导致耦合度过高。

松耦合:可以通过 单一职责原则、接口分离原则、依赖倒置原则来实现。

我们现在来复习一下这几个设计模式的概念,可以看一下这里!!!

依赖倒置原则——面向对象设计原则 (biancheng.net)http://c.biancheng.net/view/1326.html单一职责原则:一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。即一个功能用一个类表示。

缺点:

  1. 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;
  2. 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。

接口分离原则:要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。

即 一个类要给多个客户使用,那么可以为每个客户创建一个接口,然后这个类实现所有的接口;而不要只创建一个接口,其中包含所有客户类需要的方法,然后这个类实现这个接口。

依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。IOC就实现了依赖倒置原则!!! 

如何实现?

  1. 每个类尽量提供接口或抽象类,或者两者都具备。
  2. 变量的声明类型尽量是接口或者是抽象类。
  3. 任何类都不应该从具体类派生
  4. 使用继承时尽量遵循里氏替换原则(子类可以扩展父类的功能,但不能改变父类原有的功能)

七、BeanFactory的作用

BeanFactory是Spring中非常核心的一个顶层接口(它没有实现其他接口);

它是Bean的“工厂”、它的主要职责就是生产Bean

它实现了简单工厂的设计模式,通过调用getBean传入标识生产一个Bean

它有非常多的实现类、每个工厂都有不同的职责(单一职责)功能。

最强大的工厂是:DefaultListableBeanFactorySpring底层就是使用的该实现工厂进行生产Bean的。

BeanFactory它也是容器!Spring容器(管理着Bean的生命周期);Tomcat是Servlet的容器(它管理着Servlet的生命周期)

八、BeanDefinition的作用

它主要负责存储Bean的定义信息,决定Bean的生产方式。

<bean class="com.Harmony.User" id="user" scope="singleton" lazy="false" >
    <property name="username" value="xushu"> 
</bean>

配置一个bean就会产生一个BeanDefinition

后续BeanFactory根据这些信息就行生产Bean: 比如实例化 可以通过class进行反射进而得到实例对象 , 比如lazy 则不会在ioc加载时 创建Bean

九、BeanFactory 和 ApplicationContext有什么区别?

BeanFactory是Spring IOC中的基础容器,用来解析BeanDefination存放bean的容器,还会对外提供一些操作bean的接口,AplicationContext是BeanFactory的扩展容器,基于BeanFactory 将其和其他组件整合到了一起。

FactoryBean以bean结尾的,我们就可以知道它是一个bean,但是它是一个特殊的bean,可以用来生产bean的一个bean。

BeanFactoryApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是 BeanFactory的子接口

BeanFactory:是Spring里面最顶层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。BeanFactory 简单粗暴,可以理解为就是个HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。

ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具 备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等 待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能

  • 如果说BeanFactory是Spring的心脏,那么ApplicationContext就是完整的躯体了,ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要以编程的方式实现,而在ApplicationContext中则可以通过配置实现。
  • BeanFactorty接口提供了配置框架及基本功能,但是无法支持spring的aop功能和web应用。而ApplicationContext接口作为BeanFactory的派生,因而提供BeanFactory所有的功能。

十、BeanFactory 和FactoryBean有什么区别?

我们之前(九)所讲的BeanFactoryApplicationContext的更具有可比性!它们都可以作为容器,并且ApplicationContext实现了BeanFactory的接口。

但是BeanFactoryFactoryBean两者除了名字像一点以外没有什么可比性!!!

非要说联系的话:

BeanFactory是一个工厂,也就是一个容器,是来管理和生产bean的;

FactoryBean是一个bean,但是它是一个特殊的bean,所以也是由BeanFactory来管理的, 它是一个接口,他必须被一个bean去实现

一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()返回的对象(工厂产生的对象),而不是A本身;如果要获取工厂A自身的实例,那么需要在名称前面加上'&'符号。

简单的说就是:

getObject(' name ')返回工厂中的实例
getObject(' &name ')返回工厂本身的实例

十一、Spring IOC容器的加载过程(超重点!!!)

从概念态到定义态的过程

1、实例化一个ApplicationContext的对象;

2:调用bean工厂后置处理器(invokeBeanFactoryPostProcessors)完成扫描;

3:循环解析扫描出来的类信息(扫描所有.class类,看看类上面有没有@Component,有就注册为BeanDefinition

4、实例化一个BeanDefinition对象来存储解析出来的信息;

5、把实例化好的beanDefinition对象putbeanDefinitionMap当中缓存起来, 以便后面实例化bean;

6、再次调用其他bean工厂后置处理器

从定义态到纯净态(还没有依赖注入)

7:当然spring还会干很多事情,比如国际化,比如注册BeanPostProcessor等等,如果我们只关心如何实例化一个bean的话那么这一步就是spring调用 finishBeanFactoryInitialization方法来实例化单例的bean,实例化之前spring要做验证, 需要遍历所有扫描出来的类,依次判断这个bean是否Lazy,是否prototype,是否 abstract等等;(单例、不是懒加载、不是抽象才会加载)

8:如果验证完成spring在实例化一个bean之前需要推断构造方法,因为spring实例化对象是通过构造方法反射,故而需要知道用哪个构造方法;

9:推断完构造方法之后spring调用构造方法反射实例化一个对象;注意这个时候对象已经实例化出来了,但是并不是一个完整的bean, 最简单的体现是这个时候实例化出来的对象属性是没有注入,所以不是一个完整的bean;

从纯净态到成熟态

10:spring处理合并后的beanDefinition

11:判断是否需要完成属性注入

12:如果需要完成属性注入,则开始注入属性初始化

13、判断bean的类型回调Aware接口

14、调用生命周期回调方法

15、如果需要代理则完成代理

创建完成

16、put到单例池——bean完成——存在spring容器当中 

posted @   金鳞踏雨  阅读(83)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示