整体结构
- XXXAware:在spring中表示感知,如果在某个类中需要XXX,就可以通过实现XXXAware接口高速spring,spring通过接口的唯一方法setXXX。
- XXXCappable:表示具有提供XXX的能力,spring需要XXX时通过getXXX()获得。
HttpServletBean使用的是StandardServletEnvironment。
- ServletConfigPropertiesSource:封装的是ServletConfig。
- ServletContextPropertiesSource:封装的是ServletContext。
- JndiPropertiesSource:存放的是Jndi。
- MapPropertiesSource:存放的是虚拟机属性。
- SystemEnvironmentPropertiesSource:存放的是系统环境变量。
HttpServletBean
重写GenericServlet的模板方法init()。
public final void init() throws ServletException {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
}
try {
//将servlet中配置的参数封装到pvs
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
//模板方法,子类(DispatcherServlet)中调用(),bw代表DispatcherServlet
//但是子类未使用
this.initBeanWrapper(bw);
//将配置的初始化参数设置到DispatcherServlet
bw.setPropertyValues(pvs, true);
} catch (BeansException var4) {
this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
throw var4;
}
//模板方法,子类初始化入口
this.initServletBean();
if(this.logger.isDebugEnabled()) {
this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
}
}
FrameworkServlet
初始化入口为initServletBean()。
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'");
if(this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
} catch (ServletException var5) {
this.logger.error("Context initialization failed", var5);
throw var5;
} catch (RuntimeException var6) {
this.logger.error("Context initialization failed", var6);
throw var6;
}
if(this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
}
}
核心代码就两句,initFrameworkServlet()是模板方法,但是子类并没有使用。那么主要的作用就是初始化webApplicationContext。
protected WebApplicationContext initWebApplicationContext() {
//默认情况spring会将自己的容器设置为ServletContext的属性,直接通过ServletContex.getAttribute(key)获得容器
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
//第一种
//构造方法中已经设置,只需要对其进行一些设置
if(this.webApplicationContext != null) {
wac = this.webApplicationContext;
if(wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
if(!cwac.isActive()) {
if(cwac.getParent() == null) {
cwac.setParent(rootContext);
}
this.configureAndRefreshWebApplicationContext(cwac);
}
}
}
//第二种
if(wac == null) {
wac = this.findWebApplicationContext();
}
//第三种,自己创建
if(wac == null) {
wac = this.createWebApplicationContext(rootContext);
}
if(!this.refreshEventReceived) {
this.onRefresh(wac);
}
if(this.publishContext) {
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
initWebApplicationContext()做了三件事:
- 获取spring的根容器rootContext。
- 设置webApplicationContext,并按情况调用onRefresh()。
- 将webApplicationContext设置到ServletContext。
DispatcherServlet