欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot?ApplicationContext接口深入分析

 更新時間:2022年11月18日 09:02:40   作者:氵奄不死的魚  
ApplicationContext是Spring應用程序中的中央接口,由于繼承了多個組件,使得ApplicationContext擁有了許多Spring的核心功能,如獲取bean組件,注冊監(jiān)聽事件,加載資源文件等

ApplicationContext簡述

ApplicationContext代表IOC容器,在SpringIOC容器中讀取Bean配置創(chuàng)建Bean實例之前,必須對它進行實例化,只有在容器實例化后才可以從IOC容器里獲取Bean實例并使用。

Spring IOC容器實現(xiàn)方式

Spring 提供了兩種類型的IOC容器實現(xiàn):

  • BeanFactory:IOC容器的基本實現(xiàn)。
  • ApplicationContext:提供了更多的高級特性,是BeanFactory的子接口。

兩種方式比較:

  • BeanFactory:BeanFactory是Spring框架的基礎設施,面向Spring本身
  • ApplicationContext : 面向使用Spring框架的開發(fā)者,**幾乎所有的應用場合都直接使用ApplicationContext而非底層的BeanFactory。**無論使用何種方式,配置文件是相同的。

ApplicationContext接口梳理

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

根據(jù)不同的環(huán)境創(chuàng)建不同的ApplicationContext實現(xiàn)

這里看一個基礎的實現(xiàn)

AnnotationConfigApplicationContext

類圖分析

根據(jù)類圖看,ApplicationContext也是一個bean工廠的實現(xiàn),繼承自ResourceLoader也說明其具備加載文件,掃描bean的能力。ApplicationEventPublisher事件發(fā)布的能力

  • BeanFactory:Spring 管理 Bean 的頂層接口,ApplicationContext 繼承了 BeanFactory 的兩個子類:HierarchicalBeanFactory 和 ListableBeanFactory。HierarchicalBeanFactory 是一個具有層級關系的 BeanFactory,擁有屬性 parentBeanFactory。 ListableBeanFactory 實現(xiàn)了枚舉方法可以列舉出當前 BeanFactory 中所有的 bean 對象而不必根據(jù) name 一個一個的獲取。
  • ApplicationEventPublisher:用于封裝事件發(fā)布功能的接口,向事件監(jiān)聽器(Listener)發(fā)送事件消息。
  • ResourceLoader:Spring 加載資源的頂層接口,用于加載資源文件。ApplicationContext 繼承 ResourceLoader 的子類 ResourcePatternResolver,該接口是將 location 解析為 Resource 對象的策略接口。
  • MessageSource :解析 message 的策略接口,用于支撐國際化等功能。
  • EnvironmentCapable :用于獲取 Environment 的接口。

下面就這些接口來一一分析

MessageSource

MessageSource 定義了獲取 message 的策略方法 getMessage(),在 ApplicationContext 體系中,該方法 AbstractApplicationContext 實現(xiàn),在 AbstractApplicationContext 中,它持有一個 MessageSource 實例,將 getMessage() 的實現(xiàn)給該實例來實現(xiàn),如下:

private MessageSource messageSource;
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
    return this.getMessageSource().getMessage(resolvable, locale);
}
private MessageSource getMessageSource() throws IllegalStateException {
    if (this.messageSource == null) {
        throw new IllegalStateException("MessageSource not initialized - call 'refresh' before accessing messages via the context: " + this);
    } else {
        return this.messageSource;
    }
}

此外還有一個 initMessageSource()方法,在 refresh()中被調用,用來初始化一些國際化的屬性。

protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
    if (beanFactory.containsLocalBean("messageSource")) {
        this.messageSource = (MessageSource)beanFactory.getBean("messageSource", MessageSource.class);
        if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
            HierarchicalMessageSource hms = (HierarchicalMessageSource)this.messageSource;
            if (hms.getParentMessageSource() == null) {
                hms.setParentMessageSource(this.getInternalParentMessageSource());
            }
        }
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Using MessageSource [" + this.messageSource + "]");
        }
    } else {
        DelegatingMessageSource dms = new DelegatingMessageSource();
        dms.setParentMessageSource(this.getInternalParentMessageSource());
        this.messageSource = dms;
        beanFactory.registerSingleton("messageSource", this.messageSource);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("No 'messageSource' bean, using [" + this.messageSource + "]");
        }
    }
}

什么是國際化?

當我們web項目涉及到國外部署或者國外用戶使用時,需要展示不同語言信息,所以就需要國際化支持,下面將講解Springboot國際化支持操作

例如拋異常,我門希望在不同的環(huán)境能夠顯示不同的報錯

修改Springboot application.yml配置

spring:
  messages:
    basename: i18n/messages #配置國際化資源文件路徑

創(chuàng)建國際化資源文件

messages.properties不帶后綴為默認語言資源

簡體中文 messages_zh_CN.properties

unknown.exception=未知異常,請聯(lián)系管理員!
user.login.notExists={0} 用戶不存在!

英文 messages_en_US.properties

unknown.exception=Unknown error,Please contact the administrator!
user.login.notExists={0} user not exists!

messages.properties文件內容就和簡體中文文件一致,如果未設置Locale參數(shù),默認就為該文件內容,此文件也可不用

unknown.exception=未知異常,請聯(lián)系管理員!
user.login.notExists={0} 用戶不存在!

獲取錯誤信息通過messageSource獲取

public class MessageUtils {
	/**
	 * 根據(jù)消息鍵和參數(shù) 獲取消息 委托給spring messageSource
	 * @param code 消息鍵
	 * @param args 參數(shù)
	 * @return 獲取國際化翻譯值
	 */
	public static String message(String code, Object... args) {
		MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
		return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
	}
}

ApplicationEventPublisher

用于封裝事件發(fā)布功能的接口,向事件監(jiān)聽器(Listener)發(fā)送事件消息。

該接口提供了一個 publishEvent() 用于通知在此應用程序中注冊的所有的監(jiān)聽器。該方法在 AbstractApplicationContext 中實現(xiàn)。

public void publishEvent(ApplicationEvent event) {
    this.publishEvent(event, (ResolvableType)null);
}
public void publishEvent(Object event) {
    this.publishEvent(event, (ResolvableType)null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    Object applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent)event;
    } else {
        applicationEvent = new PayloadApplicationEvent(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
        }
    }
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    } else {
        this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
    }
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
        } else {
            this.parent.publishEvent(event);
        }
    }
}

根據(jù)不同的事件類型觸發(fā)對應的監(jiān)聽器,并且會觸發(fā)父容器的發(fā)布發(fā)布事件

ResourcePatternResolver

ResourcePatternResolver 接口繼承 ResourceLoader 接口,為將 location 解析為 Resource 對象的策略接口。它提供的 getResources() 在 AbstractApplicationContext 中實現(xiàn),在 AbstractApplicationContext 中它持有一個 ResourcePatternResolver 的實例對象。 其定義如下:

public Resource[] getResources(String locationPattern) throws IOException {
    return this.resourcePatternResolver.getResources(locationPattern);
}

該方法的具體實現(xiàn)在 PathMatchingResourcePatternResolve

ResourcePatternResolver 在 ResourceLoader 的基礎上增加了 getResources(String locationPattern),以支持根據(jù)路徑匹配模式返回多個 Resource 實例,同時也新增了一種新的協(xié)議前綴 classpath*:,該協(xié)議前綴由其子類負責實現(xiàn)。

PathMatchingResourcePatternResolver 為 ResourcePatternResolver 最常用的子類,它除了支持 ResourceLoader 和 ResourcePatternResolver 新增的 classpath*: 前綴外,還支持 Ant 風格的路徑匹配模式(類似于 **/*.xml)。

EnvironmentCapable

提供當前系統(tǒng)環(huán)境 Environment 組件。提供了一個 getEnvironment() 用于返回 Environment 實例對象,該方法在 AbstractApplicationContext 實現(xiàn)。

public ConfigurableEnvironment getEnvironment() {
    if (this.environment == null) {
        this.environment = this.createEnvironment();
    }
    return this.environment;
}

如果持有的 environment 實例對象為空,則調用 createEnvironment() 創(chuàng)建一個。

 protected ConfigurableEnvironment createEnvironment() {
  return new StandardEnvironment();
 }

StandardEnvironment 是一個適用于非 WEB 應用的 Environment。

Lifecycle

一個用于管理聲明周期的接口。

在 AbstractApplicationContext 中存在一個 LifecycleProcessor 類型的實例對象 lifecycleProcessor,AbstractApplicationContext 中關于 Lifecycle 接口的實現(xiàn)都是委托給 lifecycleProcessor 實現(xiàn)的。如下:

public void start() {
    this.getLifecycleProcessor().start();
    this.publishEvent((ApplicationEvent)(new ContextStartedEvent(this)));
}
public void stop() {
    this.getLifecycleProcessor().stop();
    this.publishEvent((ApplicationEvent)(new ContextStoppedEvent(this)));
}
public boolean isRunning() {
    return this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning();
}

在啟動、停止的時候會分別發(fā)布 ContextStartedEvent 和 ContextStoppedEvent 事件。

Closeable

Closeable 接口用于關閉和釋放資源,提供了 close() 以釋放對象所持有的資源。在 ApplicationContext 體系中由AbstractApplicationContext 實現(xiàn),用于關閉 ApplicationContext 銷毀所有 bean ,此外如果注冊有 JVM shutdown hook,同樣要將其移除。如下:

public void close() {
    synchronized(this.startupShutdownMonitor) {
        this.doClose();
        if (this.shutdownHook != null) {
            try {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
            } catch (IllegalStateException var4) {
            }
        }
    }
}

調用 doClose() 發(fā)布 ContextClosedEvent 事件,銷毀所有 bean(單例),關閉 BeanFactory 。如下:

protected void doClose() {
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Closing " + this);
        }
        LiveBeansView.unregisterApplicationContext(this);
        try {
            this.publishEvent((ApplicationEvent)(new ContextClosedEvent(this)));
        } catch (Throwable var3) {
            this.logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", var3);
        }
        if (this.lifecycleProcessor != null) {
            try {
                this.lifecycleProcessor.onClose();
            } catch (Throwable var2) {
                this.logger.warn("Exception thrown from LifecycleProcessor on context close", var2);
            }
        }
        this.destroyBeans();
        this.closeBeanFactory();
        this.onClose();
        if (this.earlyApplicationListeners != null) {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
        this.active.set(false);
    }
}

BeanFactory

applicationContext對beanFactory的實現(xiàn)實際上基本上都是通過成員變量來實現(xiàn)的DefaultListableBeanFactory

在applicationContext的實現(xiàn)GenericApplicationContext中

@Override
public void registerBeanDefinition(String beanName,BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName,beanDefinition);
}
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException{
this.beanFactory. removeBeanDefinition(beanName);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException{?
return this.beanFactory.getBeanDefinition(beanName);
}

總結

ApplicationContext集大成者

在實現(xiàn)對應接口功能時都是使用對應的實現(xiàn)類去做,而不是自己實現(xiàn),這點在ApplicationContext上十分常見,繼承自功能接口,這樣很容易看出ApplicationContext具備的功能,但是自身并不實現(xiàn),而調用對應的實現(xiàn)類。繼承了很多的功能。

ApplicaionContext創(chuàng)建

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

springBoot會創(chuàng)建一個ConfigurableApplicationContext

通過webApplicationType判斷創(chuàng)建什么類型的Context,如果是SERVLET那么實例化

AnnotationConfigServletWebServerApplicationContext,利用反射調用無參構造器進行實例化。

webApplicationType推斷方法

static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}

根據(jù)classPath下是對對應的類,來判斷類型

根據(jù)webApplicationType加載對應的類

調用其構造函數(shù)進行初始化我這里看AnnotationConfigApplicationContext的構造過程

接下來通過構造方法看ApplicationContext的創(chuàng)建的過程

AbstractApplicationContext

public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}
	protected ResourcePatternResolver getResourcePatternResolver() {
		return new PathMatchingResourcePatternResolver(this);
	}

PathMatchingResourcePatternResolver 為 ResourcePatternResolver 最常用的子類,它除了支持 ResourceLoader 和 ResourcePatternResolver 新增的 classpath*: 前綴外,還支持 Ant 風格的路徑匹配模式(類似于 **/*.xml)。用于掃描類路徑下的類

GenericApplicationContext

	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}

創(chuàng)建bean工廠,初始化一個空的bean工廠,后續(xù)注冊獲取bean都依靠這個bean工廠進行實現(xiàn)

AnnotationConfigApplicationContext

public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

構造函數(shù)中創(chuàng)建了AnnotatedBeanDefinitionReader和 ClassPathBeanDefinitionScanner

AnnotatedBeanDefinitionReader是一個根據(jù)指定類注冊BeanDefinnation的功能,同時能根據(jù)Condition跳過未達到條件的Bean

ClassPathBeanDefinitionScannery

BeanDeifination掃描類

繼承自RespourceAware和EnviromentCapable

設置environment

	private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		if (registry instanceof EnvironmentCapable) {
			return ((EnvironmentCapable) registry).getEnvironment();
		}
		return new StandardEnvironment();
	}

設置資源加載器resourceLoader通過資源加載,和環(huán)境完成bean的掃描

	@Override
	public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
		this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
		this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
		this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
	}

到此這篇關于SpringBoot ApplicationContext接口深入分析的文章就介紹到這了,更多相關SpringBoot ApplicationContext內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 新手小白入門必學JAVA面向對象之多態(tài)

    新手小白入門必學JAVA面向對象之多態(tài)

    說到多態(tài),一定離不開其它兩大特性:封裝和繼承,下面這篇文章主要給大家介紹了關于新手小白入門必學JAVA面向對象之多態(tài)的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • Java集合TreeSet用法詳解

    Java集合TreeSet用法詳解

    本文詳細講解了Java集合TreeSet用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • Java實現(xiàn)視頻自定義裁剪功能

    Java實現(xiàn)視頻自定義裁剪功能

    這篇文章主要介紹了如何通過java實現(xiàn)視頻裁剪,可以將視頻按照自定義尺寸進行裁剪,文中的示例代碼簡潔易懂,感興趣的可以了解一下
    2022-01-01
  • 如何給Cacheable的key加上常量

    如何給Cacheable的key加上常量

    這篇文章主要介紹了如何給Cacheable的key加上常量的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringCloud_Eureka服務注冊與發(fā)現(xiàn)基礎及構建步驟

    SpringCloud_Eureka服務注冊與發(fā)現(xiàn)基礎及構建步驟

    Eureka服務注冊中心,主要用于提供服務注冊功能,當微服務啟動時,會將自己的服務注冊到Eureka Server,這篇文章主要介紹了SpringCloud中Eureka的配置及詳細使用,需要的朋友可以參考下
    2023-01-01
  • Java實現(xiàn)Html轉Pdf的方法

    Java實現(xiàn)Html轉Pdf的方法

    這篇文章主要介紹了Java實現(xiàn)Html轉Pdf的方法,實例分析了java基于ITextRenderer類操作頁面及系統(tǒng)自帶字體生成pdf文件的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • SpringBoot統(tǒng)一處理功能實現(xiàn)的全過程

    SpringBoot統(tǒng)一處理功能實現(xiàn)的全過程

    最近在做項目時需要對異常進行全局統(tǒng)一處理,主要是一些分類入庫以及記錄日志等,下面這篇文章主要給大家介紹了關于SpringBoot統(tǒng)一功能處理實現(xiàn)的相關資料,文中通過圖文以及實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-03-03
  • 線程池之newFixedThreadPool定長線程池的實例

    線程池之newFixedThreadPool定長線程池的實例

    這篇文章主要介紹了線程池之newFixedThreadPool定長線程池的實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • SpringMVC視圖轉發(fā)重定向區(qū)別及控制器詳解

    SpringMVC視圖轉發(fā)重定向區(qū)別及控制器詳解

    這篇文章主要為大家介紹了SpringMVC視圖轉發(fā)重定向區(qū)別及控制器示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 詳解Springboot快速搭建跨域API接口的步驟(idea社區(qū)版2023.1.4+apache-maven-3.9.3-bin)

    詳解Springboot快速搭建跨域API接口的步驟(idea社區(qū)版2023.1.4+apache-maven-3.9.

    這篇文章主要介紹了Springboot快速搭建跨域API接口(idea社區(qū)版2023.1.4+apache-maven-3.9.3-bin),本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下
    2023-07-07

最新評論