spring要怎么配置呢,为什么这么配置呢,我一直想不明白。对于这些,我找了很久,总算明白一点,现在记录下来,留待以后查阅。
1. 注解配置
现在基本上都是注解配置了,很简单。就是因为太简单了所有理解不了。为什么这么配置呢?这个疑问会在下面讲解。
这一步只是讲,spring要怎么配置。
1.1 先配置web.xml ,这里的作用就是:怎样的请求会被spring处理
<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
这里配置的意思是,以 .html 结尾的请求都会被spring处理
1.2 配置 /WEB-INF/spring-servlet.xml , 这里的作用就是告诉spring要怎么去处理这些请求。这里有个注意点就是spring的配置文件的命名问题。我们采用的是默认命名方式:<servlet-name>-servlet.xml;<servlet-name>就是在web.xml里面配置的servlet的名字。
<?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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" 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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.wyy.learn"/> <!-- HanddlerMapping HanddlerAdapter --> <mvc:annotation-driven /> <!-- ViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
1.3 下面是一个简单的java例子
package com.wyy.learn; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class testControl{ private static final Logger LOGGER = LogManager.getLogger("testlogger"); @RequestMapping("/hello.html") public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("message", "Hello world xml"); mv.setViewName("index"); return mv; } }
1.4 这里还需要一个相对应的jsp页面, /WEB-INF/jsp/index.jsp
这个页面的路径和命名也是有要求的:先看路径,在spring-servlet.xml文件里面,我们定义了一个ViewResolver(视图解析器)。prefix 定义了路径,suffix 定义了文件的后缀名。再来看看文件的命名:我们在java代码里面有一个返回的视图名:mv.setViewName("index"), 这里的index就是文件名了。
好了,一个简单的spring配置就OK了。
2. 为什么这么配置呢?先来看下第二种配置方式,继承controller接口的实现方式.
2.1 web.xml
<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
2.2 /WEB-INF/spring-servlet.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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" 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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- HanddlerMapping --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- HanddlerAdapter --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- handdler --> <bean name="/hello.html" class="com.wyy.learn.testControl"/> <!-- ViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
2.3 java代码
package com.wyy.learn; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class testControl implements Controller{ private static final Logger LOGGER = LogManager.getLogger("testlogger"); @Override public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("message", "Hello world xml"); mv.setViewName("index"); return mv; } }
结论:
现在说下我对这两个配置的理解:
@Controller 是代替 Controller 接口的。
<context:component-scan base-package="com.wyy.learn"/> 和 @RequestMapping("/hello.html")
是代替 <bean name="/hello.html" class="com.wyy.learn.testControl"/>
<mvc:annotation-driven /> 是代替<!-- HanddlerMapping --> 和 <!-- HanddlerAdapter --> 的
这些配置的对应关系都已经清楚了,但为什么这么配置呢?先看下日志输出,从日志里面可以看到spring的处理过程,通过这个过程,我们就能理解,为什么这么配置了。
先看下第二种配置情况的日志
2015-08-05 09:39:27,872 TRACE (FrameworkServlet.java:1052) - Bound request context to thread: org.apache.catalina.connector.RequestFacade@e174f70 2015-08-05 09:39:27,872 DEBUG (DispatcherServlet.java:861) - DispatcherServlet with name 'spring' processing GET request for [/springTest/hello.html] 2015-08-05 09:39:27,875 TRACE (DispatcherServlet.java:1117) - Testing handler map [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@73e3862b] in DispatcherServlet with name 'spring' 2015-08-05 09:39:27,879 DEBUG (AbstractUrlHandlerMapping.java:141) - Mapping [/hello.html] to HandlerExecutionChain with handler [com.wyy.learn.testControl@1020c592] and 1 interceptor 2015-08-05 09:39:27,880 TRACE (DispatcherServlet.java:1157) - Testing handler adapter [org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@11d9ebba] 2015-08-05 09:39:27,881 DEBUG (DispatcherServlet.java:947) - Last-Modified value for [/springTest/hello.html] is: -1 2015-08-05 09:39:27,884 DEBUG (AbstractAutowireCapableBeanFactory.java:1620) - Invoking afterPropertiesSet() on bean with name 'index' 2015-08-05 09:39:27,884 TRACE (AbstractCachingViewResolver.java:164) - Cached view [index] 2015-08-05 09:39:27,884 DEBUG (DispatcherServlet.java:1241) - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/WEB-INF/jsp/index.jsp]] in DispatcherServlet with name 'spring' 2015-08-05 09:39:27,884 TRACE (AbstractView.java:297) - Rendering view with name 'index' with model {message=Hello world xml} and static attributes {} 2015-08-05 09:39:27,884 DEBUG (AbstractView.java:432) - Added model object 'message' of type [java.lang.String] to request in view with name 'index' 2015-08-05 09:39:27,892 DEBUG (InternalResourceView.java:166) - Forwarding to resource [/WEB-INF/jsp/index.jsp] in InternalResourceView 'index' 2015-08-05 09:39:27,944 TRACE (FrameworkServlet.java:1062) - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@e174f70 2015-08-05 09:39:27,945 DEBUG (FrameworkServlet.java:1000) - Successfully completed request 2015-08-05 09:39:27,945 TRACE (AbstractApplicationContext.java:360) - Publishing event in WebApplicationContext for namespace 'spring-servlet': ServletRequestHandledEvent: url=[/springTest/hello.html]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[spring]; session=[8F56AD205EF3D2B1BEBAE1F01D5E8F99]; user=[null]; time=[79ms]; status=[OK]
我们来分析下这个日志:
DispatcherServlet 拦截 [/springTest/hello.html] 请求
通过映射器 BeanNameUrlHandlerMapping 匹配映射链,[com.wyy.learn.testControl@1020c592] and 1 interceptor
通过适配器 SimpleControllerHandlerAdapter 调用处理器 testControl
通过解析器 渲染视图 Rendering view
跳转页面 Forwarding to resource [/WEB-INF/jsp/index.jsp] in InternalResourceView 'index'
通过这个日志,我总算知道了,为什么这么配置了。其实也一套就是 Spring DispatcherServlet 的原理了。
再来看看第一种配置情况的日志
2015-08-05 10:02:23,469 TRACE (DispatcherServlet.java:1117) - Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@42479576] in DispatcherServlet with name 'spring' 2015-08-05 10:02:23,476 TRACE (DispatcherServlet.java:1157) - Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@45c6c4cf]
由于字数限制,只看这两句就好了. 从这里可以看出 <!-- HanddlerMapping --> 和 <!-- HanddlerAdapter -->
所以第一种配置里面可以这么改
<!-- HanddlerMapping HanddlerAdapter --> <!-- <mvc:annotation-driven /> --> <!-- HanddlerMapping --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> <!-- HanddlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />