从入门到放弃(2)-tomcat -spring web.xml

接着从入门到放弃(1)-tomcat -spring web.xml继续对spring启动的探索
上文讲到

ServletContextListener listener =
                (ServletContextListener) instances[i];
                 listener.contextInitialized(event);

调用到我们项目即可找到,idea 快捷键ctrl+shift+n 打开对应的类
从入门到放弃(2)-tomcat -spring web.xml_第1张图片
获取类的路径:copy referene : org.springframework.web.context.ContextLoader
从入门到放弃(2)-tomcat -spring web.xml_第2张图片
找到 org.springframework.web.context.ContextLoader源码,找到285行打印日志处,可以看到打印了info lever 日志,并且可以找到对应的方法org.springframework.web.context.ContextLoader.initWebApplicationContext(ServletContext servletContext)
从入门到放弃(2)-tomcat -spring web.xml_第3张图片
先看下org.springframework.web.context.ContextLoader.initWebApplicationContext(ServletContext servletContext)是从哪里调用进来的,熟悉idea同学可以知道ctrl+鼠标左键可以看到在这个方法在哪里调用
从入门到放弃(2)-tomcat -spring web.xml_第4张图片
进入org.springframework.web.context.ContextLoaderListener.contextInitialized(ServletContextEvent event)的112行,可以找到对应的调用位置,详细的contextInitialized(ServletContextEvent event)源码

public void contextInitialized(ServletContextEvent event) {
		this.contextLoader = createContextLoader();
		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}

因为我三个listen中第一个listen 继承了ContextLoaderListener 并且调用了 super.contextInitialized(event);
从入门到放弃(2)-tomcat -spring web.xml_第5张图片
查看当前类的关系,public class ContextLoaderListener extends ContextLoader implements ServletContextListener,继承于ContextLoader 实现于ServletContextListener,这与上篇讲的tomcat启动web.xml 正好合到一起了。并且把event 从tomcat容器成功传递到spring 中
从入门到放弃(2)-tomcat -spring web.xml_第6张图片
先看下ContextLoader 加载的内容

private static final Properties defaultStrategies;
static {
		// Load default strategy implementations from properties file.
		// This is currently strictly internal and not meant to be customized
		// by application developers.
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}
	//ContextLoader.properties 内容为
	// Default WebApplicationContext implementation class for ContextLoader.
	// Used as fallback when no explicit context implementation has been specified as context-	param.
	// Not meant to be customized by application developers.

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

defaultStrategies 会在后面初始化org.springframework.web.context.support.XmlWebApplicationContext用到
从入门到放弃(2)-tomcat -spring web.xml_第7张图片
继续接着org.springframework.web.context.ContextLoaderListener.contextInitialized(ServletContextEvent event)的112行 this.contextLoader.initWebApplicationContext(event.getServletContext());

logger.info("Root WebApplicationContext: initialization started");
this.context = createWebApplicationContext(servletContext);

下面看下 createWebApplicationContext(servletContext)的源码

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		Class<?> contextClass = determineContextClass(sc);
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

再看 determineContextClass(sc)的源码

contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());

从入门到放弃(2)-tomcat -spring web.xml_第8张图片
从入门到放弃(2)-tomcat -spring web.xml_第9张图片
看上面两张图片最终返回的结果:org.springframework.web.context.support.XmlWebApplicationContext
再回到 createWebApplicationContext(servletContext)的代码中
从入门到放弃(2)-tomcat -spring web.xml_第10张图片
通过BeanUtils.instantiateClass(contextClass)方法根据类名创建对应实例,并且进行强制转换得到ConfigurableWebApplicationContext接口的实例,BeanUtils.instantiateClass(contextClass)源码

public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
                return instantiateClass(clazz.getDeclaredConstructor());      
    }    
  public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
            ReflectionUtils.makeAccessible(ctor);
            return ctor.newInstance(args);        
    }

接着this.context = createWebApplicationContext(servletContext);这一行往下看

if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}

核心代码又跑到了configureAndRefreshWebApplicationContext(cwac, servletContext);这个方法

wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}
wac.refresh();

从入门到放弃(2)-tomcat -spring web.xml_第11张图片
对应web.xml内容
从入门到放弃(2)-tomcat -spring web.xml_第12张图片
继续看wac.refresh()其位置
从入门到放弃(2)-tomcat -spring web.xml_第13张图片
代码如下

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}

当进入第一个方法prepareRefresh(); 会打印如下日志
从入门到放弃(2)-tomcat -spring web.xml_第14张图片
obtainFreshBeanFactory()方法是refresh()方法中的核心之一。
作用:初始化beanFactory,加载并解析配置

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		//1.初始化beanFactory,并执行加载和解析配置操作
		refreshBeanFactory();
		//返回beanFactory实例
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

obtainFreshBeanFactory()方法中做了二件事:
refreshBeanFactory():创建beanFactory、指定序列化Id、定制beanFactory、加载bean定义
getBeanFactory():返回beanFactory实例
一. refreshBeanFactory():刷新beanFactory
初始化beanFactory,并执行加载和解析配置操作
进入到refreshBeanFactory()方法,分析refreshBeanFactory()方法的具体实现:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    ...
    
    @Override
	protected final void refreshBeanFactory() throws BeansException {
		//判断是否存在beanFactory
		if (hasBeanFactory()) {
		    // 注销所有的单例
			destroyBeans();
			//重置beanFactory
			closeBeanFactory();
		}
		try {
		    //创建beanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			//指定序列化id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
			beanFactory.setSerializationId(getId());
			//定制BeanFactory
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
	...
}

refreshBeanFactory()方法中做了四件事情:
如果有bean工厂,销毁bean以及关闭bean工厂
createBeanFactory():创建beanFactory
beanFactory.setSerializationId(getId()):指定序列化Id
customizeBeanFactory():定制BeanFactory
loadBeanDefinitions():加载bean定义
先介绍到这里后面继续从loadBeanDefinitions()解析

你可能感兴趣的:(入门到放弃)