首先我以爲分析ApplicationContext必須從它的實現類開始進行分析,AbstractApplicationContext我以爲是一個不錯的選擇,那咱們就從這裏開始逐一分析吧,首先我本身手畫了一張圖,做爲索引吧,其中藍色的爲類,紫色的爲接口,箭頭 指向的方向是父類或者父接口。java
由於裏面接口和方法過多,因此不作展現,下面具體來進行代碼分析。首先咱們來看看這句話,MESSAGE_SOURCE_BEAN_NAME。數組
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
它這句話翻譯成中文就是消息資源的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的類結構圖:app
public StaticApplicationContext(@Nullable ApplicationContext parent) throws BeansException {
super(parent);
// Initialize and register a StaticMessageSource.
this.staticMessageSource = new StaticMessageSource();
getBeanFactory().registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.staticMessageSource);
}
咱們下面再來看一下AbstractApplicationContext這個類的一些Fields,而且來理清一下對象和對象之間的依賴關係,首先是parent -ApplicationContext,咱們找到是一個叫作getParent()的方法對這個私有的屬性進行了調用,而後又發現了getParentBeanFactory方法也對其進行了間接調用,由於BeanFactory是ApplicationContext的父接口,以下圖:ide
private ApplicationContext parent;
public ApplicationContext getParent() {
return this.parent;
}
public BeanFactory getParentBeanFactory() {
return getParent();
}
在這個類中還有一個屬性是environment,這個environment在這裏也有getter和setter方法,惟一須要注意的是若是調用getEnvironment()方法在environment爲空的狀況下會建立一個StandardEnvironment對象。post
private ConfigurableEnvironment environment;
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
StandardEnvironment類繼承了抽象的AbstractEnvironment,它的類結構圖以下所示:this
還有一個比較重要的屬性就是beanFactoryPostProcessors,這事一個ArrayList的數組,Doc當中給出的解釋是當onRefresh的時候有用到。我找到了3個方法引用到了這個屬性,下面都已標紅。spa
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
往下面看還有一個屬性active,它是線程安全的,用到了CAS技術。它經常和closed這個屬性一塊兒使用,咱們發現,在以下3個地方有組合引用,我已用相應的顏色標識出來。線程
private final AtomicBoolean active = new AtomicBoolean();
private final AtomicBoolean closed = new AtomicBoolean();
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
....................
....................
}
protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}
........................
........................
//Switch to inactive.
this.active.set(false);
}
protected void assertBeanFactoryActive() {
if (!this.active.get()) {
if (this.closed.get()) {
throw new IllegalStateException(getDisplayName() + " has been closed already");
}
else {
throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");
}
}
}
咱們繼續往下看,有一個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 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
}
}
}
}
時間不早了,今天就寫到這裏吧。