前言
在看这边博客时,如果遇到有什么不清楚的地方,可以参考我另外一边博文。Spring标签的探索,根据这边文章自己来深入源码一探究竟。这里自己只是简单记录一下各标签作用,每个人困惑不同,自然需求也不一定相同,所以还是自己动手深入源码一探究竟比较好。
context:annotation-config
![](http://upload-images.jianshu.io/upload_images/2111160-1ef171256aba6e08.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/939/format/webp)
注释说明:
配置了该标签意味着激活了bean类中要检测的各种注释,Spring的@Required
和@Autowired
以及JSR 250的@PostConstruct
,@PreDestroy
,@Resource
,JAX-WS的@WebServiceRef
,EJB3的@EJB
,和JPA的@PersistenceContext
,@PersistenceUnit
。或者你可以为这些注释激活单独的BeanPostProcessors
注意:
这个标签不会激活处理Spring的@Transactional
或EJB3的@TransactionAttribute
注解。 考虑使用<tx:annotation-driven>
标签。
From Me
看源码后分析得知我的Spring标签源码分析文章,它的作用是隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor
,CommonAnnotationBeanPostProcessor
,PersistenceAnnotationBeanPostProcessor
,RequiredAnnotationBeanPostProcessor
这4个BeanPostProcessor
。其作用是如果你想在程序中使用注解,就必须先注册该注解对应的类,如下图所示:
依赖的类 | 注解 |
---|---|
CommonAnnotationBeanPostProcessor | @Resource 、@PostConstruct 、@PreDestroy |
PersistenceAnnotationBeanPostProcessor | @PersistenceContext |
AutowiredAnnotationBeanPostProcessor | @Autowire |
RequiredAnnotationBeanPostProcesso | @Required |
另外还支持:@WebServiceRef
,@EJB
,@PersistenceUnit
当然也可以使用传统的方式要使用对应的注解一个一个去声明自定义注册项目也不会显得那么臃肿,可能就是有点儿难记了。
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/>
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
context:component-scan
![](http://upload-images.jianshu.io/upload_images/2111160-dd8a56ae7c323ace.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/938/format/webp)
注释说明:
扫描classpath
时,被注释的组件将自动注册为Spring bean。 默认情况下,Spring提供的@Component
,@Repository
,@Service
和@Controller
原型会被检测到。
注意:
这个标签的存在意味可以不在xml中配置<context:annotation-config>
标签了。因为该标签会支持@Required
,@Autowired
,@PostConstruct
,@PreDestroy
,@Resource
,@PersistenceContext
和@PersistenceUnit
这些注释,这通常是自动检测组件的理想选择(没有外部配置)。 当然你可以选择设置annotation-config
属性为false来弃用这个默认行为,该属性默认为true。例如当你想使用自定义的BeanPostProcessor
来处理这些注释的时候你可以这么做。
From Me
另外需要注意:当Spring配置需要文件分层的时候,该标签应该保证每一个配置文件都配置一次。这时就可以有点儿讲究了,SpringMVC的dispatcher-servlet.xml
配置文件可以只扫描带有@Controller
注解的类,而在Spring的applicationContext.xml
文件中则可以扫描其他所有带有注解的类(也可以过滤掉带@Controller注解的类)。
除了必须指定的属性base-package之外,<context:component-scan/>
还可以指定如下属性。
- resource-pattern:表示可以被自动检测的Class的形式,默认为
“**/*.class”
,即所有的class文件。这个只是用来告诉Spring需要对哪些文件进行扫描,而并不是把它们自动定义为对应的bean。这个需要与后续需要介绍的filter区分开。 - use-default-filters:表示使用使用默认的filter,。
<context:component-scan/>
将把哪些Class自动注册到bean容器是由对应的filter来控制的。该属性的值默认为true,即默认会使用默认的filter。而默认的filter会将标注了@Component、@Controller、@Service和@Repository的类,包括这四个注解所标注的注解所标注的类,都会将它们自动注册到bean容器中。 - annotation-config:是否启用对注解的支持,即隐式的启用
<context:annotation-config/>
,默认为true。 - name-generator:默认的beanName生成器,即在没有显式的指定beanName时,自动注册的bean将如何使用默认的beanName。默认将使用Class的简称,即不包含包名的类名称,并将首字母小写作为当前bean的名称。用户可以通过实现
org.springframework.beans.factory.support.BeanNameGenerator
接口并指定其为当前的name-generator来改变对应的策略。 - scope-resolver:指定用于解析bean定义的scope的ScopeMetadataResolver,默认将通过AnnotationScopeMetadataResolver进行解析,而该解析器将根据类上标注的@Scope注解来解析对应的scope。默认没有指定@Scope的都是单例。
- scoped-proxy:表示是否需要为自动检测到的需要加入bean容器中的bean生成对应的代理。默认是不生成。可选值有“no”、“interfaces”和“targetClass”,分别对应不生成、根据接口生成和根据目标class生成。这对需要使用代理的scope是非常有必须要的,如request、session等。更详细的内容请参考先前专门介绍scope的那篇文章。
mvc:annotation-driven
From Me
-
<mvc:annotation-driven/>
会自动注册LocaleResolver
,ThemeResolver
,HandlerMapping
,HandlerAdapter
,HandlerExceptionResolver
,RequestToViewNameTranslator
,ViewResolver
,FlashMapManager
这8个组件的实现类,这8个组件便是SpringMVC的核心组件。程序在运行时会先去容器中扫描看是否你自定义了某一组件的实现,如果没有的话就使用properties文件中默认定义的实现类。
从源码可知<mvc:annotation-driven/>
标签对应的解析类是AnnotationDrivenBeanDefinitionParser。
从其中可以看出,该标签为我们做了这些配置:
- 支持使用了像
@RquestMapping
、@ExceptionHandler
等等的注解的controller方法去处理请求。 - 支持使用
@RequestBody
、@ResponseBody
注解。 - 并提供了:数据绑定支持,
@NumberFormat
注解的支持对数据类型进行格式化,@DateTimeFormat
支持 - 支持使用
@Valid
对javaBean进行JSR-303验证。 - 读写XML的支持(JAXB),读写JSON的支持(Jackson)。
HttpMessageConverter
对于HttpMessageConverter,它到底是干什么的呢?用SpringMVC写过REST的人可能略知一二,它是用来将特定的对象转换成字符串并最终作为HttpResponse
返回的工具。实际上SpringMVC中面向开发人员的业务逻辑处理主要集中在各种Controller的方法中,基本模式是接受代表着HttpRequest
的各种输入参数,在方法体中进行业务逻辑处理,最后得到输出结果,并以返回值的形式交给SpringMvc,Springmvc根据返回值的不同调用不同的处理逻辑并最终以HttpResponse
的形式返回给客户端。Controller中的返回值可以有很多种,比如字符串,ModelAndView,普通对象,等等,甚至void类型都是可以的。所以SpringMvc会根据返回值的类型做很多的if else,不同的类型调用不同的处理逻辑。那么当函数受@ResponseBody
声明时,Spring就会尝试用配置好的各种HttpMessageConverter来将返回值进行序列化。不同HttpMessageConverter能够处理的对象以及处理方式都是不一样的,Spring会遍历各Converter,如果该Converter能够处理该对象则交由其处理。因此,很多基于Spring的REST风格的应用常常会返回一个model对象,那么你就应该配置好正确的HttpMessageConverter,以便Spring能够正确的将这些对象序列化回客户端。
mvc:default-servlet-handler
![](http://upload-images.jianshu.io/upload_images/2111160-56cf14ae629c24b6.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
注释说明:
通过转发到Servlet容器的默认Servlet来配置一个处理器,用来提供静态资源。使用这个处理程序允许使用DispatcherServlet
的“ / ”
映射,同时仍然使用Servlet容器来提供静态资源
注意:
这个处理程序将把所有请求转发给默认的Servlet。因此重要的是,它需要保持在所有其他URL HandlerMappings
的顺序之后。 如果您使用annotation-driven
元素或者其他情况就是这样。如果您正在设置您的自定义HandlerMapping
实例,请务必将它 的“order”属性设置为小于DefaultServletHttpRequestHandler
,即Integer.MAX_VALUE。
具体可看源码
From Me
其实当一个请求来到的时候,它的执行流程是先经过tomcat的servlet的url-pattern的匹配。进入到了SpringMVC,然后对于SpringMVC框架来说,为了处理对应的请求时,首先会去找对应的HandlerMapping
看是否有对应的类来处理该请求,如果有的话再根据HandlerAdapter去找是什么类,以及对应的处理方法。找不到的时候会报404。但当配置了<mvc:default-servlet-handler>
标签的时候,它会注册SimpleUrlHandlerMapping
来处理请求映射,对应的Handler是DefaultServletHttpRequestHandler
,这种情况一般是其他HandlerMapping无法匹配处理,最后才无奈交给DefaultServletHttpRequestHandler
来处理。而该Handler具体的做法其实就是转发给了web容器自身的default
Servlet来处理。这个servlet名称可以在mvc:default-servlet-handler
标签中进行配置,如果没有配置,采用默认的配置,tomcat默认的servlet名称为default
。即tomcat、Jetty等,在容器启动的时候,自身就默认注册了一个name叫default的servlet,DefaultServletHttpRequestHandler
就是转发给这些servlet。default
Servlet会去寻找有没有该文件,找到了解析并返回文件内容,比如我们常请求的jsp页面,就是通过JspServlet来进行翻译的。找不到则404。但是你可以通过自定义servlet来替换defaultServlet。给用户返回自定义的一些信息。
mvc:resources
From Me
<mvc:default-servlet-handler />
将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。而<mvc:resources />
更进一步,由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能。<mvc:resources />
允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,你甚至可以将JavaScript等静态文件打到JAR包中。通过location属性指定静态资源的位置,由于location属性是Resources类型,因此可以使用诸如classpath:
等的资源前缀指定资源位置。传统Web容器的静态资源只能放在Web容器的根路径下,<mvc:resources />
完全打破了这个限制。
来看Spring官方demo中的示例:
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
<resources mapping="/resources/**" location="/resources/" />
![](http://upload-images.jianshu.io/upload_images/2111160-d09cbff026a38c9e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/330/format/webp)
作者:HikariCP
链接:https://www.jianshu.com/p/7fcc241668d7
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。