Java——Spring的控制反转(一文详解IOC)

SpringSpring MVCSpring Boot 三者比较

答: 这三者专注的领域不同,解决的问题也不一样;总的来说,Spring 就像一个大家族,有众多衍生产品例如 BootSecurityJPA等等。但他们的基础都是 Spring IOC AOPIOC提供了依赖注入的容器,而AOP解决了面向切面的编程,然后在此两者的基础上实现了其他衍生产品的高级功能;Spring MVC是基于 Servlet 的一个 MVC 框架主要解决 WEB 开发的问题。与此同时, Spring 的配置非常复杂,各种xmlproperties处理起来比较繁琐。于是为了简化开发者的使用Spring社区创造性地推出了Spring Boot,它遵循约定优于配置,极大降低了Spring使用门槛,但又不失Spring原本灵活强大的功能,下面用一张图来描述三者的关系:

Java——Spring的控制反转(一文详解IOC)_第1张图片

最后一句话总结:Spring MVC Spring Boot 都属于 Spring Spring MVC 是基于 Spring 的一个 MVC 框架,而 Spring Boot 是基于 Spring 的一套快速开发整合包

1、什么是Spring IOC容器?

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

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

2、控制反转(IOC)有什么作用?

  • 管理对象的创建和依赖关系的维护: 对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的。
  • 解耦: 由容器去维护具体的对象。
  • 托管了类的产生过程: 比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的。

3、IOC的优点是什么?

  • IOC 或 依赖注入把应用的代码量降到最低
  • 它使应用容易测试,单元测试不再需要单例和JNDI查找机制。
  • 最小的代价和最小的侵入性使松散耦合得以实现。
  • IOC容器支持加载服务时的饿汉式初始化和懒加载

4、Spring IOC 的实现原理?

答: 工厂模式加反射机制。

interface Fruit {
   public abstract void eat();
}

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

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

class Factory {
    public static Fruit getInstance(String ClassName) {
        Fruit f = null;
        try {
            f = (Fruit)Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}

class Client {
    public static void main(String[] a) {
        Fruit f=Factory.getInstance("spring.Apple");
        if(f!=null){
          f.eat();
        }
    }
}

5、BeanFactoryApplicationContext有什么区别?

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

5.1、依赖关系

  • BeanFactory Spring里面最底层的接口,包含了各种Bean的定义,读取Bean配置文档,管理 Bean 的加载、实例化,维护 Bean 之间的依赖关系和控制 Bean 的生命周期,
  • ApplicationContext 该接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
    • 继承MessageSource,因此支持国际化。
    • 统一的资源文件访问方式。
    • 提供在监听器中注册Bean的事件。
    • 同时加载多个配置文件
    • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

5.2、加载方式

答:ApplicationContext相对于基本的BeanFactoryApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

  • BeanFactroy BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用 getBean() 方法才会抛出异常
  • ApplicationContext ApplicationContext是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例Bean,确保当你需要的时候,你就不用等待,因为它们已经创建好了。

5.3、创建方式

答: BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader

5.4、注册方式

答: BeanFactoryApplicationContext都支持 BeanPostProcessorBeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory 需要手动注册,而 ApplicationContext 则是自动注册

6、Spring 如何设计容器的,BeanFactoryApplicationContext的关系详解?Spring控制反转(IOC)

Spring作者 Rod Johnson 设计了两个接口用以表示容器。

  • BeanFactory
  • ApplicationContext
  1. BeanFactory简单粗暴,可以理解为就是个HashMapKey BeanName Value Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器
  2. ApplicationContext 可以称之为 “高级容器”。因为他比BeanFactory多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如JSP tag的支持),对BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是BeanFactory之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个 refresh ()方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 Bean
  3. 为了更直观的展示 “低级容器” 和 “高级容器” 的关系,这里通过常用的ClassPathXmlApplicationContext 类来展示整个容器的层级 UML 关系。

7、ApplicationContext通常的实现是什么?

  • FileSystemXmlApplicationContext 此容器从一个XML文件中加载Beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
  • ClassPathXmlApplicationContext 此容器也从一个XML文件中加载Beans的定义,这里,你需要 正确设置 classpath 因为这个容器将在classpath里找Bean配置。
  • WebXmlApplicationContext 此容器加载一个XML文件,此文件定义了一个WEB应用的所有Bean

8、什么是Spring的依赖注入?

答: 控制反转IOC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:依赖注入和依赖查找。面向接口编程中,让依赖注入只需要找到符合规范的接口注入即可实现调用者和被调用者解耦。对象的调用关系由Spring管理。

  • 依赖注入: 是指程序运行过程中,如果需要创建一个对象,无须再代码中new创建,而是依赖外部的注入Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对pojo之间依赖关系的管理;
  • new 对象: 类的头部进行实例化对象和依赖注入一个效果,这个时候该对象不管是否使用都贯穿该类的始终。该类对象不被回收,这个实例化对象也不会被回收。如果要使用多例对象则最好使用new创建对象而不是依赖注入,即使依赖注入有多例模式也不推荐。

9、依赖注入有什么优势?

答: 依赖注入之所以更流行是因为它是一种更可取的方式:让容器全权负责依赖查询,受管组件只需要暴露JavaBeanSetter方法或者带参数的构造器或者接口,使容器可以在初始化时组装对象的依赖关系。其与依赖查找方式相比,主要优势为:

  • 查找定位操作与应用代码完全无关。
  • 不依赖于容器的API,可以很容易地在任何容器以外使用应用对象。
  • 不需要特殊的接口,绝大多数对象可以做到完全不必依赖容器。

10、有哪些不同类型的依赖注入实现方式?

答: 依赖注入是时下最流行的IOC实现方式,依赖注入分为接口注入(Interface Injection)Setter方法注入(Setter Injection)和构造器注入(Constructor Injection)三种方式。其中接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃。

  • 构造器依赖注入: 构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
  • Setter 方法注入: Setter方法注入是容器通过调用无参构造器或无参 static 工厂方法实例化Bean之后,调用该Beansetter方法,即实现了基于setter的依赖注入。

构造器依赖注入和 Setter方法注入的区别

构造函数注入 setter注入
没有部分注入 有部分注入
不会覆盖setter属性 会覆盖setter属性
任意修改都会创建一个新实例 任意修改不会创建一个新实例
适用于设置很多属性 适用于设置少量属性

两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖, setter 方法实现可选依赖

11、Spring的循环依赖怎么理解?

答: 循环依赖是指在创建 Bean 的时候,两个为创建未完成的Bean 互相引用,形成循环。循环依赖分为三种:

  • 构造器的循环依赖: 这种依赖Spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常。
  • 单例模式下的 setter 循环依赖: 通过 “三级缓存” 处理循环依赖。
    • singletonObjects:一级缓存,用于保存实例化、注入、初始化完成的Bean实例;
    • earlySingletonObjects: 二级缓存,用于保存实例化完成的Bean实例;
    • singletonFactories:三级缓存,用于保存Bean创建工厂,以便于后面扩展有机会创建代理对象。
  • 非单例循环依赖: 无法处理。

Java——Spring的控制反转(一文详解IOC)_第2张图片

你可能感兴趣的:(Java,java,spring,log4j)