java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters)

马肤
这是懒羊羊

springmvc也是在spring framework中的,不是一个单独的项目

MVC就是和Tomcat有关。

01.MVC启动的第一步,启动Tomcat(这个和springboot的run方法启动Tomcat有关)

02.SpringMVC中,最为核心的就是DispatcherServlet,在启动Tomcat的过程中:

  1. Tomcat会先创建DispatcherServlet对象(这一步在手写springboot框架中已经写到,Tomcat在启动的时候会启动DispatcherServlet)
  2. 然后调用DispatcherServlet对象的init()------这一步是用来创建spring容器

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第1张


DispatcherServlet对象的init()

01.DispatcherServlet类的init()

DispatcherServlet本身默认是没有重写init()方法的

public class DispatcherServlet extends FrameworkServlet {
//DispatcherServlet中没有init方法,在父类中找
}

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第2张

DispatcherServlet的父类HttpServletBean类init方法:

@Override
	public final void init() throws ServletException {
		// 解析 init-param 并封装只 pvs 中(xml)
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				// 将当前的这个 Servlet 类转化为一个 BeanWrapper,从而能够以 Spring 的方法来对 init-param 的值进行注入
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
				// 属性注入
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}
		// Let subclasses do whatever initialization they like.
		// 初始化Servlet,创建Spring容器
		initServletBean();
	}

02.DispatcherServlet的父类FrameworkServlet类

有一个属性XmlWebApplicationContext,这个是可以继承的,这代表DispatcherServlet也有这个属性

	@Nullable
	private WebApplicationContext webApplicationContext;

XmlWebApplicationContext是一种spring容器,这代表DispatcherServlet有一个spring容器

03.HttpServletBean的init方法 的initServletBean方法:初始化Servlet,创建Spring容器

	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
		if (logger.isInfoEnabled()) {
			logger.info("Initializing Servlet '" + getServletName() + "'");
		}
		long startTime = System.currentTimeMillis();
		try {
			this.webApplicationContext = initWebApplicationContext();
			// 空方法,无实现·
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}
		if (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";
			logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
					"': request parameters and headers will be " + value);
		}
		if (logger.isInfoEnabled()) {
			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
		}
	}

04.initServletBean方法的initWebApplicationContext方法:初始化spring容器

这里暂时不考虑父子容器,直接看 createWebApplicationContext方法

protected WebApplicationContext initWebApplicationContext() {
		// 获得ContextLoaderListener存的父容器
		WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;
		if (this.webApplicationContext != null) {
			// 获得子容器
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// 如果没有设置父容器   spring  doGetBean
					if (cwac.getParent() == null) {
						cwac.setParent(rootContext);
					}
					// 配置并且加载子容器
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// 从servlet上下文根据名字从域里面获取
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// xml会在这里创建
			wac = createWebApplicationContext(rootContext);
		}
		//refreshEventReceived 它会在容器加载完设置为true (通过事件onApplicationEvent)
		// springboot在这初始化组件
		if (!this.refreshEventReceived) {
			synchronized (this.onRefreshMonitor) {
				onRefresh(wac);
			}
		}
		if (this.publishContext) {
			// 将当前容器放到servlet域中, 可以再创建子容器
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
		}
		return wac;
	}

05.initWebApplicationContext方法的createWebApplicationContext方法:创建容器 (重点)

	protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		Class contextClass = getContextClass();
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
		configureAndRefreshWebApplicationContext(wac);
		return wac;
	}

其中的getContextClass方法:获取spring容器class对象

public Class getContextClass() {
		return this.contextClass;
	}

this.contextClass:

	private Class contextClass = DEFAULT_CONTEXT_CLASS;
	
	public static final Class DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;

BeanUtils.instantiateClass:真正创建spring容器

	public static  T instantiateClass(Class clazz) throws BeanInstantiationException {
		Assert.notNull(clazz, "Class must not be null");
		if (clazz.isInterface()) {
			throw new BeanInstantiationException(clazz, "Specified class is an interface");
		}
		try {
			return instantiateClass(clazz.getDeclaredConstructor());
		}
		catch (NoSuchMethodException ex) {
			Constructor ctor = findPrimaryConstructor(clazz);
			if (ctor != null) {
				return instantiateClass(ctor);
			}
			throw new BeanInstantiationException(clazz, "No default constructor found", ex);
		}
		catch (LinkageError err) {
			throw new BeanInstantiationException(clazz, "Unresolvable class definition", err);
		}
	}

此时获取 createWebApplicationContext方法 的wac

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第3张

06.createWebApplicationContext方法中的getContextConfigLocation方法,获取spring容器配置类的地址

		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
	@Nullable
	public String getContextConfigLocation() {
		return this.contextConfigLocation;
	}

用到的变量:

	@Nullable
	private String contextConfigLocation;

这个一般就是在web.xml文件中写好了:这个web.xml文件自动开机扫描


	
		app
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			/WEB-INF/spring.xml
		
		1
	
	
		app
		/app/*
	

这一段就表明文件是WEB-INF文件下的spring.xml

		
			contextConfigLocation
			/WEB-INF/spring.xml
		

spring.xml:


	

这一段就会表面 spring容器的扫描器会扫描com.zhou这个包

	

07.getContextConfigLocation方法执行完了后,createWebApplicationContext方法会在内部顺序继续执行configureAndRefreshWebApplicationContext方法:完成所有bean的解析、加载和初始化。

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// 设置id
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
			}
		}
		// 设置servlet上下文
		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		// 监听器  委托设计模式
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
		// 将init-param设置到Environment中
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}
		// 空方法可扩展
		postProcessWebApplicationContext(wac);
		// 容器启动前初始化
		applyInitializers(wac);
		wac.refresh();
	}

完成后的情况:

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第4张

这一块:

// 监听器  委托设计模式
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

new ContextRefreshListener() :内部类

private class ContextRefreshListener implements ApplicationListener {
        //对ContextRefreshedEvent监听
		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
			FrameworkServlet.this.onApplicationEvent(event);
		}
	}

08.onApplicationEvent方法:spring的事件机制

	public void onApplicationEvent(ContextRefreshedEvent event) {
		this.refreshEventReceived = true;
		synchronized (this.onRefreshMonitor) {
			onRefresh(event.getApplicationContext());
		}
	}

09.onRefresh方法:这个方法在DispatcherServlet类上的

protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

10.initStrategies方法:初始化

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

11.其中

initHandlerMappings(context) 初始化HandlerMappings

initHandlerAdapters(context) 初始化HandlerAdapters

		initHandlerMappings(context);
		initHandlerAdapters(context);

12.什么是Handler

Handler表示请求处理器,在SpringMVC中有四种Handler:

  1. 实现了Controller接口的Bean对象
  2. 实现了HttpRequestHandler接口的Bean对象
  3. 添加了@RequestMapping注解的方法
  4. 一个HandlerFunction对象

比如实现了Controller接口的Bean对象:

@Component("/test")
public class ZhouyuBeanNameController implements Controller {
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		System.out.println("zhouyu");
		return new ModelAndView();
	}
}

实现了HttpRequestHandler接口的Bean对象:

@Component("/test")
public class ZhouyuBeanNameController implements HttpRequestHandler {
	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("zhouyu");
	}
}

添加了@RequestMapping注解的方法:

@RequestMapping
@Component
public class ZhouyuController {
	@Autowired
	private ZhouyuService zhouyuService;
	@RequestMapping(method = RequestMethod.GET, path = "/test")
	@ResponseBody
	public String test(String username) {
		return "zhouyu";
	}
}

一个HandlerFunction对象(以下代码中有两个):

@ComponentScan("com.zhouyu")
@Configuration
public class AppConfig {
	@Bean
	public RouterFunction person() {
		return route()
				.GET("/app/person", request -> ServerResponse.status(HttpStatus.OK).body("Hello GET"))
				.POST("/app/person", request -> ServerResponse.status(HttpStatus.OK).body("Hello POST"))
				.build();
	}
    
}

13.什么是HandlerMapping?

HandlerMapping负责去寻找Handler,并且保存路径和Handler之间的映射关系。HandlerMapping结构是: ,实际上是由两个map联合组成 ,一个map是多值map(用来辨别get,post这些方法的,虽然url一样,但是方法不同),一个是普通map(多值map的值会作为这个map的key,value是Handler)

因为有不同类型的Handler,所以在SpringMVC中会由不同的HandlerMapping来负责寻找存储Handler,比如:

  1. BeanNameUrlHandlerMapping:负责Controller接口和HttpRequestHandler接口
  2. RequestMappingHandlerMapping:负责@RequestMapping的方法
  3. RouterFunctionMapping:负责RouterFunction以及其中的HandlerFunction

首先要创建HandlerMapping,用initHandlerMappings方法

	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		// 根据类型(多个)   默认true
		if (this.detectAllHandlerMappings) {
			// 容器中有HandlerMapping,用HandlerMapping
			Map matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		// 根据名字(唯一)
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}
		// 如果没有配HandlerMapping , 就去DispatcherServlet.properties拿默认的
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
		for (HandlerMapping mapping : this.handlerMappings) {
			if (mapping.usesPathPatterns()) {
				this.parseRequestPath = true;
				break;
			}
		}
	}

getDefaultStrategies方法:默认配置HandlerMappings

	private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
	
	
	protected  List getDefaultStrategies(ApplicationContext context, Class strategyInterface) {
		if (defaultStrategies == null) {
			try {
				// 通过PropertiesLoaderUtils工具类加载DispatcherServlet.properties  
				// resource 是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());
			}
		}
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List strategies = new ArrayList(classNames.length);
			for (String className : classNames) {
				try {
				//创建DispatcherServlet.properties 文件中的类的bean
					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 Collections.emptyList();
		}
	}

其中DispatcherServlet.properties文件:HandlerMapping有三个实现类

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter

createDefaultStrategy:用到createBean方法,这里参数 Class clazz 是DispatcherServlet.properties文件中记录的

	protected Object createDefaultStrategy(ApplicationContext context, Class clazz) {
		return context.getAutowireCapableBeanFactory().createBean(clazz);
	}

创建完了HandlerMapping ,如何使用功能?


BeanNameUrlHandlerMapping:用 Aware接口 ApplicationContextAware 寻找Handler

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
}

BeanNameUrlHandlerMapping的寻找流程:

  1. 找出Spring容器中所有的beanName
  2. 判断beanName是不是以“/”开头
  3. 如果是,则把它当作一个Handler,并把beanName作为key,bean对象作为value存入handlerMap中
  4. handlerMap就是一个Map

BeanNameUrlHandlerMapping的一个父类ApplicationObjectsSupport:

实现 ApplicationContextAware

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第5张

ApplicationContextAware接口的 setApplicationContext 方法

public interface ApplicationContextAware extends Aware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

setApplicationContext最后会调用detectHandlers

	protected void detectHandlers() throws BeansException {
		ApplicationContext applicationContext = obtainApplicationContext();
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
				applicationContext.getBeanNamesForType(Object.class));
		// Take any bean name that we can determine URLs for.
		for (String beanName : beanNames) {
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// URL paths found: Let's consider it a handler.
				registerHandler(urls, beanName);
			}
		}
		if (mappingsLogger.isDebugEnabled()) {
			mappingsLogger.debug(formatMappingName() + " " + getHandlerMap());
		}
		else if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
			logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
		}
	}

determineUrlsForHandler方法:直接判断beanname是不是用/开头

	protected String[] determineUrlsForHandler(String beanName) {
		List urls = new ArrayList();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = obtainApplicationContext().getAliases(beanName);
		for (String alias : aliases) {
			if (alias.startsWith("/")) {
				urls.add(alias);
			}
		}
		return StringUtils.toStringArray(urls);
	}

registerHandler 注册到map中

	protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
		Assert.notNull(urlPaths, "URL path array must not be null");
		for (String urlPath : urlPaths) {
			registerHandler(urlPath, beanName);
		}
	}
	protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		Assert.notNull(urlPath, "URL path must not be null");
		Assert.notNull(handler, "Handler object must not be null");
		Object resolvedHandler = handler;
		// Eagerly resolve handler if referencing singleton via name.
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			ApplicationContext applicationContext = obtainApplicationContext();
			if (applicationContext.isSingleton(handlerName)) {
				resolvedHandler = applicationContext.getBean(handlerName);
			}
		}
		Object mappedHandler = this.handlerMap.get(urlPath);
		if (mappedHandler != null) {
			if (mappedHandler != resolvedHandler) {
				throw new IllegalStateException(
						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
			}
		}
		else {
			if (urlPath.equals("/")) {
				if (logger.isTraceEnabled()) {
					logger.trace("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
				if (logger.isTraceEnabled()) {
					logger.trace("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			else {
				this.handlerMap.put(urlPath, resolvedHandler);
				if (getPatternParser() != null) {
					this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

存储在handlerMap

	private final Map handlerMap = new LinkedHashMap();

RequestMappingHandlerMapping:afterPropertiesSet来找有@RequestMapping的方法

RequestMappingHandlerMapping的寻找流程:

  1. 找出Spring容器中所有beanType

    2 判断beanType是不是有@Controller注解,或者是不是有@RequestMapping注解

  2. 判断成功则继续找beanType中加了@RequestMapping的Method
  3. 并解析@RequestMapping中的内容,比如method、path,封装为一个RequestMappingInfo对象
  4. 最后把RequestMappingInfo对象做为key,Method对象封装为HandlerMethod对象后作为value,存入registry中
  5. registry就是一个Map
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
	public void afterPropertiesSet() {
		this.config = new RequestMappingInfo.BuilderConfiguration();
		this.config.setTrailingSlashMatch(useTrailingSlashMatch()); // 尾部斜杠
		this.config.setContentNegotiationManager(getContentNegotiationManager());
		if (getPatternParser() != null) {
			this.config.setPatternParser(getPatternParser());
			Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
					"Suffix pattern matching not supported with PathPatternParser.");
		}
		else {
			this.config.setSuffixPatternMatch(useSuffixPatternMatch());
			this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
			this.config.setPathMatcher(getPathMatcher());
		}
		super.afterPropertiesSet();
	}
}

父类afterPropertiesSet

	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

initHandlerMethods方法:

	protected void initHandlerMethods() {
		// 获得所有候选beanName—— 当前容器所有的beanName
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				// *处理候选bean——即解析@RequestMapping和映射路径
				processCandidateBean(beanName);
			}
		}
		// 解析完所有@RequestMapping的时候调用
		handlerMethodsInitialized(getHandlerMethods());
	}

processCandidateBean方法:

protected void processCandidateBean(String beanName) {
		Class beanType = null;
		try {
			beanType = obtainApplicationContext().getType(beanName);
		}
		catch (Throwable ex) {
			// An unresolvable bean type, probably from a lazy bean - let's ignore it.
			if (logger.isTraceEnabled()) {
				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
			}
		}
		// 这一步判断是关键  是否有Controller 或 RequestMapping注解
		if (beanType != null && isHandler(beanType)) {
			// 解析HandlerMethods
			detectHandlerMethods(beanName);
		}
	}

processCandidateBean方法中的obtainApplicationContext方法:获取spring容器

	protected final ApplicationContext obtainApplicationContext() {
		ApplicationContext applicationContext = getApplicationContext();
		Assert.state(applicationContext != null, "No ApplicationContext");
		return applicationContext;
	}
	@Nullable
		public final ApplicationContext getApplicationContext() throws IllegalStateException {
			if (this.applicationContext == null && isContextRequired()) {
				throw new IllegalStateException(
						"ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
			}
			return this.applicationContext;
		}

processCandidateBean方法中的isHandler:判断是不是有Controller注解或者RequestMapping注解

	@Override
	protected boolean isHandler(Class beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}

processCandidateBean方法中的detectHandlerMethods方法:解析

	protected void detectHandlerMethods(Object handler) {
		Class handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
		if (handlerType != null) {
			Class userType = ClassUtils.getUserClass(handlerType);
			// 循环所有方法
			Map methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup) method -> {
						try {
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
			});
			if (logger.isTraceEnabled()) {
				logger.trace(formatMappings(userType, methods));
			}
			else if (mappingsLogger.isDebugEnabled()) {
				mappingsLogger.debug(formatMappings(userType, methods));
			}
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第6张

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第7张

getMappingForMethod方法

	protected RequestMappingInfo getMappingForMethod(Method method, Class handlerType) {
		// 如果方法上面有@RequestMapping:解析出RequestMappingInfo
		// RequestMappingInfo 是用来在请求的时候做匹对的
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null) {
			// 如果方法上面有@RequestMapping,看看类上面是不是有@RequestMapping
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			// 类上面也有@RequestMapping  那就合并
			// 比如 类:/user  方法:/info 合并为 /user/info
			if (typeInfo != null) {
				info = typeInfo.combine(info);
			}
			// 合并前缀   5.1新增  默认null
			// 可通过 WebMvcConfigurer#configurePathMatch 进行定制
			String prefix = getPathPrefix(handlerType);
			if (prefix != null) {
				info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
			}
		}
		return info;
	}

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第8张

createRequestMappingInfo:

	@Nullable
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		// 获取RequestMapping注解
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
		// 获取请求调解:[可扩展], 如果有:该条件会在请求时匹对
		RequestCondition condition = (element instanceof Class ?
				getCustomTypeCondition((Class) element) : getCustomMethodCondition((Method) element));
		// 如果有RequestMapping注解,封装成RequestMappingInfo
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
	}
protected RequestMappingInfo createRequestMappingInfo(
			RequestMapping requestMapping, @Nullable RequestCondition customCondition) {
		// 将@RequestMapping注解属性的值构建成一个 RequestMappingInfo
		RequestMappingInfo.Builder builder = RequestMappingInfo
				//构建路径
				.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
				//构建方法(get还是post等)
				.methods(requestMapping.method())
				//参数 对应http request parameter
				.params(requestMapping.params())
				//头部
				.headers(requestMapping.headers())
				//request的提交内容类型content type,如application/json, text/html
				.consumes(requestMapping.consumes())
				//指定返回的内容类型的content type,仅当request请求头中的(Accept)类型中包含该指定类型才返回
				.produces(requestMapping.produces())
				.mappingName(requestMapping.name());
		if (customCondition != null) {
			builder.customCondition(customCondition);
		}
		// 构造RequestMappingInfo:将上面的属性构建成一个个的RequestCondition对象方便在请求的时候组合匹对
		return builder.options(this.config).build();
	}

回到

detectHandlerMethodsjava-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第9张

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第10张

registerHandlerMethod

	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}

register

		private final Map registry = new HashMap();
//辩别post,get方法,一个key,有多个值,值用链表
		private final MultiValueMap pathLookup = new LinkedMultiValueMap();
	public void register(T mapping, Object handler, Method method) {
			this.readWriteLock.writeLock().lock();
			try {
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				validateMethodMapping(handlerMethod, mapping);
				Set directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
				for (String path : directPaths) {
					this.pathLookup.add(path, mapping);
				}
				String name = null;
				if (getNamingStrategy() != null) {
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);
				}
				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
					corsConfig.validateAllowCredentials();
					this.corsLookup.put(handlerMethod, corsConfig);
				}
//
				this.registry.put(mapping,
						new MappingRegistration(mapping, handlerMethod, directPaths, name, corsConfig != null));
			}
			finally {
				this.readWriteLock.writeLock().unlock();
			}
		}

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第11张

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第12张

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第13张

RouterFunctionMapping:

RouterFunctionMapping的寻找流程会有些区别,但是大体是差不多的,相当于是一个path对应一个HandlerFunction。

public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean {
}

java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第14张

比较困难的点在于,当DispatcherServlet接收到一个请求时,该利用哪个HandlerMapping来寻找Handler呢?看源码:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

很简单,就是遍历,找到就返回,默认顺序为:java-springmvc 01DispatcherServlet(创建spring容器,包括HandlerMappings,HandlerAdapters),在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,没有,li,进行,第15张

所以BeanNameUrlHandlerMapping的优先级最高,比如:

@Component("/test")
public class ZhouyuBeanNameController implements Controller {
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		System.out.println("Hello zhouyu");
		return new ModelAndView();
	}
}
@RequestMapping(method = RequestMethod.GET, path = "/test")
@ResponseBody
public String test(String username) {
	return "Hi zhouyu";
}

14.什么是HandlerAdapter?

找到了Handler之后,接下来就该去执行了,比如执行下面这个test()

@RequestMapping(method = RequestMethod.GET, path = "/test")
@ResponseBody
public String test(String username) {
	return "zhouyu";
}

但是由于有不同种类的Handler,所以执行方式是不一样的,再来总结一下Handler的类型:

  1. 实现了Controller接口的Bean对象,执行的是Bean对象中的handleRequest()
  2. 实现了HttpRequestHandler接口的Bean对象,执行的是Bean对象中的handleRequest()
  3. 添加了@RequestMapping注解的方法,具体为一个HandlerMethod,执行的就是当前加了注解的方法
  4. 一个HandlerFunction对象,执行的是HandlerFunction对象中的handle()

先初始化HandlerAdapter

initHandlerAdapters:

public class DispatcherServlet extends FrameworkServlet {
    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;
        if (this.detectAllHandlerAdapters) {
            // 查找容器中所有的 HandlerAdapter类型的Bean
            Map matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList(matchingBeans.values());
                // 排序
                AnnotationAwareOrderComparator.sort(this.handlerAdapters);
            }
        }
        else {
            try {
                /* 只从容器中获取 BeanName = handlerAdapter  HandlerAdapter类型的Bean */
                HandlerAdapter ha = context.getBean("handlerAdapter", HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            }
            catch (NoSuchBeanDefinitionException ex) {
            }
        }
        /**
         * 没有自定义 使用默认的
         */
        if (this.handlerAdapters == null) {
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        }
    }
}

getDefaultStrategies:

protected  List getDefaultStrategies(ApplicationContext context, Class strategyInterface) {
        String key = strategyInterface.getName();
        /**
         * 重点关注下这里 SpringMVC 的默认策略
         */
        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());
                    /**
                     * 这里是用 Web容器去创建实例
                     * 默认是多实例的(scope = provided)
                     */
                    Object strategy = createDefaultStrategy(context, clazz);
                    strategies.add((T) strategy);
                }
                catch (ClassNotFoundException ex) {
                }
                catch (LinkageError err) {
                }
            }
            return strategies;
        }
        else {
            return new LinkedList();
        }
    }

createDefaultStrategy(context, clazz)

调用 Web容器的createBean创建Bean


HandlerAdapter一共四个

	org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter

15.springMVC响应http请求 给Handler一个HandlerAdapter

httpservlet service方法

	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
			throws Exception;
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(request);
		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap();
			Enumeration attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}
		// Make framework objects available to handlers and view objects.
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
		if (this.flashMapManager != null) {
			FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
			if (inputFlashMap != null) {
				request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
			}
			request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
		}
		RequestPath previousRequestPath = null;
		if (this.parseRequestPath) {
			previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
			ServletRequestPathUtils.parseAndCache(request);
		}
		try {
			doDispatch(request, response);
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
			if (this.parseRequestPath) {
				ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
			}
		}
	}
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		try {
			ModelAndView mv = null;
			Exception dispatchException = null;
			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
				// 进行映射
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				// 找到最合适的HandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				// Process last-modified header, if supported by the handler.  HTTP缓存相关
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				// 前置拦截器
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					// 返回false就不进行后续处理了
					return;
				}
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 如果mv有  视图没有,给你设置默认视图
				applyDefaultViewName(processedRequest, mv);
				//后置拦截器
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			// 渲染视图
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			/** 拿到所有handlerMappings (容器启动阶段初始化:拿到所有实现了HandlerMapping的Bean)
			 * @see DispatcherServlet#initHandlerMappings
			 * 测试发现: 不同的HandlerMapping可以有相同path, 谁先解析到就用哪个
			 * */
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

传入handler,遍历上面四个Adapter,谁支持就返回谁,比如判断的代码依次为:

HttpRequestHandlerAdapter :

HttpRequestHandlerAdapter, 该HttpRequestHandler接口的适配执行器

public class HttpRequestHandlerAdapter implements HandlerAdapter {
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}
}

SimpleControllerHandlerAdapter:

SimpleControllerHandlerAdapter, 该Controller接口的适配执行器

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}
}

HandlerFunctionAdapter :

public class HandlerFunctionAdapter implements HandlerAdapter, Ordered {
@Override
	public boolean supports(Object handler) {
		return handler instanceof HandlerFunction;
	}
}
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

根据Handler适配出了对应的HandlerAdapter后,就执行具体HandlerAdapter对象的handle()方法了,比如:

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	((HttpRequestHandler) handler).handleRequest(request, response);
	return null;
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	return ((Controller) handler).handleRequest(request, response);
}
HandlerFunction handlerFunction = (HandlerFunction) handler;
serverResponse = handlerFunction.handle(serverRequest);

文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复:表情:
评论列表 (暂无评论,0人围观)

还没有评论,来说两句吧...

目录[+]

取消
微信二维码
微信二维码
支付宝二维码