(001)Spring 之 IOC及其容器

林灣村龍貓發表於2017-12-13

概述

Spring的最終模板是簡化應用開發的程式設計模型。spring用於替代更加重量級的企業級java技術,如EJB(Enterprise JavaBean)。

為了降低Java開發的複雜度。spring採取了以下4中關鍵策略:

  • 基於POJO(Plain Ordinary Java Objects,實際上就是普通的java類)的輕量級和最小侵入式程式設計。
  • 通過依賴注入(DI, Dependency Injection)和麵向介面程式設計實現鬆耦合。
  • 基於切面(AOP, Aspect Oriented Programming)和慣例(可以理解為預設配置、方式)進行宣告式程式設計。
  • 通過切面和模板減少重複程式碼。

ioc容器及其使用

他山之石

IOC容器存在價值

Java是一門物件導向程式語言。Java應用本質上是一個個物件及其關係的組合。舉個簡單的例子。

在傳統的人員招聘模式中,流程一般都是這樣:HR從多如海的應聘簡歷中挑選然後進行筆試、面試等等一系列篩選後發放offer。這一系列過程複雜而且費時,最關鍵的是結果還不理想,特別是針對某些特定的崗位很難通過這一模式物色到合適的人才資源。 (自己建立特定的物件,使用特定的物件)

後來逐漸出現了一些公司專門提供類似的人才尋訪服務,這就是大名鼎鼎的獵頭行業。獵頭的興起可以說很大程度上改變了人才招聘的模式,現在公司需要招聘某個職位的人才,只需要告訴獵頭我要一個怎樣的人幹怎樣的工作等等要求,獵頭就會通過自己的渠道去物色人才,經過篩選後提供給客戶,大大簡化了招聘過程的繁瑣,提高了招聘的質量和效率。(告訴中間人,中間人自動給你需要、合適的物件)

這其中一個很重要的變化就是公司HR將繁瑣的招聘尋訪人才的過程轉移至了第三方,也就是獵頭。相對比而言,IoC在這裡充當了獵頭的角色,開發者即公司HR,而物件的控制權就相當於人才尋訪過程中的一系列工作

一句話,在java中,將物件的建立與物件的使用分離開,通過依賴注入(DI)的方式達到物件控制反轉(IOC)的目的。原本需要自己做建立物件、維護各個物件關係,現在統一交給統一專業的人或服務處理。

建立物件等操作就是你對物件的控制權,把控制權交給三方,這就是 控制反轉(IOC) 的意思。

當需要某個物件的時候,三方將合適的物件給你,這個就是 依賴注入(DI) 的意思。

IOC具象化

關係

主要類或介面uml圖

IOC容器介面設計圖

ApplicationContext 擴充套件了BeanFactory後的結果,BeanFactory為bean物件的出生地。

BeanDefinition載入

定義一個bean物件長什麼樣子,在spring中叫BeanDefinition。如何初始化一個BeanDefinition,spring中常用三種方式定義:xml檔案、註解掃描、java程式碼.

載入BeanDefinition

bean的生命週期

spring中bean生命週期.png

Bean的完整生命週期經歷了各種方法呼叫,這些方法可以劃分為以下幾類:

  • Bean自身的方法:這個包括了Bean本身呼叫的方法和通過配置檔案中的init-method和destroy-method指定的方法。
  • Bean級生命週期介面方法:這個包括了BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean這些介面的方法
  • 容器級生命週期介面方法:這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個介面實現,一般稱它們的實現類為“後處理器”。
  • 工廠後處理器介面方法:這個包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工廠後處理器  介面的方法。工廠後處理器也是容器級的。在應用上下文裝配配置檔案之後立即呼叫。

舉例(通過註解與java程式碼定義bean)

  • 定義一個Animal介面。
  • 定義實現Animal介面的兩個動物Cat,Dog類;
  • 定義一個介面代理AnimalProxy。
  • 定義一個spring Bean java類

實現通過代理類完成不同操作。

1.Animal介面

package bean;

public interface Animal {

    public void sayName();
}
複製程式碼

2.Cat類

package bean;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Primary
@Component
public class Cat implements Animal {

    public void sayName() {
        System.out.println("this is cat");
    }
}
複製程式碼

3.Dog類

package bean;

import org.springframework.stereotype.Component;

@Component
public class Dog implements Animal {
    public void sayName() {
        System.out.println("this is dog");
    }
}
複製程式碼

4.AnimalProxy類

package bean;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class AnimalProxy implements Animal {

    @Autowired
    private Animal animal;

    public void sayName(){
        animal.sayName();
    }
}
複製程式碼

5. AnimalConfig(Bean定義類)

package bean;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * User: Rudy Tan
 * Date: 2017/11/24
 */
@Configuration
@ComponentScan
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AnimalConfig {
}
複製程式碼

6.測試類:

import bean.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AnimalConfig.class)
public class AppTest {

    @Autowired
    private AnimalProxy animalProxy;

    @Test
    public void testBeanLoad(){
        animalProxy.sayName();
    }
}
複製程式碼

說明:

  • 註解Component:指明該類為bean類
  • 註解Primary:指明當多個bean物件滿足獲取條件時候,該物件優選獲取。
  • 註解Configuration:指明該類為spring bean定義類。
  • 註解ComponentScan:開啟當前目錄下的bean註解掃描。
  • 註解EnableAspectJAutoProxy:啟用aspectJauto代理。
  • 註解Autowired:該屬性,spring自動載入。

總結,多人個人或多個類協助處理問題或實現某個功能,總得要找個領頭的來管理這些關係吧。

相關文章