首页 » 网站建设 » phpmvc主动加载技巧_SpringMVC加载流程

phpmvc主动加载技巧_SpringMVC加载流程

访客 2024-11-14 0

扫一扫用手机浏览

文章目录 [+]

这个图描述了SpringMVC处理一个Http要求的基本流程,对应的流程为:

用户发送要求至前端掌握器DispatcherServlet。
DispatcherServlet收到要求调用HandlerMapping处理器映射器。
处理器映射器找到详细的处理器(可以根据xml配置、表明进行查找),天生处理器工具及处理器拦截器(如果有则天生)一并返回给DispatcherServlet。
DispatcherServlet调用HandlerAdapter处理器适配器。
HandlerAdapter经由适配调用详细的处理器(Controller,也叫后端掌握器)。
Controller实行完成返回ModelAndView。
HandlerAdapter将controller实行结果ModelAndView返回给DispatcherServlet。
DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
ViewReslover解析后返回详细View.DispatcherServlet根据View进行渲染视图(即将模型数据添补至视图中)。
DispatcherServlet响运用户。

 还有大家都会打仗到的demo:

phpmvc主动加载技巧_SpringMVC加载流程

web.xml

phpmvc主动加载技巧_SpringMVC加载流程
(图片来自网络侵删)

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app>

在applicationContext.xml,指定包的扫描访问并添加标签

<context:component-scan base-package="xxx" /><mvc:annotation-driven />

添加Controller

import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController { @RequestMapping("/hello") public String excute() { return "hello"; }}

上面表示的意思为:

开启ContextLoaderListener加载Spring根Context,对应的配置文件为applicationContext.xml开启DispatcherServlet监听/下的所有要求,加载WebContext,对应的配置文件为dispatcher-servlet.xml指定扫描包路径,并开启mvc表明支持添加对应的Controller,利用@RestController标记为Controller工具并利用@RequestMapping标记处理的要求路径3. SpringMVC加载流程

 SpringMVC的加载是依赖Servlet切入的,紧张依赖两个技能点:Listener和Servlet。

3.1. ContextLoaderListener的加载

 从web.xml中可以知道,ContextLoaderListener依赖于Servlet的Listener技能。
Listener是在servlet2.3中加入的,紧张用于对session、request、context等进行监控。
利用Listener须要实现相应的接口。
触发Listener事宜的时候,tomcat会自动调用相应的Listener的方法。
常用的监听接口包括:

HttpSessionListener:监听session的创建和销毁。
ServletRequestListener:监听request的创建和销毁ServletContextListener:监听context的创建和销毁。

这里紧张利用了ServletContextListener,用于在Servlet初始化前实行自定义动作。

 ContextLoaderListener的定义如下:

public class ContextLoaderListener extends ContextLoader implements ServletContextListener { public ContextLoaderListener() { } public ContextLoaderListener(WebApplicationContext context) { super(context); } @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } @Override public void contextDestroyed(ServletContextEvent event) { closeWebApplicationContext(event.getServletContext()); ContextCleanupListener.cleanupAttributes(event.getServletContext()); }}

该类继续了ContextLoader,并通过contextInitialized方法实行了初始化(传入ServletContext),通过contextDestroyed方法进行资源销毁回收。
重点看ContextLoader方法。

 ContextLoader在初始化时,会先实行内部的一个静态代码块:

private static final Properties defaultStrategies;static { 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()); }}

这一步会加载classpath下的配置文件ContextLoader.properties,该文件将作为默认配置用于初始化Properties工具defaultStrategies。

3.1.1. contextInitialized

 contextInitialized方法的紧张内容如下:

过程为:

(1) 判断当前Context是否已经初始化过

 通过判断ServletContext中是否存在key为org.springframework.web.context.ROOT的值

初始化WebApplicationContext:从ContextLoader.properties中查找WebApplicationContext的详细实现,如下:

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

即XmlWebApplicationContext,然后初始化该类

(2) 配置并刷新该XMLWebApplicationContext

 XMLWebApplicationContext继续简图如下:

层级比较明显,本身也是一个RefreshableConfigApplicationContext(详细内容可以看往期内容)。
其父类保存了ServletContext和ServletConfig两个Web Context干系的工具,其本身也坚持了一些默认属性,如

DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

这个属性便是默认的Spring配置文件的路径。

 须要指出的是XMLWebApplicationContext重写了父类的loadBeanDefinitions方法

@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader);}protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { reader.loadBeanDefinitions(configLocation); } }} @Overrideprotected String[] getDefaultConfigLocations() {//Tip:返回配置文件路径 if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; }}

这里用了XmlBeanDefinitionReader来解析Bean定义,且指定了配置文件的加载逻辑,getConfigLocations方法:如果父类的configLocations不为空,则返回该值,否则返回getDefaultConfigLocations的值。
而getDefaultConfigLocations方法逻辑为:如果存在命名空间,则返回/WEB_INF/namespace.xml作为配置文件,否则返回/WEB-INF/applicationContext.xml。
对应上面的demo,将返回配置中的文件(同默认值相同)。

 XMLWebApplicationContext的初始化步骤为:

读取contextId配置,进行设置读取contextConfigLocation配置,利用指定的配置文件,若没有则利用上面提到的默认配置文件DEFAULTCONFIGLOCATION加载contextInitializerClasses指定的class,用于在context刷新前实行自定义处理调用XMLWebApplicationContext的refresh方法

(3)标记已经初始化

 通过将该根Context存在ServletContext中,并设置值为org.springframework.web.context.ROOT,用于第(1)步的判断

3.1.2. contextDestroyed

 销毁过程比较大略,首先调用WebApplicationContext的close方法销毁该Context,然后移除ServletContex中的org.springframework.web.context.ROOT属性值,末了打消ServletContext中所有org.springframework.开头的属性值。

3.2. DispatcherServlet的加载

 同ContextLoaderListener类似,DispatcherServlet依赖于Servlet进行扩展。
DispatcherServlet的构造如下:

如上,DispatcherServlet继续自HttpServlet,并重写了doService方法,用于处理http要求,个中:

3.2.1. HttpServletBean

 在HttpServlet的继续上增加了ConfigurableEnvironment属性,用于存放Servlet的配置项。
通过重写init方法,在初始化时将servlet配置项添加到高下文环境变量中,并在该方法中开放了initBeanWrapper和initServletBean方法给子类。

3.2.2. FrameworkServlet

 基于Servlet实现的Web框架,每个Servlet内部都对应一个XmlWebApplicationContext工具,且namespace格式为ServletName-servlet。
上面说了在没显示设定配置文件路径的情形下,且存在namespace时,会利用/WEB-INF/namespace.xml作为Spring配置文件,对应到demo即为/WEB-INF/dispatcher-servlet.xml。
FrameworkServlet重写了父类的intServletBean方法,对XmlWebApplicationContext的初始化事情。
Servlet在初始化XmlWebApplicationContext时,会考试测验从ServletContext中获取根Context(上面提到的,会将根Ccontext放到ServletContext中以标记已经初始化过)并设置为当前Context的父Context,然后再按照雷士根Contextde 的初始化过程对其进行初始化。
不同的是,会在refresh前开放口子进行扩展,包括:

对内通过重写子类的postProcessWebApplicationContext方法对外通过加载并实行globalInitializerClasses中配置的ApplicationContextInitializer类

FrameworkServlet还重写了父类的各doXXX方法,都交给processService方法,以处理Http要求。
processService终极委托给了doService方法。

3.2.3. DispatchdrServlet

 是SpringMVC处理Http要求的紧张实现,紧张完成了两件事:

3.1. 重写了onRefresh方法

 初始化时设置了浩瀚默认处理策略,包括:文件处理策略、HandlerMapping处理策略、HandlerAdapter处理策略、HandlerException处理策略、View解析策略等。
SpringMVC在处理Http的每个步骤上,都供应了类似filter的机制,每个步骤都能够注册多个策略处理器,按照顺序选择出能够处理当前要求的策略并交给其处理。
而大部分的默认策略来至于spring-mvc模块下的org/springframework/web/servlet/DispatcherServlet.properties文件,如下:

下面为本人demo(SpringBoot)运行时DispatcherServlet各属性以及注册的各策略的情形

紧张关注handlerMappings中的RequestMappingHandlerMapping和handlerAdapters中的RequestMappingHandlerAdapter。
这两个都不是在DispatcherServlet.properties文件中指定的,而是在开启 后自动注册的,这个后面会先容。

3.1.1 RequestMappingHandlerMapping初始化

 RequestMappingHandlerMapping紧张用于查找@RequestMapping表明的handler,其继续关系如下:

AbstractHandlerMapping:实现了HandlerMapping接口,供应了获取handler的紧张实现。
getHandler方法的实现为,将详细handler的查找委托给了子类的getHandlerInternal方法,然后跟当前要求路径干系的interceptor一起包装为一个HandlerExecutionChain返回。
interceptor为所有实现了MappedInterceptor接口的bean,会在AbstractHandlerMapping初始化的时候遍历高下文进行查找。
AbstractHandlerMethodMapping:在AbstractHandlerMapping的根本上,紧张供应了根据要求查找对应handler method的实现,即getHandlerInternal方法。
该类会在初始化时遍历高下文中所有的Bean,然后符合条件的Bean(通过isHandler方法),遍历当前Bean符合条件的方法(通过getMappingForMethod方法),每个方法都有一个对应的path,称为lookUpPath。
getHandlerInternal实现上也是通过要求的HttpServletRequest得到对应的lookUpPath,然后从内存缓存中获取对应的handler。
RequestMappingHandlerMapping:@RequestMapping的实现,紧张实现了 isHandler和getMappingForMethod。
isHandler:判断是否涌现@Controller表明或者@RequestMapping表明 getMappingForMethod:根据@RequestMapping表明返回RequestMappingInfo实例。
3.1.2 RequestMappingHandlerAdapter初始化

  RequestMappingHandlerAdapter紧张完成HandlerMethod的实行,,其继续关系如下:

AbstractHandlerMethodAdapter:用于判断是否支持Handler的实行,须要传入的handler是否为HandlerMethod实例,同时将handler的实行委托给子类的handleInternal方法。
RequestMappingHandlerAdapter:真正实行handler对应的Method工具,会调用各种resolvers解析参数,用于在反射时作为入参传入;调用各种converter用于对结果进行加工等操作。

3.2. 重写doService方法

 实现了Http要求的处理过程,详细流程如下图,即开头提及的SpringMVC处理Http要求的过程,前面已经先容过流程,这里不再赘述。

3.3. mvc:annotation-driven

 按照之前说的,先看resource/META-INF/spring.handlers文件,这个配置在spring-webmvc模块下,内容为:

http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler

支持的标签如下:

annotation-driven的解析类为:AnnotationDrivenBeanDefinitionParser,该类紧张自动做了如下动作:

注入了RequestMappingHandlerMapping和BeanNameUrlHandlerMapping两个HandlerMapping实现注入了RequestMappingHandlerAdapter、HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter三个HandlerAdapter实现。
须要指出的是对付RequestMappingHandlerAdapter,如果没有配置message-converters标签指定处理器的话,会根据classpath中存在的包自动注入处理器,包括: ByteArrayHttpMessageConverter StringHttpMessageConverter ResourceHttpMessageConverter SourceHttpMessageConverter AllEncompassingFormHttpMessageConverter 如果存在com.rometools.rome.feed.WireFeed类,则增加AtomFeedHttpMessageConverter、RssChannelHttpMessageConverter 如果存在com.fasterxml.jackson.dataformat.xml.XmlMapper类,则增加MappingJackson2XmlHttpMessageConverter 如果存在javax.xml.bind.Binder类,则增加Jaxb2RootElementHttpMessageConverter 如果存在com.fasterxml.jackson.databind.ObjectMapper和com.fasterxml.jackson.core.JsonGenerator,则增加MappingJackson2HttpMessageConverter 如果存在com.google.gson.Gson,则增加GsonHttpMessageConverter注入了ExceptionHandlerExceptionResolver用于实现@ExceptionHandler表明、注入了ResponseStatusExceptionResolver用于实现@ResponseStatus和DefaultHandlerExceptionResolver注入了AntPathMatcher和UrlPathHelper用于路径解析

 上面先容了SpringMVC大体流程的实现,当然还有很多细节没有进行解释,如@Param,HttpServletRequest等各种参数的解析和注入,相应结果转为json等各种结果的加工,详细内容可以根据上面先容再进行深入。

4. WebApplicationInitializer

 Servlet3.0+供应了ServletContainerInitializer接口,用于在web容器启动时为供应给第三方组件机会做一些初始化的事情,例如注册servlet或者filtes等。

 每个框架要利用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定详细的ServletContainerInitializer实现类。
spring-web模块下便存在该配置:

内容为:

org.springframework.web.SpringServletContainerInitializer

SpringServletContainerInitializer的紧张功能是加载classpath下的所有WebApplicationInitializer实现类(非接口、非抽象类),按照@Order进行排序后依次实行WebApplicationInitializer的onStartup方法。

 spring-web模块供应的抽象类实现AbstractContextLoaderInitializer能够不用web.xml配置增加RootContext;供应的抽象类实现AbstractDispatcherServletInitializer能够不用web.xml配置增加DispatcherServlet。
当然更主要的实现是SpringBoot中的实现,这个后续先容SpringBoot时再提。

更多原创内容请搜索微信"大众号:啊驼(doubaotaizi)

相关文章

phpforwhile机能技巧_PHP 轮回While 轮回

PHP 循环在您编写代码时,您常常须要让相同的代码块一次又一次地重复运行。我们可以在代码中利用循环语句来完成这个任务。在 PHP...

网站建设 2024-12-10 阅读0 评论0