概述
- DispatchServlet继承结构
- DispatchServlet的init方法
Tomcat创建Servlet后会执行init方法
发现DispathcheServlet中没有init方法,最终在HttpServletBean中找到了init方法,在init方法中调用了initBeanWrapper,而在该方法中调用了initWebApplicationContext,得到了一个ioc容器,具体研究一下这个方法即可。
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " '" + this.getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("Initializing Servlet '" + this.getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
} catch (RuntimeException | ServletException var4) {
this.logger.error("Context initialization failed", var4);
throw var4;
}
if (this.logger.isDebugEnabled()) {
String value = this.enableLoggingRequestDetails ? "shown which may lead to unsafe logging of potentially sensitive data" : "masked to prevent unsafe logging of potentially sensitive data";
this.logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails + "': request parameters and headers will be " + value);
}
if (this.logger.isInfoEnabled()) {
this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
initWebApplicationContextrootContext是Spring的容器,Spring的容器一启动就创建好了,并保存在了ServletContext中。
紧接着调用了createWebApplicationContext方法,而在这个方法中
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);创建了一个springmvc的ioc容器,紧接着执行了 wac.setParent(parent);将spring的容器设置为父容器,因为controller可能会有属性注入,需要从spring的容器中获取。
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = this.getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
} else {
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(this.getEnvironment());
wac.setParent(parent);
String configLocation = this.getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
this.configureAndRefreshWebApplicationContext(wac);
return wac;
}
}
来到了configureAndRefreshWebApplicationContext,在这个方法中,有这么一行代码很关键
wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
给新创建出来的容器添加了一个监听,当springmvc的容器启动完成以后,会进行回调。最后执行了wac.refresh方法进行刷新容器。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
if (this.contextId != null) {
wac.setId(this.contextId);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(this.getServletContext().getContextPath()) + '/' + this.getServletName());
}
}
wac.setServletContext(this.getServletContext());
wac.setServletConfig(this.getServletConfig());
wac.setNamespace(this.getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());
}
this.postProcessWebApplicationContext(wac);
this.applyInitializers(wac);
wac.refresh();
}
果然,断点来到了FramewordServlet的回调方法
此时获取到的就是一个完整的IOC容器
紧接着调用了本类的onRefresh方法,由于创建的是DispatchServlet,那么来到该类的这个方法,
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
关键的核心就是在这,DispatcherServlet拿到容器以后,从容器中获取了各种组件,并进行了初始化。
以initViewResolvers为例:
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
} else {
try {
ViewResolver vr = (ViewResolver)context.getBean("viewResolver", ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.viewResolvers == null) {
this.viewResolvers = this.getDefaultStrategies(context, ViewResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No ViewResolvers declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
会先从容器中获取该组件,如果能获取到,则直接赋值,如果不能则使用默认的。
从容器中获取到该组件后,给this.viewResolvers赋值,并进行了排序,多个视图解析器可进行排序。
springmvcr容器中的HandlerMapping、ViewResolver组件是从哪里来的?
大家都知道,Spring容器初始化是需要一些BeanDefination的,而这些Bean的定义信息通过debug源码发现是从XmlWebApplicationContext的loadBeanDefinitions方法解析来的。
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
public XmlWebApplicationContext() {
}
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
String[] var3 = configLocations;
int var4 = configLocations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String configLocation = var3[var5];
reader.loadBeanDefinitions(configLocation);
}
}
}
protected String[] getDefaultConfigLocations() {
return this.getNamespace() != null ? new String[]{"/WEB-INF/" + this.getNamespace() + ".xml"} : new String[]{"/WEB-INF/applicationContext.xml"};
}
}
在beanDefinitionReader里面有个一registry,而这个对象里面保存了我们要创建哪些bean,除了我们自己定义的一些bean以外,容器自身也提前定义好了一些bean,获取到这些bean的定义信息后,交给IOC容易进行bean的实例化与初始化和属性装配。
最后
以上就是潇洒皮卡丘为你收集整理的【源码分析】SpringMVC-DispatchServlet初始化的全部内容,希望文章能够帮你解决【源码分析】SpringMVC-DispatchServlet初始化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复