IOC是用爲用戶建立、管理實例對象的。用戶須要實例對象時只須要向IOC容器獲取就好了,不用本身去建立,從而達到與具體類解耦。 php
簡單點來說就是Spring IOC就是一個Map集合,對象的名字就是集合中的key,值就是對應的對象。咱們能夠經過一個對象的名字到集合中獲取對象。java
Spring提供了多種方式來配置Bean定義,有Xml,JavaConfigspring
Xml:設計模式
<bean id="user" class="com.ranger.bean.User">
<constructor-arg type="String" value="ranger"></constructor-arg>
<constructor-arg ref="cbean"></constructor-arg>
</bean>
<bean id="car" class="com.ranger.bean.Car">
<constructor-arg type="String" value="mazda"></constructor-arg>
</bean>
複製代碼
JavaConfig的方法,這種方式要和註解配合app
@Configuration
public class AppConfig {
@Bean
public Service myService() {
return new ServiceImpl();
}
}
複製代碼
建立SpringIOC容器的時候指定一個配置文件(xml),或者指定包掃描的路徑(JavaConfig)ui
// 經過指定classpath下的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springcontext.xml");
複製代碼
或者使用JavaConfig的方式spa
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(AppConfig.class);
annotationConfigApplicationContext.refresh();
System.out.println(annotationConfigApplicationContext.getBean(User.class));
複製代碼
大概介紹每一個父接口對應的職責prototype
ApplicationContext中定義的方法線程
ApplicationContext中定義了本身的幾個方法,對這幾個方法作簡單的介紹:設計
咱們先從ApplicationContext後面的子孫開始
從上面的類繼承圖能夠看出,AbastractApplicationContext 後面有兩個兒子,分別是 GernericApplicationContext
和AbstractRefreshableApplicationContext
.這兩個大兒子分別都持有了BeanFactory實例,這兩個兒子全部的對於BeanDefiniton的註冊,Bean的實例化都是基於這個BeanFactory實例的
它們分紅了兩大派系:
AbstractRefreshableApplicationContext:這個類在每次調用refresh方法的時候都會產生一個新的beanfactory實例(一般是,可是不是必須的)。這個應用上下文會經過一系列的配置文件去加載BeanDefinition。在調用refresh方法的時候纔會建立內部持有的BeanFacoty實例(能夠參見該類中的refreshBeanFactory方法)
GenericApplicationContext:這個類內部持有惟一的一個DefaultListableBeanFactory實例,並且相較於其它ApplicationContext的實現類,這個類在建立的時候就會有一個BeanFactory的實例,意思就是在refresh方法調用前,內部持有的BeanFactory實例就已經建立,且這個類從開始到最終都是一個BeanFacoty實例。
GenericApplicationContext實現了BeanDefinitionRegistry這個接口,這個接口乾啥的呢,看名字是BeanDefinition的註冊什麼東東,沒錯,這個就是用來添加刪除BeanDefiniton的。GenericApplicationContext也還有幾個兒子,後面會簡單分析一下他們的不一樣。
上面都提到了refresh方法,這個方法是AbastractApplicationContext實現的,用於配置Context.該類使用了模板方法模式,不少方法都留給了子類去實現。
在AbstractApplicationContext中,實現了大多數ApplicationContext接口從BeanFactroy接口繼承來的方法。
咱們還能夠看到,AbstractApplicationContext的父類是ConfigurableApplicationContext,這個類提供了配置Context的方法,還提供了生命週期方法。
經過上面的分析咱們看到,雖然都有一個共同的祖先叫作ApplicationContext,可是不一樣的子孫仍是有不一樣的加載BeanDefinition的方法,可是其它方面都是同樣的,SpringIOC中最重要的方法refresh就在他們共同的老爸AbstractApplicationContext中。refresh方法會根據BeanDefinition來建立Bean對象(除開lazy loading)
咱們就從咱們常見的ClasspathXmlApplicationContext開始分析:
如今項目中包含上面圖中的類和配置,咱們編寫一個主方法:
public class Application {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springcontext.xml");
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
}
}
複製代碼
springcontext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init="true" default-init-method="" default-destroy-method="">
<bean id="car" class="com.ranger.spring.ioc.bean.Car">
<constructor-arg name="brand" value="mazda"></constructor-arg>
</bean>
<bean id="person" class="com.ranger.spring.ioc.bean.Person">
<property name="car" ref="car"></property>
</bean>
</beans>
複製代碼
調試啓動Application類的main方法
由於最終BeanDefinition的註冊都是在DefaultListableBeanFactory 中完成的,因此在registerBeanDefinition(String beanName, BeanDefinition beanDefinition)打斷點就能看到下面的調用棧
從線程調用棧的下面向上看。
獲得一個基本的流程:
這裏面的解析Document獲取BeanDefinition也比較複雜,若是有興趣能夠去看看。
那麼GenericXmlApplicationContext加載BeanDefinition的流程是否是也和上面同樣呢。
能夠看到流程是同樣的。
只是GenericXmlApplicationContext會先調用load來加載BeanDefinition,而後調用refresh完成配置。
而ClasspathXmlApplicationContext會在refresh方法調用的時候完成BeanDefinition的加載。
經過前面的分析咱們能夠看到,ApplicationContext的大部分操做其實都是基於DefaultListableBeanFactory來完成的。
DefaultListableBeanFactory是BeanFactory的一個實現類
如今咱們來認識一下它:
經過讀源碼的doc,
這個接口是spring bean容器的根接口,它有一些爲了提供特定功能的子接口ListableBeanFactory和ConfigurableBeanFactory
實現這個接口的對象持有一系列的 bean definitions,每一個bean definition 都有一個惟一的字符串名字。返回的Bean能夠是單例的,也能夠是獨立的(每次都要建立),具體返回什麼類型取決於applicationcontext的配置。
BeanFactory經過依賴注入來完成配置,一般的手段是用setter或者constructor
一般狀況BeanFactory加載的BeanDefinition保存在一個配置資源中,好比XML文件。可是具體存儲在哪兒是沒有限制的,好比LDAP,XML,properties等等。
HierarchicalBeanFactory會先從本上下文找,找不到從父BeanFactory找,且本工廠實例中的bean會覆蓋父工廠
BeanFactory的實現類應該儘量支持bean的生命週期方法,好比BeanNameAware,BeanClassLoaderAware,等等。
對於這些生命週期方法的支持,BeanFacoty沒有給出抽象的接口,須要實現類本身去實現
BeanFactory的源碼:
public interface BeanFactory {
// 用來區分FactoryBean和其產生的對象
String FACTORY_BEAN_PREFIX = "&";
// 經過BeanName獲取Bean
Object getBean(String name) throws BeansException;
// 經過beanName和bean 的Class類型來獲取Bean
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
// 增長獲取bean的參數
Object getBean(String name, Object... args) throws BeansException;
// 經過類型獲取
<T> T getBean(Class<T> requiredType) throws BeansException;
// 和上面同樣的道理
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 判斷是否包含某個Bean
boolean containsBean(String name);
// bean是不是單例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// bean是不是prototype
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//查詢指定了名字的Bean的Class類型是否與指定類型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
// 同上
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
//獲取指定名字bean的Class類型
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 獲取bean的別名
String[] getAliases(String name);
}
複製代碼
BeanFactory 有三個子類接口:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory,還有一個實現類SimpleJndiBeanFactory。
這裏對於BeanFactory的體系介紹就先不說了,太多了,單獨寫吧。
ApplicationContext的體系很大,重要抓住了核心幾個比較重要的幾個類:AbstractApplicationContext
,以及它的兩個大兒子 GenericApplicationContext
和AbstractRefreshableApplicationContext
。大部分功能都在這裏面實現了。
兩個大兒子生下的兒子都是基於他們作了一些擴展。
閱讀代碼能夠發現,ApplicationContext不少的方法都留到了子類去實現,這裏用到了模板方法設計模式。
最終對於註冊BeanDefinition和基於BeanDefinition建立bean實例都是歸結到了DefaultListableBeanFactory中。
前面對Spring容器的體系作了總體的瞭解,接下來會分析bean的建立。