此篇文章繼續(xù)解析SpringApplication的run
方法具體代碼如下:
public ConfigurableApplicationContext run(String... args) {
1.StopWatch stopWatch = new StopWatch();
2.stopWatch.start();
3.ConfigurableApplicationContext context = null;
4.Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
5.configureHeadlessProperty();
6.SpringApplicationRunListeners listeners = getRunListeners(args);
7.listeners.starting();
try {
8. ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
9. ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
10. configureIgnoreBeanInfo(environment);
11. Banner printedBanner = printBanner(environment);
12. context = createApplicationContext();
13. exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
14. prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
15. refreshContext(context);
16. afterRefresh(context, applicationArguments);
17. stopWatch.stop();
18. if (this.logStartupInfo) {
19. new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
20. listeners.started(context);
21. callRunners(context, applicationArguments);
}
catch (Throwable ex) {
22. handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
23. listeners.running(context);
}
catch (Throwable ex) {
24. handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
一共24行代碼誊锭,本章主要解析15小節(jié),其就是真正的把spring容器初始化的方法,基本上把spring容器的大部分功能都包含在內(nèi)
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
最終注冊方法就是這個doClose
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
卸載當(dāng)前的spring容器壁袄,包含卸載該spring容器相關(guān)的MBeanServer
LiveBeansView.unregisterApplicationContext(this);
try {
發(fā)布關(guān)閉事件
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
停止所有實現(xiàn)SmartLifecycle或者Lifecycle的bean出吹,lifecycleProcessor 就是
負(fù)責(zé)這些bean的聲明周期
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
摧毀容器中的所有單例bean
destroyBeans();
關(guān)閉bean工廠
closeBeanFactory();
關(guān)閉我們內(nèi)置的tomcat的容器
onClose();
設(shè)置未激活標(biāo)識
this.active.set(false);
}
refresh(context);
的詳細(xì)代碼如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
清除ClassPathBeanDefinitionScanner的緩存
設(shè)置servletContext和servletConfig耕陷,如果這個兩個屬性不為空則替換
environment的source中關(guān)于這個兩個的屬性
校驗必須存在的properties是否存在(我們可以設(shè)置哪些properties)
設(shè)置earlyApplicationEvents掂名,存儲早期的ApplicationEvents,當(dāng)所有的ApplicationContextListener都注冊進(jìn)入容器之后在執(zhí)行這些事件
prepareRefresh();
獲取beanFactory哟沫,還給其設(shè)置了refreshed標(biāo)識
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
準(zhǔn)備beanFactory饺蔑,在注冊bean之前先給beanFactory注冊一堆bean,這些bean可以
幫助beanFactory后期去解析嗜诀,注冊其他的bean猾警,比如忽略依賴,比如指定依賴
ignoreDependencyInterface:當(dāng)我們spring指定自動注入的時候會忽略對這個指定參數(shù)的EnvironmentAware的注入
registerResolvableDependency:當(dāng)我們spring指定自動注入的時候會只注入我們指定的參數(shù)屬性
prepareBeanFactory(beanFactory);
try {
設(shè)置ignoreDependencyInterface(ServletContextAware.class)隆敢,標(biāo)識對于ServletContextAware
的實現(xiàn)類中的ServletContextAware屬性禁止自動注入
如果存在basePackages和annotatedClasses发皿,則掃描basePackages,并把掃描到的class和annotatedClasses注冊到spring容器中
postProcessBeanFactory(beanFactory);
執(zhí)行beanFactory的PostProcessors
按照這個順序PriorityOrdered拂蝎,Ordered穴墅,nonOrdered
分別執(zhí)行BeanDefinitionRegistry的postProcessBeanDefinitionRegistry,
BeanFactoryPostProcessor的postProcessBeanFactory
alreadyCreated:這個集合存儲已經(jīng)初始化好的bean實例,
所以當(dāng)我們執(zhí)行完beanFactoryPostProcessor的方法時候 會清除未初始化的bean
也會清除allBeanNamesByType和singletonBeanNamesByType
invokeBeanFactoryPostProcessors(beanFactory);
注冊beanPostProcessor(會確保spring的internalPostProcessors)一定是排在beanPostProcessor的集合最后
registerBeanPostProcessors(beanFactory);
給spring的容器和其父容器設(shè)置messageSource
initMessageSource();
給spring的容器注冊一個事件廣播器applicationEventMulticaster
initApplicationEventMulticaster();
初始化tomcat
onRefresh();
注冊所有的ApplicationListener,并且執(zhí)行之前積攢的earlyApplicationEvents
registerListeners();
初始化所有非懶加載的單例bean
finishBeanFactoryInitialization(beanFactory);
清理resource的緩存玄货,初始化LifecycleProcessor用來執(zhí)行
lifeCycle的bean的onRefresh皇钞,
發(fā)布ContextRefreshedEvent,將該spring容器注冊到
LiveBeansView松捉,啟動tomcat發(fā)布tomcat啟動事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
每行代碼的意思都有英文解釋夹界,我們一行行來分析
prepareRefresh();
的詳細(xì)代碼如下:
protected void prepareRefresh() {
this.scanner.clearCache();
super.prepareRefresh();
}
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
第一步主要是父類AbstractApplicationContext的refresh方法(因為其子類AnnotationConfigServletWebServerApplicationContext 沒有實現(xiàn)該方法)
refresh:
- 該方法第一步調(diào)用子類的 prepareRefresh()方法
- 子類的prepareRefresh方法清除CachingMetadataReaderFactory中的緩存然后繼續(xù)調(diào)用父類的prepareRefresh方法
prepareRefresh: - 設(shè)置相關(guān)屬性 校驗environment的properties是否正確
- initPropertySources會調(diào)用GenericWebApplicationContext的實現(xiàn) 就是設(shè)置容器的環(huán)境初始化容器的屬性
- earlyApplicationEvents 是在multicaster 可用的時候進(jìn)行發(fā)布
obtainFreshBeanFactory()
的代碼如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
- 首先ConfigurableListableBeanFactory 是在初始化容器的時候其父類容器也被初始化了才賦值的
spring容器是通過ConfigurableListableBeanFactory 這個bean工廠進(jìn)行真正的bean加載
- 然后就是首先查看beanFactory是否已經(jīng)refresh過,如果是 就給容器一個id 同時返回容器
prepareBeanFactory(beanFactory);
的詳細(xì)代碼如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
- 上述代碼的作用如下:
- 設(shè)置beanFactory的classloader隘世,一般都是線程上下文類加載器
- 設(shè)置beanFactory的BeanExpressionResolver可柿,用來根據(jù)bean的表達(dá)式來解析bean
- 增加ResourceEditorRegistrar,主要是注冊用戶或者系統(tǒng)定義的屬性編輯器
- 添加BeanPostProcessor-ApplicationContextAwareProcessor
1.BeanPostProcessor 提供了2個方法
postProcessBeforeInitialization(該方法在調(diào)用bean的初始化方法(注意是初始化方法此時bean早已經(jīng)實例化好了))
postProcessAfterInitialization(該方法是在調(diào)用bean的初始化方法后進(jìn)行調(diào)用)
還需注意的是@service @component 都沒有初始化方法 但是@Bean注解有
還有需要注意的是若是上述2中方法對bean 進(jìn)行修改那么原始的bean就會被替換
而ApplicationContextAwareProcessor則是只修改postProcessBeforeInitialization丙者,
方法內(nèi)部就是判斷 bean是否屬于
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
不同的aware調(diào)用不同的方法
代碼細(xì)節(jié)如下:
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
而ignoreDependencyInterface 則是正好對應(yīng)著上述的
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
--ignoreDependencyInterface的真正意思是在自動裝配時忽略指定接口的實現(xiàn)類中复斥,對外的依賴。
如果想忽略指定類的自動注入使用ignoreDependencyType
- autowiring特定指的是通過beans標(biāo)簽default-autowire 即@Bean注解
蔓钟,發(fā)現(xiàn)英語中的autowiring特定指的是通過beans標(biāo)簽default-autowire屬性來依賴注入的方式永票,而不是指使用@Autowired注解進(jìn)行的依賴注入。區(qū)別在于滥沫,使用default-autowire會自動給所有的類都會從容器中查找匹配的依賴并注入,而使用@Autowired注解只會給這些注解的對象從容器查找依賴并注入键俱。
- 所謂的自動裝配是指我們配置ben的xml 或者@Bean的時候 會自動幫我們注入屬性(比如我們配置A類的B屬性=3)兰绣,那么容器就會給我們生成一個屬性為3的A的實例對象
如果上述幾個Aware不使用ignoreDependencyInterface會有什么問題尼,很簡單 如果我們寫一個實現(xiàn)類编振,然后給他默認(rèn)配置ApplicationContext屬性缀辩,而這個ApplicationContext是我們自己new的,這就導(dǎo)致了我們使用的不是spring自己生成的ApplicationContext踪央,所以spring為了避免我們手誤自己注冊下這個屬性臀玄,而幫我們忽略。
而registerResolvableDependency意思更簡單了
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
上述代碼的意思就是當(dāng)我們使用自動注入比如@AutoWired注入BeanFactory 類型的那么他會幫我們注入我們目前輸入的實例對象畅蹂,而不會去注入他的其他實現(xiàn)類健无,這是為了避免我們使用其他的自定義的實例對象
ApplicationListenerDetector
是檢測ApplicationListener的實現(xiàn)類是否是單例
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
上述檢測是否存在代碼織入,簡介如下抄襲別人博客的定義:
在Java 語言中液斜,從織入切面的方式上來看累贤,存在三種織入方式:編譯期織入、類加載期織入和運行期織入少漆。編譯期織入是指在Java編譯期臼膏,采用特殊的編譯器,將切面織入到Java類中示损;而類加載期織入則指通過特殊的類加載器渗磅,在類字節(jié)碼加載到JVM時,織入切面;運行期織入則是采用CGLib工具或JDK動態(tài)代理進(jìn)行切面的織入始鱼。
AspectJ采用編譯期織入和類加載期織入的方式織入切面仔掸,是語言級的AOP實現(xiàn),提供了完備的AOP支持风响。它用AspectJ語言定義切面嘉汰,在編譯期或類加載期將切面織入到Java類中。
AspectJ提供了兩種切面織入方式状勤,第一種通過特殊編譯器鞋怀,在編譯期,將AspectJ語言編寫的切面類織入到Java類中持搜,可以通過一個Ant或Maven任務(wù)來完成這個操作密似;第二種方式是類加載期織入,也簡稱為LTW(Load Time Weaving)
如何使用Load Time Weaving葫盼?首先残腌,需要通過JVM的-javaagent參數(shù)設(shè)置LTW的織入器類包,以代理JVM默認(rèn)的類加載器贫导;第二抛猫,LTW織入器需要一個 aop.xml文件,在該文件中指定切面類和需要進(jìn)行切面織入的目標(biāo)類孩灯。
本人對上述LTW似懂非懂
下面的代碼就沒什么好講的了闺金,就是檢測某個屬性是否存在,然后注冊單例bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
refresh中的postProcessBeanFactory 等以下代碼留著明天分享