javascript
Spring 源码分析之AbstractApplicationContext源码分析
首先我覺得分析ApplicationContext必須從它的實現類開始進行分析,AbstractApplicationContext我覺得是一個不錯的選擇,那我們就從這里開始逐一分析吧,首先我自己手畫了一張圖,作為索引吧,其中藍色的為類,紫色的為接口,箭頭 指向的方向是父類或者父接口。
因為里面接口和方法過多,所以不做展示,下面具體來進行代碼分析。首先我們來看看這句話,MESSAGE_SOURCE_BEAN_NAME。
它這句話翻譯成中文就是消息資源的bean的一個name,我們暫時把它看成一個普通的beanName,我們來看看有哪些地方引用到了這個屬性,首先在initMessageSource方法里面有引用到,我把這些地方標紅顯示了。
protected void initMessageSource() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);// Make MessageSource aware of parent MessageSource.if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;if (hms.getParentMessageSource() == null) {// Only set parent context as parent MessageSource if no parent MessageSource// registered already.hms.setParentMessageSource(getInternalParentMessageSource());}}if (logger.isTraceEnabled()) {logger.trace("Using MessageSource [" + this.messageSource + "]");}}else {// Use empty MessageSource to be able to accept getMessage calls.DelegatingMessageSource dms = new DelegatingMessageSource();dms.setParentMessageSource(getInternalParentMessageSource());this.messageSource = dms;beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);if (logger.isTraceEnabled()) {logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");}}}還有一個顯示的地方就是在StaticApplicationContext類中的構造器當中有使用到。下面是StaticApplicationContext的類結構圖:
我們下面再來看一下AbstractApplicationContext這個類的一些Fields,并且來理清一下對象和對象之間的依賴關系,首先是parent -ApplicationContext,我們找到是一個叫做getParent()的方法對這個私有的屬性進行了調用,然后又發現了getParentBeanFactory方法也對其進行了間接調用,因為BeanFactory是ApplicationContext的父接口,如下圖:
在這個類中還有一個屬性是environment,這個environment在這里也有getter和setter方法,唯一需要注意的是如果調用getEnvironment()方法在environment為空的情況下會創建一個StandardEnvironment對象。
private ConfigurableEnvironment environment; public ConfigurableEnvironment getEnvironment() {if (this.environment == null) {this.environment = createEnvironment();}return this.environment; }StandardEnvironment類繼承了抽象的AbstractEnvironment,它的類結構圖如下所示:
還有一個比較重要的屬性就是beanFactoryPostProcessors,這事一個ArrayList的數組,Doc當中給出的解釋是當onRefresh的時候有用到。我找到了3個方法引用到了這個屬性,下面都已標紅。
往下面看還有一個屬性active,它是線程安全的,用到了CAS技術。它常常和closed這個屬性一起使用,我們發現,在如下3個地方有組合引用,我已用相應的顏色標識出來。
prepareRefresh
doClose
assertBeanFactoryActive
我們繼續往下看,有一個startupShutdownMonitor的屬性,字面意思上面理解就是啟動關閉監視器,屬性在這個類當中的命名表示了它所發揮的作用,我們來看一下有哪些方法引用到了這個屬性。大家不知道發現沒有,還有一個“很像”的屬性在這里就是shutdownHook,這個和startupShutdownMonitor是配合在一起使用的。shudownHook在這里是一個線程類型的屬性。
private final Object startupShutdownMonitor = new Object(); private Thread shutdownHook; public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) {...... public void registerShutdownHook() { if (this.shutdownHook == null) { // No shutdown hook registered yet. this.shutdownHook = new Thread() { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); }} public void close() { synchronized (this.startupShutdownMonitor) { doClose(); // If we registered a JVM shutdown hook, we don't need it anymore now: // We've already explicitly closed the context. if (this.shutdownHook != null) { try { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); } catch (IllegalStateException ex) { // ignore - VM is already shutting down } } }}既然shutdownHook和startupShutdownMonitor一起使用,那么它們之間的關系我們得分析一下,hook顧名思義鉤子,說簡單點這個就是一個鉤子,也算是一個擴展點。我們來仔細分析一下它的幾個方法,首先是registerShutdownHook方法:這個方法有一句話特別重要,就是Runtime.getRuntime().addShutdownHook(this.shutdownHook);它實際上在系統層面上把鉤子線程添加到了JVM虛擬機。在鉤子運行的時候,就會執行doClose方法關閉并銷毀applicationContext。需要注意的一點是明白registerShutdownHook方法和close方法的不同點,在close方法中如果發現已經調用registerShutdownHook在JVM層面上注冊了鉤子,那么就調用Runtime.getRuntime().removeShutdownHook(this.shutdownHook)移除此鉤子,另外這個close的實現來自于closable接口的父接口AutoClosable接口方法,而registerShutdownHook則在PropertyResolver當中被定義。
public void <strong>registerShutdownHook</strong>() {if (this.shutdownHook == null) {// No shutdown hook registered yet.this.shutdownHook = new Thread() {@Overridepublic void run() {synchronized (startupShutdownMonitor) {doClose();}}};Runtime.getRuntime().addShutdownHook(this.shutdownHook);}}<br><br> public void close() {synchronized (this.startupShutdownMonitor) {doClose();// If we registered a JVM shutdown hook, we don't need it anymore now:// We've already explicitly closed the context.if (this.shutdownHook != null) {try {Runtime.getRuntime().removeShutdownHook(this.shutdownHook);}catch (IllegalStateException ex) {// ignore - VM is already shutting down}}} }總結
以上是生活随笔為你收集整理的Spring 源码分析之AbstractApplicationContext源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xpath中两个冒号_爬虫学习(5)—X
- 下一篇: 一些常用的IOS开发网站