深入瞭解Spring控制反轉IOC原理

一、什麼是Spring IOC容器

Spring是包含眾多工具的IoC容器,控制反轉即IoC,它有兩個核心的功能:

①將對象(Bean)存儲在容器(Spring)

②將對象(Bean)從容器(Spring)中取出來

【擴展:將對象存放到容器中的好處】

將對象存儲在 IoC 容器相當於將以後可能⽤的所有工具制作好都放到倉庫中,需要的時候直接取就行瞭,用完再把它放回到倉庫。而new 對象的方式相當於,每次需要工具瞭,才現做,用完就扔掉瞭也不會保存,下次再用的時候還得重新做,這就是 IoC 容器和普通程序開發的區別

二、IOC有哪些優點

IOC 或 依賴註入把應用的代碼量降到最低

它使應用容易測試,單元測試不再需要單例和JNDI查找機制

最小的代價和最小的侵入性使松散耦合得以實現

IOC容器支持加載服務時的餓漢式初始化和懶加載

三、控制反轉(IOC)有什麼作用

將創建對象的控制權交給Spring的IoC,以前需要程序員自己控制對象創建,現在交給Spring的IoC創建,如果需要使用需要通過DI(依賴註入)@Autowired自動註入

解耦,由容器去維護具體的對象,降低耦合度

【擴展:什麼是解耦,代碼示例】

解耦指的是解決瞭代碼的耦合性,耦合性也可以換⼀種叫法叫程序相關性。這就好比我們打造⼀輛完整的汽車,如果所有的配件都是自己造,那麼當客戶需求發生改變的時候,比如輪胎的尺寸不再是原來的尺寸瞭,那我們要自己動手來改瞭,但如果我們是把輪胎外包出去,那麼即使是輪胎的尺寸發生變變瞭,我們隻需要向代理工廠下訂單就行瞭,我們自身身是不需要出力的

在傳統的代碼中對象創建順序是:Car -> Framework -> Bottom -> Tire

改進之後解耦的代碼的對象創建順序是:Tire -> Bottom -> Framework -> Car

public class IocCarExample {
   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.run();
  }
  //車類,把創建⼦類的⽅式,改為註⼊傳遞的⽅式
  static class Car {
    private Framework framework;
    public Car(Framework framework) {
      this.framework = framework;
    }
    public void run() {
      framework.init();
    }
  }
  //車身類
  static class Framework {
    private Bottom bottom;
    public Framework(Bottom bottom) {
      this.bottom = bottom;
    }
    public void init() {
    bottom.init();
    }
  }

四、IoC和DI有什麼區別

IoC:控制反轉,由主動new產生對象(耦合過高)轉換成從外部提供對象,就是將對象的創建控制權從程序轉移到瞭外部

DI:依賴註入,就是在程序運行期間,自動的將一個對象從Spring拿出來給當前類使用

區別:

IoC 是“目標”也是⼀種思想,而目標和思想隻是⼀種指導原則,而 DI 就是具體的實現

例如:比如說我今天心情比較好,吃⼀頓好的犒勞犒勞自己,那麼“吃⼀頓好的”是思想和目標(是 IoC),但最後我是吃海底撈,這就是具體的實現,就是 DI

五、Spring IoC的實現機制

1. 簡單工廠:通過一個方法傳入一個標識,生產對應對象

工廠模式案例:

public static void main(String[] arge){
  // 調用工廠方法,根據傳入參數,返回一個對象
  BaseService  userService = Factory.getBean("user");
}
class Factory{
  public static BaseService getBean(String beanName){
      if("user".equals(beanName)){
         return = new UserServiceImpl();
      }
      if("role".equals(beanName)){
         return = new RoleServiceImpl();
      }
   }
}

2.反射:反射就是在工廠模式getBean()方法中通過反射的方式來創建Bean

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;
    }
}

【擴展:反射是什麼,反射的實現原理】

反射機制是在運行的狀態,對於任何一個類,都能知道所有屬性和方法,對於任何一個對象都能調用任意方法屬性,所以反射就是將Java類的各種成分映射成一個個對象

①通過Class類的靜態方法:forName(String className)(常用)獲取Class對象

 try {
   Class stuClass3 = Class.forName("fanshe.Student");//註意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名
   System.out.println(stuClass3 == stuClass2);//判斷三種方式是否獲取的是同一個Class對象
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }

②通過反射獲取構造方法並使用:

public class Student {
  //---------------構造方法-------------------
 //(默認的構造方法)
 Student(String str){
  System.out.println("(默認)的構造方法 s = " + str);
 }
 //無參構造方法
 public Student(){
  System.out.println("調用瞭公有、無參構造方法執行瞭。。。");
 }
 
 //有一個參數的構造方法
 public Student(char name){
  System.out.println("姓名:" + name);
 }
 //有多個參數的構造方法
 public Student(String name ,int age){
  System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,以後解決。
 }
 //受保護的構造方法
 protected Student(boolean n){
  System.out.println("受保護的構造方法 n = " + n);
 }
 //私有構造方法
 private Student(int age){
  System.out.println("私有的構造方法   年齡:"+ age);
 }
 
}

六、IoC支持哪些功能

Spring 的 IoC 設計支持以下功能:

1.依賴註入

2.依賴檢查

3.自動裝配

4.支持集合

5.指定初始化方法和銷毀方法

6.支持回調某些方法(但是需要實現 Spring 接口,略有侵入)

其中,最重要的就是依賴註入,從 XML 的配置上說,即 ref 標簽。對應 Spring RuntimeBeanReference 對象。

對於 IoC 來說,最重要的就是容器。容器管理著 Bean 的生命周期,控制著 Bean 的依賴註入

【擴展:解釋Bean周期】下篇博客詳細介紹

七、BeanFactory和ApplicationContext有什麼區別

首先創建Spring上下文的時候,會使用BeanFactory和ApplicationContext兩種方法

//先得到Spring上下文
  ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");//配置文件對應
 // 先得到 spring 獲取 bean 的對象
  BeanFactory beanFactory =
                new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

共同點:BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當做Spring的容器。其中ApplicationContext是BeanFactory的子接口

區別:

①繼承關系和功能:ApplicationContext是BeanFactory的子類,BeanFactory隻是提供瞭基礎操作Bean的方法,ApplicationContext除瞭繼承瞭 BeanFactory 的所有功能之外,它還擁有獨特的特性,還添加瞭對國際化⽀持,資源訪問⽀持等

②性能:ApplicationContext 是⼀次性加載並初始化所有的 Bean 對象,而 BeanFactory是需要那個才去加載那個,因此更加輕量

八、ApplicationContext通常的實現是什麼

FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數

ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這裡,你需要正確設置classpath因為這個容器將在classpath裡找bean配置

WebXmlApplicationContext:此容器加載一個XML文件,此文件定義瞭一個WEB應用的所有bean

九、依賴註入的方式,構造器依賴註入和 Setter方法註入的區別

依賴註入是時下最流行的IoC實現方式,依賴註入分為接口註入,Setter方法註入,和構造器註入,三種方式。其中接口註入由於在靈活性和易用性比較差,現在從Spring4開始已被廢棄

1.構造器註入

將被依賴對象通過構造函數的參數註入給依賴對象,並且在初始化對象的時候註入。優點:對象初始化完成後便可獲得可使用的對象。

缺點:當需要註入的對象很多時,構造器參數列表將會很長;不夠靈活。若有多種註入方式,每種方式隻需註入指定幾個依賴,那麼就需要提供多個重載的構造函數,麻煩

2.setter方法註入

lOC Service Provider通過調用成員變量提供的setter函數將被依賴對象註入給依賴類優點:靈活,可以選擇性地註入需要的對象

缺點:依賴對象初始化完成後由於尚未註入被依賴對象,因此還不能使用

3.接口註入

依賴類必須要實現指定的接口,然後實現該接口中的一個函數,該函數就是用於依賴註入。該函數的參數就是要註入的對象

優點:接口註入中,接口的名字、函數的名字都不重要,隻要保證函數的參數是要註入的對象類型即可。缺點:侵入行太強,不建議使用

【擴展:什麼是侵入性?】

如果類A要使用月別人提供的一個功能,若為瞭使用這功能,需要在自己的類中增加額外的代碼,這就是侵入性

區別:

十、依賴註入的基本原則和優點

依賴註入的基本原則:

應用組件不應該負責查找資源或者其他依賴的協作對象。配置對象的工作應該由IoC容器負責,“查找資源”的邏輯應該從應用組件的代碼中抽取出來,交給IoC容器負責。容器全權負責組件的裝配,它會把符合依賴關系的對象通過屬性(JavaBean中的setter)或者是構造器傳遞給需要的對象

優勢:

①查找定位操作與應用代碼完全無關

②不依賴於容器的API,可以很容易地在任何容器以外使用應用對象

③不需要特殊的接口,絕大多數對象可以做到完全不必依賴容器

以上就是深入瞭解Spring控制反轉IOC原理的詳細內容,更多關於Spring控制反轉IOC的資料請關註WalkonNet其它相關文章!

推薦閱讀: