Tomcat如何加载web项目

Tomcat加载web项目的原理

WEB项目相信大家一定都很了解,但是开发久了慢慢就忘记了基础,下面抛出两个问题:

(1)tomcat如何加载web项目的?

(2)tomcat如何加载带有spring的web项目?

Tomcat如何加载web项目?

tomcat在解析web项目的war包的时候,会首先加载一个文件——web.xml文件,这个web.xml
也就是你写的应用程序配置servelt的入口,其中包含了一些url路径,最终外部就是靠这个路径定位到你的servelt的。但是你的servelt搭载的服务器tomcat只能在局域网才能找到。想被其他外网找到的话就必须搭载到一个外网可以访问的服务器。
此处介绍两个方法:
直接放到阿里云上
使用花生壳,或者ngrok。

这也就是为什么SSM项目或者SSH项目里面必须要有web.xml文件的原因。

1:tomcat 加载顺序 web.xml文件详解
(1)、启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取listener和context-param两个结点。
(2)、紧接着,容创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。
(3)、容器将context-param转换为键值对,并交给servletContext。
(4)、容器创建listener中的类实例,创建监听器。

2:tomcat加载web.xml后
(1)其中有一些servlet等待请求的到来。
(2)tomcat中的HttpServletRequest与HttpServletResponse分别是用来接收客户端的请求,返回处理后的请求。

墙裂推荐去看看:
Tomcat的实现原理

Tomcat如何支持带有spring的web项目?

下面以一个SSM项目的web.xml文件为例子:

  
  
    Archetype Created Web Application  
      
      
        encodingFilter  
        org.springframework.web.filter.CharacterEncodingFilter  
        true  
          
            encoding  
            UTF-8  
          
      
      
        encodingFilter  
        /*  
      
      
      
        org.springframework.web.context.ContextLoaderListener  
       
         
    
        contextConfigLocation  
        /WEB_INF/applicationContext.xml  
     
      
      
        DispatcherServlet  
        org.springframework.web.servlet.DispatcherServlet  
        1    
      
      
        SpringMVC  
          
        *.do  
      
      
        /index.jsp  
      
 

下面论述下上面文件的配置内容:

  1. 系统变量contextConfigLocation告诉了spring的配置文件在哪里,这样子spring会根据路径找到这些配置文件。

  2. contextLoaderListener实现了ServletContextListener,而ServletContextListener是在整个web工程初始化前后加入自定义代码,所以在web工程初始化前。可以完成对spring容器的初始化。注意:配置contextLoaderListener一定要保证可以找到配置文件,不然会出错。

  3. 配置DispatcherServlet,首先配置了servlet-name,这意味着会默认需要一个/WEB_INF/dispatcher-servlet.xml配置文件,同样我们配置可以在服务器启动的时候初始化完成。

  4. servlet-mapping配置会拦截所有后缀为do的请求,然后处理他,当然最后是交给springmvc,具体是根据spring mvc中一个HandlerMapping这个骚东西去路由到指定的controller下面。

注意:
也许你的web工程中没有ContextLoaderListener这样的配置,这个时候DispatcherServlet会在初始化的时候对spring-ioc容器进行初始化。可以看DispatcherServlet源码中,如果检测到没有初始化Spring-Ioc,会首先初始化它。

DispatcherServlet的继承关系:
Tomcat如何加载web项目_第1张图片
从图中看,DispatcherServlet继承FrameworkServlet和HttpServletBean,HttpServletBean继承了web容器的HttpServlet,所以DispatcherServlet是一个可以载入web容器的Servlet。
web容器对于servlet的初始化,首先调用其init方法,DispatcherServlet的这个方法位于其父类HttpServletBean中。

public final void init() throws ServletException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
        }

        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()));
                this.initBeanWrapper(bw);
                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();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
        }

    }

子类FrameworkServlet中的这个方法:

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 {
        //初始化 Spring Ioc容器
            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");
        }

    }

看initWebApplicationContext方法

protected WebApplicationContext initWebApplicationContext() {
        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);
                }
            }
        }
// IOC没有被初始化,则查找是否存在IOC容器
        if (wac == null) {
            wac = this.findWebApplicationContext();
        }
//没有初始化,也没有找到IOC容器,则DispatcherServlet自己创建他。
        if (wac == null) {
            wac = this.createWebApplicationContext(rootContext);
        }
// 当onRefresh没有被调用过,则执行onRefresh方法
        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;
    }

下面来看 onRefresh(wac)方法,这个方法在DispatcherServlet中,其也就是在IOC容器完成后,初始化一些与SpringMVC相关的东西。看方法你就很熟悉了:

    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);
    }

看到上面熟悉吧。

总结:有spring的web项目一般是在容器初始化的时候完成spring-ioc容器的初始化,比如ssm就是在web容器启动时候初始化的。

你可能感兴趣的:(web)