Spring IoC 概述
問題
1.什么是依賴倒置?
2.什么是控制反轉?
3.什么是依賴注入?
4.它們之間的關系是怎樣的?
5.優點有哪些?
依賴倒置原則 (Dependency Inversion Principle)
依賴倒置是一種設計原則。
依賴倒置包括三層含義:(1)高層模塊不應該直接依賴於底層模塊,兩者都應依賴其抽象;(2)抽象不應依賴於細節;(3)細節應該依賴於抽象。
控制反轉 (Inversion of Control)
控制反轉是一種思想。其核心思想在於,合作的對象依賴關系的管理不由具體對象來完成,而是具體對象交出依賴關系的控制權,由第三方容器來集中管理。
第三方容器管理的優點:(1)依賴關系的集中管理,關系清晰且易管理;(2)降低合作對象之間的耦合程度。
舉個栗子。我想在北京租一間房子,我只需要把我的需求告知鏈家等中介公司,通過他們整合的資源,我就能夠找到一間符合我需求的房子。我不需要與房東產生任何直接的關系,中間的任何問題都由鏈家進行統一處理。在這個例子中,房客與房東是兩個獨立的對象,而鏈家則是充當中間容器。
依賴注入(Dependency Inversion)
依賴注入是控制反轉的具體方法之一。依賴注入就是將底層依賴對象以參數形式傳入上層對象。
對象間的依賴關系的管理被反轉至IoC容器中。對象間的依賴關系由IoC容器進行統一管理,並由IoC容器來完成對象的注入。
依賴倒置原則 、控制反轉 、依賴注入的關系

優點
1.實現模塊間松耦合
2.由IoC容器來統一管理依賴關系,對象從復雜的依賴關系中解放。
3.對象自身弄夠專注於自身功能上,不需要了解依賴對象的內部結構。
IoC 容器

BeanFactory

BeanFactory提供最基本的IoC容器功能和基本規范。
BeanFactory中有getBean、getType、getAliases、isSingleton、isPrototype等函數。主要常用接口是getBean,改函數能夠通過Bean名稱獲取Bean
BeanFactory擴展接口:
(1)ListableBeanFactory:接口定義Bean的基本信息。
接口中函數有:getBeanDefinitionCount獲取Bean數量、containsBeanDefinition判斷容器中是否存在該Bean、getBeanDefinitionNames獲取工程所有Bean的名稱等。
(2)HierarchicalBeanFactory:父子容器關聯
接口中函數有:getParentBeanFactory子容器可以通過函數訪問到父容器
(3)ConfigurableBeanFactory:可定制IoC容器
接口中函數有:setBeanClassLoader設置Bean類加載器、setBeanExpressionResolver設置表達式解析器、registerCustomEditor注冊編輯器等。
(4)AutowireCapableBeanFactory:定義Bean自動裝配規則
接口中函數有:autowireBeanProperties根據名稱或屬性給Bean進行自動裝配等。
ApplicationContext

ApplicationContext基於BeanFactory,是比BeanFactory更為高級的容器。
ApplicationContext相對於BeanFactory提供更多功能,BeanFactory中需要通過編程實現的功能,ApplicationContext中可以使用配置來實現。
ApplicationContext繼承ListableBeanFactory、HierarchicalBeanFactory,除此之外還擴展了其他接口。
ApplicationContext擴展接口:
(1)ApplicationEventPublisher:封裝事件發布功能。
(2)MessageSource:提供i18n國際化消息剛問功能。(解釋模塊中解釋i18n)
(3)ResourcePatternResolver:通過路徑加載資源
(4)LifeCycle:start()、stop()、isRunning(),控制與判斷容器當前狀態,以達到控制與調度的作用。
(5)ConfigurableApplicationContext:實現ApplicationContext,新增refresh()、close(),使ApplicationContext具備啟動、刷新、關閉等功能。
IoC容器的依賴注入
基於注解定義Bean
Spring2.0開始Spring提供基於注解的依賴注入功能。使用xml進行配置使Bean定義信息與Bean實現代碼分離,這就會造成代碼復雜且易錯。基於注解就可以在Bean實現類上進行注解標注,這大大降低的代碼的復雜性。
定義Bean注解有以下4中:
(1)@Component:組件
(2)@Respository:對於Dao實現類進行標注
(3)@Service:對於Service實現類進行標注
(4)@Controller:對於Controller實現類進行標注
@Respository、@Service、@Controller是@Component的擴展,盡量使用3種特殊的注解,因為能夠標識出Bean的類型。
自動裝配
@Resource
resource是用J2EE提供的。
查找方式:
(1)按照指定name和type,容器中找到后對bean進行裝配,找不到拋出異常。
(2)按照指定name,容器中找到后對bean進行裝配,找不到拋出異常。
(3)按照指定type,容器中找到后對bean進行裝配,找不到或找到多個拋出異常。
(4)沒指定name和type,則先安裝name方式裝配,找不到這則按type進行裝配,都沒有拋異常。
@Autowired
autowired是spring提供的。
查找方式:
(1)按照類型查找,如果該類型bean不唯一則拋異常。
@Qualifier
查找方式:
(1)通過名稱指定Bean,同一個接口有多個實現,我們要裝配其中某一個Bean時,可以用qualifier通過名稱直接指定,一般結合Autowired一起使用。
基於Java類配置
@Bean
普通的POJO可以通過標注@Configuration注解,就可以為Spring容器提供Bean定義信息,標注了@Bean的類方法就相當於提供了Bean的定義信息。當第三方庫引入時,可以使用@Bean注解將Bean交由Spring容器進行管理。
@Configuration
public class AppConfig {
@Bean(name = "dataSource")
public DataSource initDataSource() {
return DataSourceBuilder.create().build();
}
}
相當於
<beans>
<bean id="dataSource" class="org.springframework.boot.jdbc.DataSourceBuilder"/>
</beans>
Bean的作用域
類型 | 說明 |
---|---|
singleton | IoC容器中僅存在一個Bean實例 |
prototype | 每次調用都會返回新的Bean實例 |
request | 每次Http請求都會創建一個Bean |
session | 同一個session共享Bean |
globalSession | 同一個全局Session共享一個Bean |
singleton

prototype

FactoryBean
解釋說明
FactoryBean是能夠生產和修飾對象生成的工廠Bean。Spring提供了org.springframework.beans.factory. FactoryBean
使用場景
(1)第三方框架提供的類,我們很難直接修改類代碼,為其添加@Service或@Componet時。
(2)當我們需要對第三方框架生成的實例進行修飾時。
應用案例
(1) mybatis-spring中org.mybatis.spring.SqlSessionFactoryBean
IoC容器內部關系

Bean配置信息配置了Bean的實現與依賴關系,容器將Bean配置信息注冊至注冊表中,然后根據注冊表加載與實例化,並建立Bean與Bean之間的依賴關系,最后將結果放置Bean緩存池中,供用應用程序調用。
JSR-250注釋
JSR-250注釋包括@PostConstruct,@PreDestroy,@Resource。@PostConstruct與@PreDestroy不用於依賴注入,用於標注對象生命周期的管理方法。
@Resource
@Resource與@Autowired的區別在上文已經講過就不再贅述。
@PostConstruct
如果想要在對象實例化后做一些准備工作,可以使用@PostConstruct。
@Resource
private ADRFingerprintBuilder adrFingerprintBuilder;
@Resource
private IOSFingerprintBuilder iosFingerprintBuilder;
@Resource
private List<ADRChecker> adrCheckers;
@Resource
private List<IOSChecker> iosCheckers;
private static Map<String, EventTemplate> event = new HashMap<>();
@PostConstruct
public void buildEventMap() {
event.put(ClientSourceEnum.ADR.getSource(), EventTemplate.builder().builder(adrFingerprintBuilder).checkers(adrCheckers).build());
event.put(ClientSourceEnum.IOS.getSource(), EventTemplate.builder().builder(iosFingerprintBuilder).checkers(iosCheckers).build());
}
在完成實例化后,將實例放入map中,為后續操作做准備工作。
@PreDestroy
在對象銷毀之前調用方法關閉資源或其他動作可以使用@PreDestroy。
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
解釋
- i18n:國際化信息也稱為本地化信息 。 Java 通過 java.util.Locale 類來表示本地化對象,它通過 “語言類型” 和 “國家/地區” 來創建一個確定的本地化對象。比如在發送一個具體的請求的時候,在header中設置一個鍵值對:"Accept-Language":"zh",通過Accept-Language對應值,服務器就可以決定使用哪一個區域的語言,找到相應的資源文件,格式化處理,然后返回給客戶端。
參考
[1]https://www.jianshu.com/p/6f0a59623090
[2]https://www.cnblogs.com/hujunzheng/p/11037577.html
[3]《精通Spring4.x企業應用開發實戰》
[4]《Spring揭秘》