最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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框架的基礎(chǔ)設(shè)施,面向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)

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

AnnotationConfigApplicationContext

類圖分析

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

  • BeanFactory:Spring 管理 Bean 的頂層接口,ApplicationContext 繼承了 BeanFactory 的兩個子類:HierarchicalBeanFactory 和 ListableBeanFactory。HierarchicalBeanFactory 是一個具有層級關(guān)系的 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()中被調(diào)用,用來初始化一些國際化的屬性。

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文件內(nèi)容就和簡體中文文件一致,如果未設(shè)置Locale參數(shù),默認就為該文件內(nèi)容,此文件也可不用

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 的基礎(chǔ)上增加了 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 實例對象為空,則調(diào)用 createEnvironment() 創(chuàng)建一個。

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

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

Lifecycle

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

在 AbstractApplicationContext 中存在一個 LifecycleProcessor 類型的實例對象 lifecycleProcessor,AbstractApplicationContext 中關(guān)于 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 接口用于關(guān)閉和釋放資源,提供了 close() 以釋放對象所持有的資源。在 ApplicationContext 體系中由AbstractApplicationContext 實現(xiàn),用于關(guā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) {
            }
        }
    }
}

調(diào)用 doClose() 發(fā)布 ContextClosedEvent 事件,銷毀所有 bean(單例),關(guān)閉 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);
}

總結(jié)

ApplicationContext集大成者

在實現(xiàn)對應接口功能時都是使用對應的實現(xiàn)類去做,而不是自己實現(xiàn),這點在ApplicationContext上十分常見,繼承自功能接口,這樣很容易看出ApplicationContext具備的功能,但是自身并不實現(xiàn),而調(diào)用對應的實現(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,利用反射調(diào)用無參構(gòu)造器進行實例化。

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加載對應的類

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

接下來通過構(gòu)造方法看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);
	}

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

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

ClassPathBeanDefinitionScannery

BeanDeifination掃描類

繼承自RespourceAware和EnviromentCapable

設(shè)置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();
	}

設(shè)置資源加載器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());
	}

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

相關(guān)文章

  • Java使用動態(tài)規(guī)劃算法思想解決背包問題

    Java使用動態(tài)規(guī)劃算法思想解決背包問題

    背包問題(Knapsack problem)是一種組合優(yōu)化的NP完全問題。問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內(nèi),我們?nèi)绾芜x擇,才能使得物品的總價格最高
    2022-04-04
  • maven中的scope與systemPath用法

    maven中的scope與systemPath用法

    這篇文章主要介紹了maven中的scope與systemPath用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • java中DateUtils時間工具類詳解

    java中DateUtils時間工具類詳解

    這篇文章主要為大家詳細介紹了java中DateUtils時間工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • java實現(xiàn)從方法返回多個值功能示例

    java實現(xiàn)從方法返回多個值功能示例

    這篇文章主要介紹了java實現(xiàn)從方法返回多個值功能,結(jié)合實例形式分析了集合類、封裝對象、引用傳遞三種實現(xiàn)方法,需要的朋友可以參考下
    2017-10-10
  • Java找不到或無法加載主類及編碼錯誤問題的解決方案

    Java找不到或無法加載主類及編碼錯誤問題的解決方案

    今天小編就為大家分享一篇關(guān)于Java找不到或無法加載主類及編碼錯誤問題的解決方案,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • pdf2swf+flexpapers實現(xiàn)類似百度文庫pdf在線閱讀

    pdf2swf+flexpapers實現(xiàn)類似百度文庫pdf在線閱讀

    這篇文章主要介紹了pdf2swf+flexpapers實現(xiàn)類似百度文庫pdf在線閱讀的相關(guān)資料,需要的朋友可以參考下
    2014-10-10
  • CompletableFuture?異步編排示例詳解

    CompletableFuture?異步編排示例詳解

    這篇文章主要為大家介紹了CompletableFuture?異步編排示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • ElasticSearch自定義注解增刪改方式

    ElasticSearch自定義注解增刪改方式

    這篇文章主要介紹了ElasticSearch自定義注解增刪改方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • java 獲取已知文件擴展名的代碼

    java 獲取已知文件擴展名的代碼

    java 編寫程序獲取已知文件的擴展名. 注意: abc.txt的擴展名是txt, abc.java.txt的擴展名也是txt.,需要的朋友可以參考下
    2017-02-02
  • Java Spring注解之@Async的基本用法和示例

    Java Spring注解之@Async的基本用法和示例

    Spring為任務(wù)調(diào)度與異步方法執(zhí)行提供了注解支持,通過在方法上設(shè)置@Async注解,可使得方法被異步調(diào)用,下面這篇文章主要給大家介紹了關(guān)于Java Spring注解之@Async的基本用法和示例,需要的朋友可以參考下
    2022-03-03

最新評論

乐陵市| 日土县| 万山特区| 云霄县| 桂阳县| 来凤县| 高唐县| 莱州市| 怀宁县| 普洱| 剑川县| 崇阳县| 临泉县| 手游| 大名县| 买车| 安陆市| 合山市| 靖远县| 施秉县| 瓦房店市| 奎屯市| 岳阳市| 肇东市| 麻江县| 磐石市| 玉林市| 淮北市| 凭祥市| 托里县| 邳州市| 那坡县| 玛多县| 通河县| 石渠县| 嘉禾县| 延长县| 图们市| 醴陵市| 雅江县| 酒泉市|