想想Spring框架是怎麼啟動一個IOC容器的,以下是一個例子:
ClassPathResource classPathResource = new ClassPathResource("bean.xml");DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);reader.loadBeanDefinitions(classPathResource);
這是最原始的方式,透過 ClassPathResource定位資源,建立一個BeanFactory的實現類物件,這裡用的是 DefaultListableBeanFactory。 然後建立一個XmlBeanDefinitionReader類的例項,把 DefaultListableBeanFactory物件傳進去,最終用 XmlBeanDefinitionReader物件的例項讀取xml檔案,載入BeanDefinitions,從而實現一個基礎的IOC容器的初始化。
Spring同時還提供了一些上下文的實現類,對基礎的IOC容器功能進行了一些擴充套件。並且使用上下文來初始化一個IOC容器是Spring更推薦的一種方式。它的實現過程類似這樣子的:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");Demo1 demo1 = (Demo1) context.getBean("demo");<br>
很短,初始化一個上下文環境就只有一行程式碼。ClassPathXmlApplicationContext內部對於IOC容器的初始化, 經過層層的包裝,最後在AbstractRefreshableApplicationContext的refreshBeanFactory()方法中建立了一個DefaultListableBeanFactory類的物件,用來初始化IOC容器。
可以看出,上下文初始化一個IOC容器的最核心的方法也是Spring框架的那套。
到了Spring MVC的時候,IOC容器是隨著WEB專案一起啟動的,這時候自然不再是手動去建立一個IOC容器了
web.xml檔案裡面有一個關於ContextLoaderListener的配置,這個配置就是Spring MVC中初始化IOC容器的地方,不過ContextLoaderListener沒有自己做初始化的事情。而是呼叫了父類ContextLoder來實現。
ContextLoder呼叫createWebApplicationContext,方法 createWebApplicationContext方法又調determineContextClass方法,最後determineContextClass從ContextLoader.properties中讀取了一個預設的ApplicationContext實現類作為IOC容器,這個實現類就是XmlWebApplicationContext
XmlWebApplicationContext裡面有一個loadBeanDefinitions方法,有一個入參,就是DefaultListableBeanFactory物件
所以,拐彎抹角半天,ContextLoaderListener類也是用DefaultListableBeanFactory來作為IOC容器物件的
Spring MVC裡面還有一個父子容器的概念。說的是ContextLoaderListener初始化好IOC容器以後,另外一個配置類DispatcherServlet還會建立一個上下文物件作為子容器,這個子容器持有父容器,然後管理者一些Spring MVC框架特有的Bean物件,例如HandlerMapping等。這裡不多說這個
到了Springboot的時候,專案的入口變成了Application.run()方法。這個方法經過層層呼叫,在最終執行的run方法裡面呼叫了一個方法,叫refreshContext(context); 這個方法可以一直斷點到SpringApplication類的refresh方法。
可以看到這裡需要一個ConfigurableApplicationContext物件。這個物件在run方法裡面的createApplicationContext()這個方法裡面建立的,在WEB環境下返回的是 AnnotationConfigServletWebServerApplicationContext物件,這個物件裡恰巧也有一個refresh方法。這個方法又經過層層呼叫,最後跑到GenericWebApplicationContext類裡。而這個類的其中一個建構函式,傳入的正好也是DefaultListableBeanFactory。
所以,在Springboot裡面,Run方法自己就能初始化一個IOC容器起來,當然也就沒有ContextLoaderListener什麼事了。