
Java中的网络通信是由Socket实现的,Socket分为
ServerSocket的使用分为三步
举栗
从JDK1.4开始,Java新增的新的io模式,nio(new IO)
服务端流程
Buffer类
HTTP协议是在应用层解析内容的,只需要按照它的报文的格式封装和解析数据就可以了,具体传输还是使用Socket
二、 详解ServletServlet 是 Server + Applet的缩写,表示一个服务器应用,简单理解Servlet就是一套规范,我们按照鞋套规范写代码就可以直接在Java服务器上面运行
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package javax.servlet;
import java.io.IOException;
public interface Servlet {
// 方法在容器启动时被容器调用,只会调用一次,也可以使用web.xml文件中的配置init的时机
// 被调用时接受 ServletConfig 参数,是容器传进去的(Tomcat)
// 在web.xml配置的信息,如SpringMVC的contextConfigLocation信息
void init(ServletConfig var1) throws ServletException;
// 用于获取ServletConfig
ServletConfig getServletConfig();
// 具体处理一个请求
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
// 获取Servlet相关的一些信息,版权、作者等,这个方法需要自己实现,默认返回空字符串
String getServletInfo();
// 服务器关闭,Servlet销毁时释放一些资源,也只会调用一次
void destroy();
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package javax.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration getInitParameterNames();
}
Tomcat和Servlet的关系
Tomcat的org.apache.catalina.core#StandardWrapper类初调用Servlet的init方法
private synchronized void initServlet(Servlet servlet) throws ServletException {
if (!this.instanceInitialized || this.singleThreadModel) {
try {
if (Globals.IS_SECURITY_ENABLED) {
boolean success = false;
try {
Object[] args = new Object[]{this.facade};
SecurityUtil.doAsPrivilege("init", servlet, classType, args);
success = true;
} finally {
if (!success) {
SecurityUtil.remove(servlet);
}
}
} else {
// facade 就是 StandardWrapperFacade
// StandardWrapperFacade implements ServletConfig
servlet.init(this.facade);
}
this.instanceInitialized = true;
} catch (UnavailableException var10) {
this.unavailable(var10);
throw var10;
} catch (ServletException var11) {
throw var11;
} catch (Throwable var12) {
ExceptionUtils.handleThrowable(var12);
this.getServletContext().log(sm.getString("standardWrapper.initException", new Object[]{this.getName()}), var12);
throw new ServletException(sm.getString("standardWrapper.initException", new Object[]{this.getName()}), var12);
}
}
}
需要将web.xml的配置文件在调用init方法的时候,封装成 StandardWrapperFacade 传过去
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.catalina.core;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
public final class StandardWrapperFacade implements ServletConfig {
private final ServletConfig config;
private ServletContext context = null;
public StandardWrapperFacade(StandardWrapper config) {
this.config = config;
}
public String getServletName() {
return this.config.getServletName();
}
public ServletContext getServletContext() {
if (this.context == null) {
this.context = this.config.getServletContext();
if (this.context instanceof ApplicationContext) {
this.context = ((ApplicationContext)this.context).getFacade();
}
}
return this.context;
}
public String getInitParameter(String name) {
return this.config.getInitParameter(name);
}
public Enumeration getInitParameterNames() {
return this.config.getInitParameterNames();
}
}
1、GenericServlet和HttpServlet
GenericServlet是Servlet的默认实现,主要做了三件事
HttpServlet是用HTTP协议实现的Servlet的基类,写Servlet直接继承它就可以了,不需要从头实现Servlet接口
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
// 重载方法
this.service(request, response);
}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETe")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
需要注意的是SpringMVC的处理思路并不是这样的,又将所有的请求合并到一个tonguide方法进行处理,后续详细介绍
三、 Tomcat的分析 1、Tomcat的顶层结构org.apache.catalina.startup#Catalina类主要进行的是对Server 进行生命周期处理,通过反射调用server对应的方法,自己的方法
public void load() {
if (!this.loaded) {
this.loaded = true;
long t1 = System.nanoTime();
this.initDirs();
this.initNaming();
ConfigFileLoader.setSource(new CatalinabaseConfigurationSource(Bootstrap.getCatalinabaseFile(), this.getConfigFile()));
File file = this.configFile();
Digester digester = this.createStartDigester();
try {
Resource resource = ConfigFileLoader.getSource().getServerXml();
Throwable var6 = null;
try {
InputStream inputStream = resource.getInputStream();
InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
} catch (Throwable var18) {
var6 = var18;
throw var18;
} finally {
if (resource != null) {
if (var6 != null) {
try {
resource.close();
} catch (Throwable var17) {
var6.addSuppressed(var17);
}
} else {
resource.close();
}
}
}
} catch (Exception var20) {
log.warn(sm.getString("catalina.configFail", new Object[]{file.getAbsolutePath()}), var20);
if (file.exists() && !file.canRead()) {
log.warn(sm.getString("catalina.incorrectPermissions"));
}
return;
}
this.getServer().setCatalina(this);
this.getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
this.getServer().setCatalinabase(Bootstrap.getCatalinabaseFile());
this.initStreams();
try {
this.getServer().init();
} catch (LifecycleException var21) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new Error(var21);
}
log.error(sm.getString("catalina.initError"), var21);
}
long t2 = System.nanoTime();
if (log.isInfoEnabled()) {
log.info(sm.getString("catalina.init", new Object[]{(t2 - t1) / 1000000L}));
}
}
}
public void load(String[] args) {
try {
if (this.arguments(args)) {
this.load();
}
} catch (Exception var3) {
var3.printStackTrace(System.out);
}
}
public void start() {
if (this.getServer() == null) {
this.load();
}
if (this.getServer() == null) {
log.fatal(sm.getString("catalina.noServer"));
} else {
long t1 = System.nanoTime();
try {
this.getServer().start();
} catch (LifecycleException var7) {
log.fatal(sm.getString("catalina.serverStartFail"), var7);
try {
this.getServer().destroy();
} catch (LifecycleException var6) {
log.debug("destroy() failed for failed Server ", var6);
}
return;
}
long t2 = System.nanoTime();
if (log.isInfoEnabled()) {
log.info(sm.getString("catalina.startup", new Object[]{(t2 - t1) / 1000000L}));
}
if (this.useShutdownHook) {
if (this.shutdownHook == null) {
this.shutdownHook = new Catalina.CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager)logManager).setUseShutdownHook(false);
}
}
if (this.await) {
this.await();
this.stop();
}
}
}
public void stop() {
try {
if (this.useShutdownHook) {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager)logManager).setUseShutdownHook(true);
}
}
} catch (Throwable var3) {
ExceptionUtils.handleThrowable(var3);
}
try {
Server s = this.getServer();
LifecycleState state = s.getState();
if (LifecycleState.STOPPING_PREP.compareTo(state) > 0 || LifecycleState.DESTROYED.compareTo(state) < 0) {
s.stop();
s.destroy();
}
} catch (LifecycleException var4) {
log.error(sm.getString("catalina.stopError"), var4);
}
}
需要注意的是org.apache.catalina.startup#Bootstrap类才是Tomcat的入口,也就是main方法所在,类似CatalinaAdapter,这样做的好处可以把启动入口和具体的管理类分开,从而可以很方便的创建出多种启动方式,每种启动方式只需写一个对应的CatalinaAdapter即可
public static void main(String[] args) {
synchronized(daemonLock) {
if (daemon == null) {
// 新建一个BootStrap
Bootstrap bootstrap = new Bootstrap();
try {
// 初始化了ClassLoader,并用ClassLoder创建了Catalina实例,赋值给catalianDaemon变量
bootstrap.init();
} catch (Throwable var5) {
handleThrowable(var5);
var5.printStackTrace();
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
try {
// 处理main方法传入的参数,为空执行satrt
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
// 这里调用Servlet的init()方法
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command "" + command + "" does not exist.");
}
} catch (Throwable var7) {
Throwable t = var7;
if (var7 instanceof InvocationTargetException && var7.getCause() != null) {
t = var7.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
通过启动类加载器,通过反射创建 catalinaDaemon 实例,之后daemon.load(args);daemon.start();
// BootStrap Tomcat入口类的init()方法,主要是反射创建 catalinaDaemon 实例,调用load(),start()
public void init() throws Exception {
this.initClassLoaders();
Thread.currentThread().setContextClassLoader(this.catalinaLoader);
SecurityClassLoad.securityClassLoad(this.catalinaLoader);
if (log.isDebugEnabled()) {
log.debug("Loading startup class");
}
Class> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
if (log.isDebugEnabled()) {
log.debug("Setting startup class properties");
}
String methodName = "setParentClassLoader";
Class>[] paramTypes = new Class[]{Class.forName("java.lang.ClassLoader")};
Object[] paramValues = new Object[]{this.sharedLoader};
Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
this.catalinaDaemon = startupInstance;
}
public void start() throws Exception {
// 无实例 先init()
if (this.catalinaDaemon == null) {
this.init();
}
Method method = this.catalinaDaemon.getClass().getMethod("start", (Class[])null);
method.invoke(this.catalinaDaemon, (Object[])null);
}
2、Server启动过程
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.catalina;
import java.io.File;
import java.util.concurrent.ScheduledExecutorService;
import javax.naming.Context;
import org.apache.catalina.deploy.NamingResourcesImpl;
import org.apache.catalina.startup.Catalina;
public interface Server extends Lifecycle {
NamingResourcesImpl getGlobalNamingResources();
void setGlobalNamingResources(NamingResourcesImpl var1);
Context getGlobalNamingContext();
int getPort();
void setPort(int var1);
int getPortOffset();
void setPortOffset(int var1);
int getPortWithOffset();
String getAddress();
void setAddress(String var1);
String getShutdown();
void setShutdown(String var1);
ClassLoader getParentClassLoader();
void setParentClassLoader(ClassLoader var1);
Catalina getCatalina();
void setCatalina(Catalina var1);
File getCatalinabase();
void setCatalinabase(File var1);
File getCatalinaHome();
void setCatalinaHome(File var1);
int getUtilityThreads();
void setUtilityThreads(int var1);
void addService(Service var1);
void await();
Service findService(String var1);
Service[] findServices();
void removeService(Service var1);
Object getNamingToken();
ScheduledExecutorService getUtilityExecutor();
}
protected void initInternal() throws LifecycleException {
super.initInternal();
this.reconfigureUtilityExecutor(getUtilityThreadsInternal(this.utilityThreads));
this.register(this.utilityExecutor, "type=UtilityExecutor");
this.onameStringCache = this.register(new StringCache(), "type=StringCache");
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
this.onameMBeanFactory = this.register(factory, "type=MBeanFactory");
this.globalNamingResources.init();
if (this.getCatalina() != null) {
for(ClassLoader cl = this.getCatalina().getParentClassLoader(); cl != null && cl != ClassLoader.getSystemClassLoader(); cl = cl.getParent()) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader)cl).getURLs();
URL[] var4 = urls;
int var5 = urls.length;
for(int var6 = 0; var6 < var5; ++var6) {
URL url = var4[var6];
if (url.getProtocol().equals("file")) {
try {
File f = new File(url.toURI());
if (f.isFile() && f.getName().endsWith(".jar")) {
ExtensionValidator.addSystemResource(f);
}
} catch (URISyntaxException var9) {
} catch (IOException var10) {
}
}
}
}
}
}
for(int i = 0; i < this.services.length; ++i) {
this.services[i].init();
}
}
protected void startInternal() throws LifecycleException {
this.fireLifecycleEvent("configure_start", (Object)null);
this.setState(LifecycleState.STARTING);
this.globalNamingResources.start();
synchronized(this.servicesLock) {
int i = 0;
while(true) {
if (i >= this.services.length) {
break;
}
this.services[i].start();
++i;
}
}
if (this.periodicEventDelay > 0) {
this.monitorFuture = this.getUtilityExecutor().scheduleWithFixedDelay(new Runnable() {
public void run() {
StandardServer.this.startPeriodicLifecycleEvent();
}
}, 0L, 60L, TimeUnit.SECONDS);
}
}
更多Tomcat知识此处省略…
四、俯视SpringMVC 1、使用使用步骤
XxxAware类:简单理解用处就是某个类想要使用spring的一些东西,需要实现XxxAware告诉spring,spring看到之后就会传送过来,接受唯一方式是重写XxxAware接口的ser-Xxx方法
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext var1) throws BeansException;
}
public interface EnvironmentAware extends Aware {
void setEnvironment(Environment var1);
}
// 可以自己写一个Cobtroller然后实现 EnvironmentAware 重写setEnvironment方法,直接向spring通过方法参数的方式要数据
ApplicationContext:类似前面的ServletContext
Environment:环境,实际在HttpServletBean的Environment使用的是Standard-Servlet-Environment,封装了ServletContext、ServletConfig、JndiProperty、系统环境变量和系统属性,这些封装到了HttpServletBean的propertySources属性下
org.springframework.web.context.support#StandardServletEnvironment 类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.context.support;
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
// web.xml中的servletContext相关key
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
// web.xml中的servletConfig相关key
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
public StandardServletEnvironment() {
}
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
// 调用父类StandardEnvironment的方法,将配置传给父类
super.customizePropertySources(propertySources);
}
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}
}
2、HttpServletBean
org.springframework.web.servlet#HttpServletBean类
Servlet的创建过程
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.servlet;
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
protected final Log logger = LogFactory.getLog(this.getClass());
@Nullable
private ConfigurableEnvironment environment;
private final Set requiredProperties = new HashSet(4);
public HttpServletBean() {
}
protected final void addRequiredProperty(String property) {
this.requiredProperties.add(property);
}
// 直接从sring容器活的ServletConfig
public void setEnvironment(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment, "ConfigurableEnvironment required");
// 转为ConfigurableEnvironment类型
this.environment = (ConfigurableEnvironment)environment;
}
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = this.createEnvironment();
}
return this.environment;
}
protected ConfigurableEnvironment createEnvironment() {
// 使用 StandardServletEnvironment 作为配置文件的载体
return new StandardServletEnvironment();
}
// 初始化方法,
public final void init() throws ServletException {
// 封装ServletConfig
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
// 初始化DispatchServlet
this.initBeanWrapper(bw);
// 设置配置信息,其实就是environment
bw.setPropertyValues(pvs, true);
} catch (BeansException var4) {
if (this.logger.isErrorEnabled()) {
this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
}
throw var4;
}
}
// 模板方法,调用子类方法
this.initServletBean();
}
// 子类模板,也就是调用子类
protected void initServletBean() throws ServletException {
}
@Nullable
public String getServletName() {
return this.getServletConfig() != null ? this.getServletConfig().getServletName() : null;
}
// 静态内部类,为了解析ServletConfig的配置信息
private static class ServletConfigPropertyValues extends MutablePropertyValues {
public ServletConfigPropertyValues(ServletConfig config, Set requiredProperties) throws ServletException {
// 是否含必要的配置,不含为null,下面抛异常
Set missingProps = !CollectionUtils.isEmpty(requiredProperties) ? new HashSet(requiredProperties) : null;
// 配置项key
Enumeration paramNames = config.getInitParameterNames();
// 获取配置项value,调用addPropertyValue(),实际执行this.requiredProperties.add(property);
while(paramNames.hasMoreElements()) {
String property = (String)paramNames.nextElement();
Object value = config.getInitParameter(property);
this.addPropertyValue(new PropertyValue(property, value));
// 检查全部必须项
if (missingProps != null) {
missingProps.remove(property);
}
}
if (!CollectionUtils.isEmpty(missingProps)) {
throw new ServletException("Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", "));
}
}
}
}
// HttpServletBean需要 Envirment类转为ConfigurableEnvironment
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
void setActiveProfiles(String... var1);
void addActiveProfile(String var1);
void setDefaultProfiles(String... var1);
MutablePropertySources getPropertySources();
Map getSystemProperties();
Map getSystemEnvironment();
void merge(ConfigurableEnvironment var1);
}
可以看到在HttpServletBean的init中,首先将Servlet的配置参数使用BeanWrapper设置到DispatchServlet的相关属性,然后调用模板方法initServletNean子类就是通过这个方法初始化
3、frameworkServlet由HttpServletBean得知,frameworkServlet的初始化入口方法应该是initServletBean,由父类HttpServletBean调用,主要作用是初始化 WebApplicationContext
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 {
// 1. 初始化 initWebApplicationContext
this.webApplicationContext = this.initWebApplicationContext();
// 初始化 initframeworkServlet,模板方法,可由子类重写
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");
}
}
initWebApplicationContext()方法,做了三件事
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
// 如果已经通过构造方法设置 webApplicationContext
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) {
// 当webApplicationContext 已经存在ServletContext之后,通过Servlet的contextAttribute参数获取
wac = this.findWebApplicationContext();
}
if (wac == null) {
// 上一步没获取到,也就是还没创建,此处创建
wac = this.createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// 当COntextRefreshEvent事件没有被触发时调用,模板方法,子类可重写
synchronized(this.onRefreshMonitor) {
this.onRefresh(wac);
}
}
if (this.publishContext) {
// WebApplicationContext设置到ServletContext
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
}
return wac;
}
4、设置WebApplicationContext的方法
第一种
第二种
第三种
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);
// 将设置的contextConfigLocation参数传给wac,默认WEB-INFO/[ServletName]-Servlet.xml
String configLocation = this.getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
// 给wac添加监听器
this.configureAndRefreshWebApplicationContext(wac);
return wac;
}
}
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());
// 添加监听器
// 实际监听的是 ContextRefreshListener 所监听的事件
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();
}
frameworkServlet的内部类,监听ContextRefreshedEvent 事件
private class ContextRefreshListener implements ApplicationListener5、将WebApplicationContext设置到ServletContext中{ private ContextRefreshListener() { } public void onApplicationEvent(ContextRefreshedEvent event) { frameworkServlet.this.onApplicationEvent(event); } }
frameworkServlet的initWebApplicationContext方法
if (this.publishContext) {
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
}
最后会根据 publishContext 标志判断是都将创建出来的webApplicationContext设置到ServletContext中
onRefresh方法是DispatcherServlet的入口方法,调用了initStrategies,其中有9个初始化方法
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
// 9 个组件初始化
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
具体的初始化过程
以LocalResolver为例,组件初始化分两步
private void initLocaleResolver(ApplicationContext context) {
try {
// 在context中获取
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.localeResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 使用默认策略
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
}
}
}
getDefaultStrategy获取默认组件策略,因为HandleMapping的组件可能有多个,需要返回List,对于其他的去list.get(0)即可
** * Return the default strategy object for the given strategy interface. *The default implementation delegates to {@link #getDefaultStrategies}, * expecting a single object in the list. * @param context the current WebApplicationContext * @param strategyInterface the strategy interface * @return the corresponding strategy object * @see #getDefaultStrategies */ protected
T getDefaultStrategy(ApplicationContext context, Class strategyInterface) { // 调用 getDefaultStrategies 获取所有默认策略 List strategies = getDefaultStrategies(context, strategyInterface); if (strategies.size() != 1) { throw new BeanInitializationException( "DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]"); } // 因为HandleMapping的组件可能有多个,需要返回List,对于其他的去list.get(0)即可 return strategies.get(0); } @SuppressWarnings("unchecked") protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface) { String key = strategyInterface.getName(); // 从 defaultStrategies 获取所需策略的类型 String value = defaultStrategies.getProperty(key); if (value != null) { // 策略有多个,以逗号分割数组 String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List strategies = new ArrayList<>(classNames.length); for (String className : classNames) { try { // 按获取到的类型初始化策略 Class> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } catch (ClassNotFoundException ex) { throw new BeanInitializationException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (linkageError err) { throw new BeanInitializationException( "Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", err); } } return strategies; } else { return new linkedList<>(); } }
核心代码Class> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
// 也就是DispatcherServlet.properties特定键值对
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
可以看到一共8各组件,对于处理上传组件MultipartResolver无默认配置