- <mvc:annotation-driven >和<context:component-scan>的区别
为啥要说这两个注解的区别,因为<mvc:annotation-driven >和<context:component-scan>放置的位置出错,可能就会导致项目出现404的错误。程序即不提示出错,控制台也不打印错误,这样很难排除错误。所以很有必要说明这两个注解的区别。
2.详解
首先我们需要了解springMVC的原理,:
运行步骤:
1、 首先用户发送请求http://localhost:9080/springmvc-chapter2/hello——>web容器,web容器根据“/hello”路径映射到DispatcherServlet(url-pattern为/)进行处理;
2、 DispatcherServlet——>BeanNameUrlHandlerMapping进行请求到处理的映射,BeanNameUrlHandlerMapping将“/hello”路径直接映射到名字为“/hello”的Bean进行处理,即HelloWorldController,BeanNameUrlHandlerMapping将其包装为HandlerExecutionChain(只包括HelloWorldController处理器,没有拦截器);
3、 DispatcherServlet——> SimpleControllerHandlerAdapter,SimpleControllerHandlerAdapter将HandlerExecutionChain中的处理器(HelloWorldController)适配为SimpleControllerHandlerAdapter;
4、 SimpleControllerHandlerAdapter——> HelloWorldController处理器功能处理方法的调用,SimpleControllerHandlerAdapter将会调用处理器的handleRequest方法进行功能处理,该处理方法返回一个ModelAndView给DispatcherServlet;
5、 hello(ModelAndView的逻辑视图名)——>InternalResourceViewResolver, InternalResourceViewResolver使用JstlView,具体视图页面在/WEB-INF/jsp/hello.jsp;
6、 JstlView(/WEB-INF/jsp/hello.jsp)——>渲染,将在处理器传入的模型数据(message=HelloWorld!)
而<mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean, MVC为@Controllers分发请求所必须的。
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)——这个是最主要的。后面,我们处理响应ajax请求时,就使用到了对json的支持。后面,对action写JUnit单元测试时,要从spring IOC容器中取DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,来完成测试,取的时候要知道是<mvc:annotation-driven />这一句注册的这两个bean。<mvc:interceptors/>会为每一个HandlerMapping,注入一个拦截器。总有一个HandlerMapping是可以找到处理器的,最多也只找到一个处理器,所以这个拦截器总会被执行的。起到了总拦截器的作用。
@Controller
public class TestController {
//每一个Springmvc
@RequestMapping(value = "/test/springmvc.do")
public String test(String name){
System.out.println();
return "";
}
如果直接在配置文件下只有<scan>注解,或者<mvc>注解配置在<scan>后面,这样是会导致404的问题。同时就算<mvc>放在<scan>也是报404的。
解决方法:
@Controller
public class TestController {
//每一个Springmvc
@RequestMapping(value = "/test/springmvc.do")
public @Requestbody String test(String name){
System.out.println();
return "";
}
需要在方法加上@Requestbody 注解,同时<mvc>,需要配置在<scan>前面。
为什么呢?因为根据上面的<mvc:annotation-driven />解释,主要提供数据支持。
为了深入 <mvc:annotation-driven />的注解 ,提供了加载类,如下所示:
-
RequestMappingHandlerMapping
-
BeanNameUrlHandlerMapping
-
RequestMappingHandlerAdapter
-
HttpRequestHandlerAdapter
-
SimpleControllerHandlerAdapter
-
ExceptionHandlerExceptionResolver
-
ResponseStatusExceptionResolver
-
DefaultHandlerExceptionResolver
上面几个Bean实例。这几个类都是用来做什么的呢?
前两个是HandlerMapping接口的实现类,用来处理请求映射的。其中第一个是处理@RequestMapping注解的。第二个会将controller类的名字映射为请求url。
中间三个是用来处理请求的。具体点说就是确定调用哪个controller的哪个方法来处理当前请求。第一个处理@Controller注解的处理器,支持自定义方法参数和返回值(很酷)。第二个是处理继承HttpRequestHandler的处理器。第三个处理继承自Controller接口的处理器。
而 <context:component-scan>,在使用注解(@Component,@Repository,@Service,@Controller)配置的情况下,系统启动时会被自动扫描,并添加到bean工厂中去(省去了配置文件中写bean定义了),另外三个分别表示MVC三层模式中不同层中的组件,他们都是被@Component标记的,所以也会被自动扫描。
继而言之:
<context:component-scan/>标签是告诉Spring 来扫描指定包下的类,并注册被@Component,@Controller,@Service,@Repository等注解标记的组件。
而<mvc:annotation-scan/>是告知Spring,我们启用注解驱动。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。