文章部分圖片來自參考資料,本文介紹的是 Spring 的兩個重要概念,是學習總結。 html
咱們依舊提出幾個問題,幫助咱們在學習中帶着問題解答。 java
問題 : spring
他們的關係以下圖所示。api
上圖咱們能夠得出 : app
控制反轉是目的,而依賴注入是實現控制反轉的手段。框架
理解這一點很重要。要始終記得控制反轉這個思路是咱們要追求的目的。ide
用通俗的語言來解釋控制反轉能夠參考下面幾篇文章 : 學習
經過前面四篇文章的閱讀能夠了解到控制反轉的概念和能夠解決到的問題, 咱們下面再來總結一下幾個知識點 。ui
IoC 主要的做用就是解耦各個組件,讓高層模塊不依賴底層模塊,而是讓二者依賴接口和抽象來實現。this
ioc的思想最核心的地方在於,資源不禁使用資源的雙方管理,而由不使用資源的第三方管理,這能夠帶來不少好處。
1. 資源集中管理,實現資源的可配置和易管理。
2. 下降了使用資源雙方的依賴程度,也就是咱們說的耦合度
而IoC Container (控制反轉容器)是經過維護一個configuration 文件初始化Bean對象的容器,它的好處 :
依賴注入的主要做用是配置和管理咱們的應用對象,依賴注入的方式有 :
bean 在Ioc Container 中,那麼容器中如何注入和管理的又是誰?咱們又是如何從容器中獲取出來bean的呢?容器的管理者正是 BeanFactory ,而獲取管理的bean天然須要一個上下文對象 : ApplicationContext
下面將會介紹BeanFactory和ApplicationContext這二者的知識點,並介紹了 FactoryBean
BeanFactory 和 ApplicationContext 二者都是接口,前者提供了一個高級的機制去管理任何類型的對象(bean);後者是 BeanFactory的子接口,它增長多瞭如下功能 :
• 更輕鬆地與Spring的AOP功能集成
• 消息資源處理(用於國際化)
• 事件發佈
• 特定於應用程序層次的上下文,例如WebApplicationContext,用於Web應用程序
下面這一段這是關於 BeanFactory的介紹。
The
BeanFactory
API provides the underlying basis for Spring’s IoC functionality. Its specific contracts are mostly used in integration with other parts of Spring and related third-party frameworks, and itsDefaultListableBeanFactory
implementation is a key delegate within the higher-levelGenericApplicationContext
container.
BeanFactory
and related interfaces (such asBeanFactoryAware
,InitializingBean
,DisposableBean
) are important integration points for other framework components. By not requiring any annotations or even reflection, they allow for very efficient interaction between the container and its components.
總而言之,BeanFactory 提供了配置框架和基礎的功能,而 ApplicationContext 添加了更多與企業級別相關的功能,ApplicationContext 是BeanFactory 的全子集,提供了不少 BeanFactory 所不及的功能。下圖列舉了這兩種接口能夠完成的功能對比 :
Spring自帶了多種類型的應用上下文。 下面羅列的幾個是你最有可能遇到的。
這些都是 ApplicationContext 的子類,這些子類在不一樣場景發揮着做用。(從名字咱們就能夠判斷在哪些場景了)
FactoryBean 是個接口,它的做用是返回一些真實須要的bean,便是說某些bean並不能一步到位能夠注入到Container ,須要通過特殊的構造,它的常見的子類實現是 : ProxyFactoryBean 和 JndiRmiProxyFactoryBean 。 從它的子類,咱們就能夠知道FactoryBean 對於一些有特定要求的Bean 解決這一痛點發揮着做用。
public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
從上面的解釋中好難理解 FactoryBean 真實的做用是什麼(開始看到這個東西的時候)。推薦閱讀這兩篇資料 : fb_doc 和 what's the fb ,資料講到的 FactoryBean 的做用 :
A
FactoryBean
is a pattern to encapsulate interesting object construction logic in a class. It might be used, for example, to encode the construction of a complex object graph in a reusable way. Often this is used to construct complex objects that have many dependencies. It might also be used when the construction logic itself is highly volatile and depends on the configuration. AFactoryBean
is also useful to help Spring construct objects that it couldn’t easily construct itself. For example, in order to inject a reference to a bean that was obtained from JNDI, the reference must first be obtained. You can use theJndiFactoryBean
to obtain this reference in a consistent way. You may inject the result of aFactoryBean
’sgetObject()
method into any other property.
第二篇文章用到一個示例代碼,以下 :
public class Person { private Car car ; private void setCar(Car car){ this.car = car; } } public class MyCarFactoryBean implements FactoryBean<Car>{ private String make; private int year ; public void setMake(String m){ this.make =m ; } public void setYear(int y){ this.year = y; } public Car getObject(){ // wouldn't be a very useful FactoryBean // if we could simply instantiate the object! CarBuilder cb = CarBuilder.car(); if(year!=0) cb.setYear(this.year); if(StringUtils.hasText(this.make)) cb.setMake( this.make ); return cb.factory(); } public Class<Car> getObjectType() { return Car.class ; } public boolean isSingleton() { return false; } } <bean class = "a.b.c.MyCarFactoryBean" id = "car"> <property name = "make" value ="Honda"/> <property name = "year" value ="1984"/> </bean> <bean class = "a.b.c.Person" id = "josh"> <property name = "car" ref = "car"/> </bean> //或是 javaConfig 的形式 // identical configuration in Java to the XML above @Configuration public class CarConfiguration { @Bean public MyCarFactoryBean carFactoryBean(){ MyCarFactoryBean cfb = new MyCarFactoryBean(); cfb.setMake("Honda"); cfb.setYear(1984); return cfb; } @Bean public Person aPerson(){ Person person = new Person(); person.setCar( carFactoryBean().getObject()); return person; } }
上面的示例能夠看到,返回的bean 對象並非 FactoryBean ,而是通過「封裝」事後的對象,這正是FactoryBean 的做用。
FactoryBean 和其餘Spring Bean 同樣也是享有一樣的 lifecycle hooks 和 services(like AOP) ,因此當你想要在設置屬性以前,讓spring container 返回一個回調給你也是行的,只要繼承 InitializingBean 接口。詳細地見下面引用,來自第二篇推薦文章 :
Spring
FactoryBean
s have all the other characteristics of any other Spring bean, including the lifecycle hooks and services (like AOP) that all beans in the Spring container enjoy.So, if you’d like a chance to perform construction logic after the properties on the
FactoryBean
have been set, but before thegetObject()
method has been called, then you can tell the Spring container give yourFactoryBean
a callback. One way to do this is to implement theInitializingBean
interface. This will be called no matter what. A far more POJO-centric alternative is to annotate a method with@PostConstruct
. This method will be called, in this case, after both the code>make and theyear
properties have been set. You might use this callback to do sanity checks before the object construction’s finished, but after the configuration by the container has finished.
@PostConstruct public void setup() throws Throwable { // these methods throw an exception that // will arrest construction if the assertions aren't met Assert.notNull(this.make, "the 'make' must not be null") ; Assert.isTrue(this.year > 0, "the 'year' must be a valid value"); }