GVKun编程网logo

Spring 中的 Dispatcher Servlet 是什么?(springmvc中dispatcherservlet的作用)

36

对于Spring中的DispatcherServlet是什么?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍springmvc中dispatcherservlet的作用,并为您提供关于1.Sp

对于Spring 中的 Dispatcher Servlet 是什么?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍springmvc中dispatcherservlet的作用,并为您提供关于1.SpringMVC 设计理念与 DispatcherServlet、DispatcherServlet & SpringMVC 启动过程、Dubbox 的 DispatcherServlet 和 spring-mvc 的 DispatcherServlet,两者 url-pattern 抢占要怎么解决?、http-500:Servlet.init() for servlet SpringDispatcherServlet threw exception的有用信息。

本文目录一览:

Spring 中的 Dispatcher Servlet 是什么?(springmvc中dispatcherservlet的作用)

Spring 中的 Dispatcher Servlet 是什么?(springmvc中dispatcherservlet的作用)

在这张图片中(我从
这里
得到的), HTTP 请求向 Dispatcher Servlet 发送了一些东西。

在此处输入图像描述

我的问题是 Dispatcher Servlet 做什么?

是否类似于从网页中获取信息并将其扔给控制器?

答案1

小编典典

DispatcherServlet 的工作是获取传入的 URI 并找到处理程序(通常是 Controller 类上的方法)和视图(通常是
JSP)的正确组合,它们组合起来形成应该在该位置找到的页面或资源。

我可能有

  • 一份文件/WEB-INF/jsp/pages/Home.jsp
  • 和一个类的 方法
    @RequestMapping(value="/pages/Home.html")

    private ModelMap buildHome() {
    return somestuff;
    }

Dispatcher servlet 是“知道”在浏览器请求页面时调用该方法并将其结果与匹配的 JSP 文件组合以生成 html 文档的位。

它如何实现这一点因配置和 Spring 版本而异。

也没有理由最终结果必须是网页。它可以做同样的事情来定位 RMI 端点、处理 SOAP 请求,以及任何可以进入 servlet 的事情。

1.SpringMVC 设计理念与 DispatcherServlet

1.SpringMVC 设计理念与 DispatcherServlet

 

SpringMVC 作为 Struts2 之后异军突起的一个表现层框架,正越来越流行,相信 javaee 的开发者们就算没使用过 SpringMVC,也应该对其略有耳闻。我试图通过对 SpringMVC 的设计思想和源码实现的剖析,从抽象意义上的设计层面和实现意义上的代码层面两个方面,逐一揭开 SpringMVC 神秘的面纱,本文的代码,都是基于 Spring 的 3.1.3RELEASE 版本。

任何一个框架,都有自己特定的适用领域,框架的设计和实现,必定是为了应付该领域内许多通用的,烦琐的、基础的工作而生。SpringMVC 作为一个表现层框架,也必须直面 Web 开发领域中表现层中的几大课题,并给出自己的回答:

  • URL 到框架的映射。

  • http 请求参数绑定

  • http 响应的生成和输出

这三大课题,组成一个完整的 web 请求流程,每一个部分都具有非常广阔的外延。SpringMVC 框架对这些课题的回答又是什么呢?

学习一个框架,首要的是要先领会它的设计思想。从抽象、从全局上来审视这个框架。其中最具有参考价值的,就是这个框架所定义的核心接口。核心接口定义了框架的骨架,也在最抽象的意义上表达了框架的设计思想。

下面我以一个 web 请求流程为载体,依次介绍 SpringMVC 的核心接口和类。

用户在浏览器中,输入了 http://www.xxxx.com/aaa/bbb.ccc 的地址,回车后,浏览器发起一个 http 请求。请求到达你的服务器后,首先会被 SpringMVC 注册在 web.xml 中的前端转发器 DispatcherServlet 接收,DispatcherServlet 是一个标准的 Servlet,它的作用是接受和转发 web 请求到内部框架处理单元。

下面看一下第一个出现在你面前的核心接口,它是在 org.springframework.web.servlet 包中定义的 HandlerMapping 接口:

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;

public interface HandlerMapping {

String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";

String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";

String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";

String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

为了阅读方便,我去掉了源码中的注释,但是我强烈建议你一定要记得去阅读它,这样你才能从框架的设计者口中得到最准确的关于这个类或者接口的设计说明。类中定义的几个常量,我们先不去管它。关键在于这个接口中唯一的方法:

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

这个方法就算对于一个 java 初学者来说,也很容易理解:它只有一个类型为 HttpServletRequest 的参数,throws Exception 的声明表示它不处理任何类型的异常,HandlerExecutionChain 是它的返回类型。

回到 DispatcherServlet 的处理流程,当 DispatcherServlet 接收到 web 请求后,由标准 Servlet 类处理方法 doGet 或者 doPost,经过几次转发后,最终注册在 DispatcherServlet 类中的 HandlerMapping 实现类组成的一个 List(有点拗口)会在一个循环中被遍历。以该 web 请求的 HttpServletRequest 对象为参数,依次调用其 getHandler 方法,第一个不为 null 的调用结果,将被返回。DispatcherServlet 类中的这个遍历方法不长,贴一下,让大家有更直观的了解。

/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//遍历处理器映射器
       for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name ''" + getServletName() + "''");
}
           //获取HandlerExecutionChain(处理执行链),并返回
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}

是的,第一步处理就这么简单的完成了。一个 web 请求经过处理后,会得到一个 HandlerExecutionChain 对象,这就是 SpringMVC 对 URl 映射给出的回答。需要留意的是,HandlerMapping 接口的 getHandler 方法参数是 HttpServletRequest,这意味着,HandlerMapping 的实现类可以利用 HttpServletRequest 中的 所有信息来做出这个 HandlerExecutionChain 对象的生成” 决策 “。这包括,请求头、url 路径、cookie、session、参数等等一切你从一个 web 请求中可以得到的任何东西(最常用的是 url 路径)。

SpirngMVC 的第一个扩展点,就出现在这里。我们可以编写任意的 HandlerMapping 实现类,依据任何策略来决定一个 web 请求到 HandlerExecutionChain 对象的生成。可以说,从第一个核心接口的声明开始,SpringMVC 就把自己的灵活性和野心暴露无疑:哥玩的就是”Open-Closed“。

HandlerExecutionChain 这个类,就是我们下一个要了解的核心类。从名字可以直观的看得出,这个对象是一个执行链的封装。熟悉 Struts2 的都知道,Action 对象也是被层层拦截器包装,这里可以做个类比,说明 SpringMVC 确实是吸收了 Struts2 的部分设计思想。

HandlerExecutionChain 类的代码不长,它定义在 org.springframework.web.servlet 包中,为了更直观的理解,先上代码。

package org.springframework.web.servlet;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.util.CollectionUtils;

public class HandlerExecutionChain {

private final Object handler;

private HandlerInterceptor[] interceptors;

private List<HandlerInterceptor> interceptorList;

public HandlerExecutionChain(Object handler) {
this(handler, null);
}

public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList<HandlerInterceptor>();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
}
else {
this.handler = handler;
this.interceptors = interceptors;
}
}

public Object getHandler() {
return this.handler;
}

public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList();
this.interceptorList.add(interceptor);
}

public void addInterceptors(HandlerInterceptor[] interceptors) {
if (interceptors != null) {
initInterceptorList();
this.interceptorList.addAll(Arrays.asList(interceptors));
}
}

private void initInterceptorList() {
if (this.interceptorList == null) {
this.interceptorList = new ArrayList<HandlerInterceptor>();
}
if (this.interceptors != null) {
this.interceptorList.addAll(Arrays.asList(this.interceptors));
this.interceptors = null;
}
}

public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
}
return this.interceptors;
}

@Override
public String toString() {
if (this.handler == null) {
return "HandlerExecutionChain with no handler";
}
StringBuilder sb = new StringBuilder();
sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]");
if (!CollectionUtils.isEmpty(this.interceptorList)) {
sb.append(" and ").append(this.interceptorList.size()).append(" interceptor");
if (this.interceptorList.size() > 1) {
sb.append("s");
}
}
return sb.toString();
}

}

乱七八糟一大堆,相信你也没全看完,也没必要全看。其实只需要看两行足矣。

private final Object handler; //处理器,真正处理业务

private HandlerInterceptor[] interceptors; //拦截器数组

不出我们所料,一个实质执行对象,还有一堆拦截器。这不就是 Struts2 中的实现么,SpringMVC 没有避嫌,还是采用了这种封装。得到 HandlerExecutionChain 这个执行链(execution chain)之后,下一步的处理将围绕其展开。

HandlerInterceptor 也是 SpringMVC 的核心接口,定义如下:

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface HandlerInterceptor {

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception;

void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;

void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;

}

至此,HandlerExecutionChain 整个执行脉络也就清楚了:在真正调用其 handler 对象前,HandlerInterceptor 接口实现类组成的数组将会被遍历,其 preHandle 方法会被依次调用,然后真正的 handler 对象将被调用。

handler 对象被调用后,就生成了需要的响应数据,在将处理结果写到 HttpServletResponse 对象之前(SpringMVC 称为渲染视图),其 postHandle 方法会被依次调用。视图渲染完成后,最后 afterCompletion 方法会被依次调用,整个 web 请求的处理过程就结束了。

在一个处理对象执行之前,之后利用拦截器做文章,这已经成为一种经典的框架设计套路。Struts2 中的拦截器会做诸如参数绑定这类复杂的工作,那么 SpringMVC 的拦截器具体做些什么呢?我们暂且不关心,虽然这是很重要的细节,但细节毕竟是细节,我们先来理解更重要的东西。

HandlerInterceptor,是 SpringMVC 的第二个扩展点的暴露,通过自定义拦截器,我们可以在一个请求被真正处理之前、请求被处理但还没输出到响应中、请求已经被输出到响应中之后这三个时间点去做任何我们想要做的事情。Struts2 框架的成功,就是源于这种拦截器的设计,SpringMVC 吸收了这种设计思想,并推陈出新,更合理的划分了三个不同的时间点,从而给 web 请求处理这个流程,提供了更大的扩展性。

这个 HandlerExecutionChain 类中以 Object 引用所声明的 handler 对象,到底是个什么东东?它是怎么被调用的?

回答这些问题之前,先看 SpringMVC 中的又一个核心接口,HandlerAdapter:

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface HandlerAdapter {

boolean supports(Object handler);

ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

long getLastModified(HttpServletRequest request, Object handler);

}

在 DispatcherServlet 中,除了 HandlerMapping 实现类的列表,同样也注册了一个 HandlerAdapter 实现类组成的列表,有代码为证。

/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;

/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;

接下来,我们再以 DispatcherServlet 类中另外一段代码来回答上述的问题:

/**
	 * Return the HandlerAdapter for this handler object.
	 * @param handler the handler object to find an adapter for
	 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
	 */
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			if (ha.supports(handler)) {
				return ha;
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: Does your handler implement a supported interface like Controller?");
	}

这段代码已经很明显了,HandlerExecutionChain 中的 handler 对象会被作为参数传递进去,在 DispatcherServlet 类中注册的 HandlerAdapter 实现类列表会被遍历,然后返回第一个 supports 方法返回 true 的 HandlerAdapter 对象,用这个 HandlerAdapter 实现类中的 handle 方法处理 handler 对象,并返回 ModelAndView 这个包含了视图和数据的对象。HandlerAdapter 就是 SpringMVC 提供的第三个扩展点,你可以提供自己的实现类来处理 handler 对象。

ModelAndView 对象的代码就不贴了,它是 SpringMVC 中对视图和数据的一个聚合类。其中的视图,就是由 SpringMVC 的最后一个核心接口 View 所抽象:

package org.springframework.web.servlet;
 
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public interface View {
 
	String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
 
	String PATH_VARIABLES = View.class.getName() + ".pathVariables";
 
	String getContentType();
 
	void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
 
}

所有的数据,最后会作为一个 Map 对象传递到 View 实现类中的 render 方法,调用这个 render 方法,就完成了视图到响应的渲染。这个 View 实现类,就是来自 HandlerAdapter 中的 handle 方法的返回结果。当然从 ModelAndView 到真正的 View 实现类有一个解析的过程,ModelAndView 中可以有真正的视图对象,也可以只是有一个视图的名字,SpringMVC 会负责将视图名称解析为真正的视图对象。

至此,我们了解了一个典型的完整的 web 请求在 SpringMVC 中的处理过程和其中涉及到的核心类和接口。

在一个典型的 SpringMVC 调用中,HandlerExecutionChain 中封装 handler 对象就是用 @Controller 注解标识的类的一个实例,根据类级别和方法级别的 @RequestMapping 注解,由默认注册的 DefaultAnnotationHandlerMapping(3.1.3 中更新为 RequestMappingHandlerMapping 类,但是为了向后兼容,DefaultAnnotationHandlerMapping 也可以使用)生成 HandlerExecutionChain 对象,再由 AnnotationMethodHandlerAdapter(3.1.3 中更新为 RequestMappingHandlerAdapter 类,但是为了向后兼容,AnnotationMethodHandlerAdapter 也可以使用)来执行这个 HandlerExecutionChain 对象,生成最终的 ModelAndView 对象后,再由具体的 View 对象的 render 方法渲染视图。

可以看到,作为一个表现层框架,SpringMVC 没有像 Struts2 那样激进,并没有采用和 Web 容器完全解耦的设计思想,而是以原生的 Servlet 框架对象为依托,通过合理的抽象,制定了严谨的的处理流程。这样做的结果是,执行效率比 Struts2 要高,灵活性也上升了一个层次。

上一篇文章《SpringMVC 源码剖析(一)- 从抽象和接口说起》中,我介绍了一次典型的 SpringMVC 请求处理过程中,相继粉墨登场的各种核心类和接口。我刻意忽略了源码中的处理细节,只列出最简单的类甚至是接口类,目的就是让大家先从最高层次的抽象意义上来审视 SpringMVC 这个框架;我也刻意将 SpringMVC 和 Struts2 做对比,目的是让大家看到,SpringMVC 究竟吸取了 Sturts2 设计思想中的哪些精华,又弥补了它的哪些遗憾。

DispatcherServlet 作为 SpringMVC 的核心之中的核心类,再怎么强调它的重要性也不为过。SpringMVC 所有的核心类和接口,都密集地出现在 DispatcherServlet 的源码中,SpringMVC 源码剖析,很大程度上可以说也是在剖析 DispatcherServlet 这一个类。这一篇文章里,我先说几点关于 DispatcherServlet 的前世今生,希望能帮助你更好的理解它。

1. 对扩展开放,对修改封闭

SpringMVC 是一个基于著名的 Open-Closed,即开闭原则进行设计的框架。在 Spring 官方文档里面关于 SpringMVC 的介绍开宗明义地进行了说明:

A key design principle in Spring Web MVC and in Spring in general is the “Open for extension,closed for modificationprinciple.

开闭原则是一个很宽泛的原则,具体体现到 DispatcherServlet 的源码中,我们可以大致摸得到一些线索:

  • 类中所有的变量声明,几乎都以接口的形式给出,并没有绑定在具体的实现类上。

  • 使用模版方法模式,在父类中对基础行为进行定义,让子类实现模版方法扩展行为。

其中第一点,在一个框架的设计中尤为重要,也是贯彻开闭原则最重要的一点。因为当你通过一些高层次的接口或者抽象类,将一个类完成的逻辑或流程编写完成后(具体点说,是通过一个接口的引用调用接口方法),整个逻辑或流程的功能就被确实的在源码中固定下来了。可是这时,这些接口或抽象类的具体实现者是谁,还没有固定!这就给了你的系统或框架近乎无限的扩展性,因为你可以任意安排和实现这些类。

我认为,面向对象设计的精髓,是对现实世界中 “行为和契约” 的描述。这个 “行为和契约”,体现在接口和抽象类的方法声明中。软件设计师要用面向对象的眼光去观察和抽象这个世界中的事物,这里的事物可以是一些商业逻辑、可以是一些处理流程,然后用高层次的接口去描述这些行为和契约。当你在越抽象的层次上将这些行为和契约描述清楚后,你所设计的系统就是越符合开闭原则的。

SpringMVC 框架在面向对象设计上,做出了绝佳的示范。它通过高度抽象的接口,描述出了一次请求处理的流程,从而让整个框架从一开始就是符合开闭原则的。同时它也提供了这些接口的一系列默认实现类,让你不需要很复杂的配置,就能很好的使用 SpringMVC 进行开发。抽象的确是个利器,但是框架绝不能运行在空中楼阁中,SpringMVC 提供的的这一系列默认实现类必须要有容身之所。聪明的你可能早已想到:Spring IOC 容器。这就引出了我要说的第二点。

2. 配置元素的对象化

所有的框架,都需要有这样一个功能,叫做:配置元素的对象化。因为几乎所有的框架,都将配置元素集中到外部的 xml 配置文件中,然后在框架的初始化流程中,对这些配置文件进行解析,再变成 java 世界中的一个个对象供框架使用,这整个过程,可以被称为配置元素的对象化。为什么要有配置文件呢?这个问题的回答也是很简单,因为没有人会想要使用一个配置散布在框架中各个 java 类源码里面的框架。框架也不允许使用者这样子做,因为框架在发布的时候,提供的是一个个 jar 包文件,jar 包内是已经编译好的 class 文件。配置文件由使用者外部提供,框架对它进行解析,使用者能得到集中配置的好处,框架也乐于这样子,可以说是合情合理。

那么作为 Spring 产品族的新成员,SpringMVC 在设计的时候,相信设计者们不做它想,这一个 “配置元素的对象化” 功能既然不可避免,那么使用 Spring IOC 容器,通过 bean 配置文件来配置 SpringMVC,绝对是不二之选。不可能像 Struts2 一样,内部再搞一个别的容器,因为 Spring 容器本身已经是被高度设计,而且已经在 java 世界获得巨大成功。从推广的角度上来说,如果对 spring 容器的所有知识,都可以完整的应用到 SpringMVC,那么对于开发者无疑是一个极大的吸引力。

剩下的问题就只有:到底该如何将 Spring 容器和 SpringMVC 的初始化过程整合起来呢?

答案就是 WebApplicationContext 接口,更具体点说,是 XmlWebApplicationContext 这个 Spring 上下文实现类。SpringMVC 也使用了这一个为了将 Spring 容器和 Web 环境整合而特意设计的 Spring 上下文类。我们打开 WebApplicationContext 的源码:

package org.springframework.web.context;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
public interface WebApplicationContext extends ApplicationContext {
 
	String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
 
	String SCOPE_REQUEST = "request";
 
	String SCOPE_SESSION = "session";
 
	String SCOPE_GLOBAL_SESSION = "globalSession";
 
	String SCOPE_APPLICATION = "application";
 
	String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
 
	String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
 
	String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
 
	ServletContext getServletContext();
 
}

发现它是继承于 ApplicationContext 这个普通 Spring 容器所使用的上下文接口类,除了一些常量的声明,只多了一个可以获取到 ServletContext 的 getServletContext () 方法。回到上面提到的 “行为和契约的描述” 上,我们可以大胆的断言,Spring 容器和 Web 环境的整合,是在 ServletContext 上做文章。

打开所有使用了 Spring 的 Web 项目的 web.xml 文件,必定有这样一段配置:

<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

ContextLoaderListener 实现了 ServletContextListener 接口,在 Servlet 容器启动的时候,会初始化一个 WebApplicationContext 的实现类,并将其作为 ServletContext 的一个属性设置到 Servlet 环境中,摘抄源码如下:

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 的值,在上面 WebApplicationContext 的源码中的第一个常量中就被声明,是 WebApplicationContext.class.getName () + ".ROOT",更直接一点,它是 “org.springframework.web.context.WebApplicationContext.ROOT”。ContextLoaderListener 所初始化的这个 Spring 容器上下文,被称为根上下文。

SpringMVC 在 DispatcherServlet 的初始化过程中,同样会初始化一个 WebApplicationContext 的实现类,作为自己独有的上下文,这个独有的上下文,会将上面的根上下文作为自己的父上下文,来存放 SpringMVC 的配置元素,然后同样作为 ServletContext 的一个属性,被设置到 ServletContext 中,只不过它的 key 就稍微有点不同,key 和具体的 DispatcherServlet 注册在 web.xml 文件中的名字有关,从这一点也决定了,我们可以在 web.xml 文件中注册多个 DispatcherServlet,因为 Servlet 容器中注册的 Servlet 名字肯定不一样,设置到 Servlet 环境中的 key 也肯定不同。

由于在 Spring 容器中,子上下文可以访问到所有父上下文中的信息,而父上下文访问不到子上下文的信息,这个根上下文,就很适合作为多个子上下文配置的集中点。以官方文档中的图来说明:

3. 前端控制器

前端控制器,即所谓的 Front Controller,体现的是设计模式中的前端控制器模式。前端控制器处理所有从用户过来的请求。所有用户的请求都要通过前端控制器。SpringMVC 框架和其他请求驱动的表示层框架一样,也是围绕一个将请求分发到相应控制器的核心 Servlet 来设计的。DispatcherServlet 和其他框架中的 Servlet 不一样的地方在于,它和 Spring 容器无缝整合在了一起,因此你可以在 SpringMVC 中使用 Spring 容器所有的特性。

DispatcherServlet 这个前端控制器,在 SpringMVC 中的作用,以官方文档中的配图来说明:

整个流程可以被大致描述为:一个 http 请求到达服务器,被 DispatcherServlet 接收。DispatcherServlet 将请求委派给合适的处理器 Controller,此时处理控制权到达 Controller 对象。Controller 内部完成请求的数据模型的创建和业务逻辑的处理,然后再将填充了数据后的模型即 model 和控制权一并交还给 DispatcherServlet,委派 DispatcherServlet 来渲染响应。DispatcherServlet 再将这些数据和适当的数据模版视图结合,向 Response 输出响应。

可以看到 Model-View-Controller 这三样东西协同合作,共同体现出 MVC 的设计理念,三个层次可以分别独立演化,整个系统架构又清晰又简洁。这是 SpringMVC 为我们描述的美好愿景,后面我们也将看到,SpringMVC 为了实现这一承诺,究竟做出了什么样的努力

DispatcherServlet & SpringMVC 启动过程

DispatcherServlet & SpringMVC 启动过程

ServletContext

ServletContext是WEB应用的全局的储存信息的空间,服务器启动就创建,服务器关闭则销毁,即应用上下文

Spring容器的初始化

WEB应用启动时,ServletContext初始化,Spring提供的ContextLoaderListener会监听到这个事件,ContextLoaderListener.contextInitialized方法会被调用

// 在这个方法中,Spring会初始化根上下文,即WebApplicationContext
initWebApplicationContext(event.getServletContext()) 

WebApplicationContext实际的实现类是XmlWebApplicationContext,这个就是Spring的IOC容器,对应管理的Bean的定义由web.xml中的context-param标签指定(即applicationContext.xml)
在这个IOC容器初始化完毕后,Spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取

SpringMVC的启动过程

web.xml中的配置

<servlet>
<servlet-name>service_dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/services/service_dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

这段配置会初始化DispatcherServlet,load-on-startup表示启动容器时初始化该Servlet

  • SpringMVC启动的过程,实际上是DispatcherServlet的初始化过程
    DispatcherServlet 继承关系为 FrameworkServlet -> HttpServletBean -> HttpServlet -> Servlet,通过使用Servlet API 来对HTTP请求进行响应,成为SpringMVC的前端处理器,用以转发、匹配、处理每个请求。

  • DispatcherServlet初始化从HttpServletBean覆盖父类的init方法开始
public final void init() throws ServletException {
    if (logger.isDebugEnabled()) {
        logger.debug("Initializing servlet ''" + getServletName() + "''");
    }

    // Set bean properties from init parameters.
    try {
    // 获得web.xml中的contextConfigLocation配置属性(即springmvc-config.xml),Spring MVC的配置文件
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
    // 获取ServletContext
    ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
    bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
    // 模板方法,可以在子类中调用,做一些初始化工作,bw代表DispatcherServelt
    initBeanWrapper(bw);
    // 将配置的初始化值设置到DispatcherServlet中
    bw.setPropertyValues(pvs, true);
    }
    catch (BeansException ex) {
        logger.error("Failed to set bean properties on servlet ''" + getServletName() + "''", ex);
        throw ex;
    }

    // Let subclasses do whatever initialization they like.
    // 模板方法,子类初始化的入口方法
    initServletBean();

    if (logger.isDebugEnabled()) {
        logger.debug("Servlet ''" + getServletName() + "'' configured successfully");
    }
}

HttpServletBean中通过Spring的委托类BeanWrapper来对DispatcherServlet设值,并在FrameworkServlet.initServletBean()中进一步初始化上下文

FrameworkServlet利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE从ServletContext中获取Spring的根上下文(即WebApplicationContext)作为父上下文

DispatcherServlet获得了父上下文之后,在其initStrategies初始化处理器映射、视图解析等。初始化完毕后,Spring以与Servlet的名字相关(此处不是简单的以Servlet名为Key,而是通过一些转换)的属性为属性Key,也将其存到ServletContext中,以便后续使用

  • 故,在applicationContext.xml中将@Controller注释的组件排除在外,而在dispatcherServlet加载的配置文件中将@Controller注释的组件加载进来,方便DispatcherServlet进行控制和查找

Dubbox 的 DispatcherServlet 和 spring-mvc 的 DispatcherServlet,两者 url-pattern 抢占要怎么解决?

Dubbox 的 DispatcherServlet 和 spring-mvc 的 DispatcherServlet,两者 url-pattern 抢占要怎么解决?

本工程同时使用 dubbox 的 rest 和 spring-mvc 的 rest,,两者 url-pattern,请问要如何解决

web.xml 配置如下

   <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
<servlet-name>zxq</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>/sp-vs-web/openapi/*</url-pattern>
    </servlet-mapping>
<servlet-mapping>
        <servlet-name>zxq</servlet-name>
        <url-pattern>/sp-vs-web/vs/1.0/*</url-pattern>
    </servlet-mapping>

http-500:Servlet.init() for servlet SpringDispatcherServlet threw exception

http-500:Servlet.init() for servlet SpringDispatcherServlet threw exception

在使用solr与spring一起后,配置完再去访问,总是找不到controller。很愁,找不到原因,愿大神指点一二,感激。。。

controller层

package com.lxy.main;

import com.lxy.entity.ResultModel;
import com.lxy.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by BlingBlingBling on 2017/8/18.
 */
@Controller
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService service;

    @RequestMapping("/list")
    public String list(String querything, String catalog_name,
                       String price, String sort,
                       Integer page, Model model) throws Exception{

        ResultModel rm = service.getProducts(querything, catalog_name, price, sort, page);

        //将查询结果防到request作用域
        model.addAttribute("result",rm);

        //简单类型的数据回显
        model.addAttribute("querything",querything);
        model.addAttribute("catalog_name",catalog_name);
        model.addAttribute("price",price);
        model.addAttribute("sort",sort);
        model.addAttribute("page",page);

        return  "product_list";
    }

}

service

package com.lxy.service;

import com.lxy.entity.ResultModel;

/**
 * Created by BlingBlingBling on 2017/8/18.
 */
public interface ProductService {
    public ResultModel getProducts(String querything,String catalogName,String price,String sort,Integer page) throws Exception;
}

serviceImpl

package com.lxy.service.impl;

import com.lxy.entity.Products;
import com.lxy.entity.ResultModel;
import com.lxy.service.ProductService;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by BlingBlingBling on 2017/8/18.
 */
@Service
public class ProductServiceImpl implements ProductService{

    @Autowired
    //依赖注入server
    private HttpSolrServer server;

    @Override
    public ResultModel getProducts(String querything, String catalogName, String price, String sort, Integer page) throws Exception {

        //创建SolrQuery对象
        SolrQuery query = new SolrQuery();

        //输入关键字
        if(StringUtils.isNotEmpty(querything)){
            query.setQuery(querything);
        }else{
            query.setQuery("*:*");
        }

        //输入商品分类过滤条件
        if(StringUtils.isNotEmpty(catalogName)){
            query.addFilterQuery("product_catalog_name:"+catalogName);
        }

        // 输入价格区间过滤条件
        // price的值:0-9 10-19
        if (StringUtils.isNotEmpty(price)) {
            String[] ss = price.split("-");
            if (ss.length == 2) {
                query.addFilterQuery("product_price:[" + ss[0] + " TO " + ss[1]
                        + "]");
            }
        }

        // 设置排序
        if ("1".equals(sort)) {
            query.setSort("product_price", SolrQuery.ORDER.desc);
        } else {
            query.setSort("product_price", SolrQuery.ORDER.asc);
        }

        // 设置分页信息
        if (page == null)
            page = 1;

        query.setStart((page - 1) * 20);
        query.setRows(20);

        // 设置默认域
        query.set("df", "product_keywords");

        // 设置高亮信息
        query.setHighlight(true);
        query.addHighlightField("product_name");
        query.setHighlightSimplePre("<font style=\"color:red\" >");
        query.setHighlightSimplePost("</font>");

        QueryResponse response = server.query(query);
        // 查询出的结果
        SolrDocumentList results = response.getResults();
        // 记录总数
        long count = results.getNumFound();

        List<Products> products = new ArrayList<>();
        Products prod;

        // 获取高亮信息
        Map<String, Map<String, List<String>>> highlighting = response
                .getHighlighting();
        for (SolrDocument doc : results) {
            prod = new Products();

            // 商品ID
            prod.setPid(Integer.parseInt(doc.get("id").toString()));

            List<String> list = highlighting.get(doc.get("id")).get(
                    "product_name");
            // 商品名称
            if (list != null)
                prod.setName(list.get(0));
            else {
                prod.setName(doc.get("product_name").toString());
            }

            // 商品价格
            prod.setPrice(Integer.parseInt(doc.get("product_price").toString()));
            // 商品图片地址
            prod.setPicture(doc.get("product_picture").toString());

            products.add(prod);
        }

        // 封装ResultModel对象
        ResultModel rm = new ResultModel();
        rm.setProductList(products);
        rm.setCurPage(page);
        rm.setRecordCount(count);

        int pageCount = (int) (count / 20);

        if (count % 20 > 0)
            pageCount++;
        // 设置总页数
        rm.setPageCount(pageCount);

        return rm;
    }
}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns:jdbc="http://www.springframework.org/schema/jdbc"
   xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
   
   <!-- 扫描service,mapper包 -->
   <!--<context:component-scan base-package="com.lxy"></context:component-scan>-->
   
   <!-- 引入配置文件 -->
   <!--<bean id="propertyConfigurer"
>
      <property name="location" value="classpath:jdbc.properties" />
   </bean>-->
   
   <!-- 创建数据源(数据库连接池使用DBCP) -->
   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
      <!--<property name="driverClassName" value="${driver}"></property>
      <property name="url" value="${url}"></property>
      <property name="username" value="${username}"></property>
      <property name="password" value="${password}"></property>-->
   </bean>
   
   <!-- MyBatis -->   
   <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
   <!--<bean id="sqlSessionFactory">
      <property name="dataSource" ref="dataSource" />
   </bean>-->
   
   <!-- Mapper接口所在包名,Spring会自动查找其下的类 -->
   <!--<bean>
      <property name="basePackage" value="com.lxy.mapper" />
      <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
   </bean>-->
   
   <!-- spring -->
   <!-- 配置事务 -->
   <bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource" />
   </bean>
   
   <!-- 开启事务控制的注解支持 -->  
    <tx:annotation-driven transaction-manager="transactionManager"/>
   
</beans>

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns:jdbc="http://www.springframework.org/schema/jdbc"
   xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
   
   <!-- 扫描controller -->
   <context:component-scan base-package="com.lxy.main"></context:component-scan>
   
   <!-- 配置返回页面 -->
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
   </bean>


   <!-- 配置HttpSolrServer -->
   <bean class="org.apache.solr.client.solrj.impl.HttpSolrServer">
      <constructor-arg value="http://localhost:8080/solr/"></constructor-arg>
   </bean>
   
</beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

    <!-- 配置springMVC的核心控制器  Start-->
    <!-- spring MVC DispatcherServlet -->
    <servlet>
        <servlet-name>SpringDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>SpringDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- 配置springMVC的核心控制器  End-->

    <!-- 配置spring  Start-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 配置spring  End-->

    <!-- 过滤器 -->
    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- 欢迎页面 -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ''productController'': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.lxy.service.ProductService com.lxy.main.ProductController.service; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.lxy.service.ProductService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
	org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
	org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
	org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
	org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
	org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
	org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:643)
	org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:606)
	org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:657)
	org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:525)
	org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:466)
	org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
	javax.servlet.GenericServlet.init(GenericServlet.java:160)
	org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
	org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	java.lang.Thread.run(Thread.java:745)

 

root cause

org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.lxy.service.ProductService com.lxy.main.ProductController.service; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.lxy.service.ProductService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
	org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
	org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
	org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
	org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
	org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
	org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
	org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
	org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:643)
	org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:606)
	org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:657)
	org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:525)
	org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:466)
	org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
	javax.servlet.GenericServlet.init(GenericServlet.java:160)
	org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
	org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	java.lang.Thread.run(Thread.java:745)

 

报错信息

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.lxy.service.ProductService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1100)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
	org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
	org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
	org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
	org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
	org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
	org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
	org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
	org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
	org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:643)
	org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:606)
	org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:657)
	org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:525)
	org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:466)
	org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
	javax.servlet.GenericServlet.init(GenericServlet.java:160)
	org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
	org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	java.lang.Thread.run(Thread.java:745)

这是代码,辛苦各位大神看一下,帮帮忙,谢谢!

今天的关于Spring 中的 Dispatcher Servlet 是什么?springmvc中dispatcherservlet的作用的分享已经结束,谢谢您的关注,如果想了解更多关于1.SpringMVC 设计理念与 DispatcherServlet、DispatcherServlet & SpringMVC 启动过程、Dubbox 的 DispatcherServlet 和 spring-mvc 的 DispatcherServlet,两者 url-pattern 抢占要怎么解决?、http-500:Servlet.init() for servlet SpringDispatcherServlet threw exception的相关知识,请在本站进行查询。

本文标签: