SpringMVC源码分析(1)标签解析

简介:

本文主要内容是根据一个常见的springmvc 配置文件,剖析分解每个标签的工作内容。

  1. 一个非常熟悉的springmvc配置样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<? 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <!-- Scans the classpath of this application for @Components to deploy as beans -->
    < context:component-scan  base-package = "org.springframework.samples.mvc.basic"  />
 
    <!-- Configures the @Controller programming model -->
    < mvc:annotation-driven  />
 
    <!-- Forwards requests to the "/" resource to the "welcome" view -->
    < mvc:view-controller  path = "/"  view-name = "welcome" />
 
    <!-- Configures Handler Interceptors -->   
    < mvc:interceptors >
       <!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
       < bean  class = "org.springframework.web.servlet.i18n.LocaleChangeInterceptor"  />
    </ mvc:interceptors >
 
    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
    < mvc:resources  mapping = "/resources/**"  location = "/resources/"  />
 
    <!-- Saves a locale change using a cookie -->
    < bean  id = "localeResolver"  class = "org.springframework.web.servlet.i18n.CookieLocaleResolver"  />
 
    <!-- Application Message Bundle -->
    < bean  id = "messageSource"  class = "org.springframework.context.support.ReloadableResourceBundleMessageSource" >
       < property  name = "basename"  value = "/WEB-INF/messages/messages"  />
       < property  name = "cacheSeconds"  value = "0"  />
    </ bean >
 
    <!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
    < bean  class = "org.springframework.web.servlet.view.InternalResourceViewResolver" >
       < property  name = "prefix"  value = "/WEB-INF/views/" />
       < property  name = "suffix"  value = ".jsp" />
    </ bean >
</ beans >

接下来,逐个标签进行分析

2.<context:component-scan>标签

1
2
3
4
5
6
7
public  class  ContextNamespaceHandler  extends  NamespaceHandlerSupport {
 
    public  void  init() {
        ...
       registerBeanDefinitionParser( "component-scan" new  ComponentScanBeanDefinitionParser());
       ...  
    }

ComponentScanBeanDefinitionParser负责具体解析工作。

2.1 属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  class  ComponentScanBeanDefinitionParser  implements  BeanDefinitionParser {
 
    private  static  final  String BASE_PACKAGE_ATTRIBUTE =  "base-package" ;
 
    private  static  final  String RESOURCE_PATTERN_ATTRIBUTE =  "resource-pattern" ;
 
    private  static  final  String USE_DEFAULT_FILTERS_ATTRIBUTE =  "use-default-filters" ;
 
    private  static  final  String ANNOTATION_CONFIG_ATTRIBUTE =  "annotation-config" ;
    
    private  static  final  String NAME_GENERATOR_ATTRIBUTE =  "name-generator" ;
    
    private  static  final  String SCOPE_RESOLVER_ATTRIBUTE =  "scope-resolver" ;
    
    private  static  final  String SCOPED_PROXY_ATTRIBUTE =  "scoped-proxy" ;
 
    private  static  final  String EXCLUDE_FILTER_ELEMENT =  "exclude-filter" ;
 
    private  static  final  String INCLUDE_FILTER_ELEMENT =  "include-filter" ;
 
    private  static  final  String FILTER_TYPE_ATTRIBUTE =  "type" ;
 
    private  static  final  String FILTER_EXPRESSION_ATTRIBUTE =  "expression" ;
    ...
    }

首先在ComponentScanBeanDefinitionParser类中定义了</context:component-scan>元素的所有属性值

  • base-package:为必须配置属性,指定了spring需要扫描的跟目录名称,可以使用”,” “;” “\t\n(回车符)”来分割多个包名

  • resource-pattern:配置扫描资源格式.默认”**/*.class

  • use-default-filters:是否使用默认扫描策略,默认为”true”,会自动扫描指定包下的添加了如下注解的类,@Component, @Repository, @Service,or @Controller

  • annotation-config:是否启用默认配置,默认为”true”,该配置会在BeanDefinition注册到容器后自动注册一些BeanPostProcessors对象到容器中.这些处理器用来处理类中Spring’s @Required and 
    @Autowired,  JSR 250’s @PostConstruct, @PreDestroy and @Resource (如果可用), 
    JAX-WS’s @WebServiceRef (如果可用), EJB 3’s @EJB (如果可用), and JPA’s 
    @PersistenceContext and @PersistenceUnit (如果可用),但是该属性不会处理Spring’s @Transactional 和 EJB 3中的@TransactionAttribute注解对象,这两个注解是通过<tx:annotation-driven>元素处理过程中对应的BeanPostProcessor来处理的.

  • include-filter:如果有自定义元素可以在该处配置

  • exclude-filter:配置哪些类型的类不需要扫描,如上面指定了类中添加了”Controller”元素的类不扫描. 
    注意:</context:component-scan>元素中默认配置了annotation-config,所以不需要再单独配置</annotation-config>元素.


2.2 解析

1
2
3
4
5
6
7
8
9
10
11
public  BeanDefinition parse(Element element, ParserContext parserContext) {
    String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
          ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
 
    // Actually scan for bean definitions and register them.
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
 
    return  null ;
}

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner主要用来完成类路径下符合条件的bean扫描功能,并将扫描出来的bean注册到指定的BeanFactory中。 
- 默认过滤器主要扫描@Component @Repository @Service @Controller注解的类,同样可以通过配置类扫描过滤器来扫描自定义注解的类。 
- 当类路径下有javax.annotation.ManagedBean和javax.inject.Named类库时支持这2个注解扫描。


3 <mvc:annotation-driven />标签

1
2
3
4
5
6
7
8
9
10
11
public  class  MvcNamespaceHandler  extends  NamespaceHandlerSupport {
 
    public  void  init() {
       registerBeanDefinitionParser( "annotation-driven" new  AnnotationDrivenBeanDefinitionParser());
       registerBeanDefinitionParser( "default-servlet-handler" new  DefaultServletHandlerBeanDefinitionParser());
       registerBeanDefinitionParser( "interceptors" new  InterceptorsBeanDefinitionParser());     
       registerBeanDefinitionParser( "resources" new  ResourcesBeanDefinitionParser());
       registerBeanDefinitionParser( "view-controller" new  ViewControllerBeanDefinitionParser());
    }
 
}

AnnotationDrivenBeanDefinitionParser具体负责解析工作。

3.2 具体解析方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class  AnnotationDrivenBeanDefinitionParser  implements  BeanDefinitionParser {
...
public  BeanDefinition parse(Element element, ParserContext parserContext) {
    Object source = parserContext.extractSource(element);
 
    CompositeComponentDefinition compDefinition =  new  CompositeComponentDefinition(element.getTagName(), source);
    parserContext.pushContainingComponent(compDefinition);
    
    RootBeanDefinition annMappingDef =  new  RootBeanDefinition(DefaultAnnotationHandlerMapping. class );
    annMappingDef.setSource(source);
    annMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    annMappingDef.getPropertyValues().add( "order" 0 );
    String annMappingName = parserContext.getReaderContext().registerWithGeneratedName(annMappingDef);
 
    RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
    RuntimeBeanReference validator = getValidator(element, source, parserContext);
    
    RootBeanDefinition bindingDef =  new  RootBeanDefinition(ConfigurableWebBindingInitializer. class );
    bindingDef.setSource(source);
    bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    bindingDef.getPropertyValues().add( "conversionService" , conversionService);
    bindingDef.getPropertyValues().add( "validator" , validator);
 
    RootBeanDefinition annAdapterDef =  new  RootBeanDefinition(AnnotationMethodHandlerAdapter. class );
    annAdapterDef.setSource(source);
    annAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    annAdapterDef.getPropertyValues().add( "webBindingInitializer" , bindingDef);
    annAdapterDef.getPropertyValues().add( "messageConverters" , getMessageConverters(source));
    String annAdapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef);
 
    RootBeanDefinition csInterceptorDef =  new  RootBeanDefinition(ConversionServiceExposingInterceptor. class );
    csInterceptorDef.setSource(source);
    csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue( 0 , conversionService);    
    RootBeanDefinition mappedCsInterceptorDef =  new  RootBeanDefinition(MappedInterceptor. class );
    mappedCsInterceptorDef.setSource(source);
    mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue( 0 , (Object)  null );
    mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue( 1 , csInterceptorDef);
    String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
    
    parserContext.registerComponent( new  BeanComponentDefinition(annMappingDef, annMappingName));
    parserContext.registerComponent( new  BeanComponentDefinition(annAdapterDef, annAdapterName));
    parserContext.registerComponent( new  BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
    parserContext.popAndRegisterContainingComponent();
    
    return  null ;
}
...
}

(1)注册DefaultAnnotationHandlerMapping bean,具体负责请求与@Controller的mapping.

(2)注册AnnotationMethodHandlerAdapter bean,调用@Controller的方法,并注入webBindingInitializer属性和messageConverters。

(3)其中webBindingInitializer指定conversionService,validator属性。

3.1

Configures the conversionService if specified, otherwise defaults to a fresh ConversionService instance created by the default FormattingConversionServiceFactoryBean.
3.2

Configures the validator if specified, otherwise defaults to a fresh Validator instance created by the default LocalValidatorFactoryBean if the JSR-303 API is present on the classpath.
3.3

Configures standard HttpMessageConverters, including the Jaxb2RootElementHttpMessageConverter if JAXB2 is present on the classpath, and the MappingJacksonHttpMessageConverter if Jackson is present on the classpath.

4.<mvc:view-controller>标签

ViewControllerBeanDefinitionParser 负责具体解析。

主要完成 注册一个ParameterizableViewController.和SimpleUrlHandlerMapping ,SimpleControllerHandlerAdapter

SimpleUrlHandlerMapping注册的名称为"org.springframework.web.servlet.config.viewControllerHandlerMapping";

5.<mvc:interceptors>标签

注册一组MappedInterceptor 。有公共和私有之分。

<bean>标签对应公共interceptor;

<mvc:interceptor和<mvc:mapping>对应Mapping私有。

6.<mvc:resources>标签

ResourcesBeanDefinitionParser负责解析。

完成工作

(6.1) 注册一个 ResourceHttpRequestHandler

(6.2)注册一个 SimpleUrlHandlerMapping for mapping resource 

(6.3) 可能会注册一个HttpRequestHandlerAdapter.

(由AbstractHttpRequestHandlerBeanDefinitionParser.registerHandlerAdapterIfNecessary实现)

1
2
3
4
5
@Override
public  void  doParse(Element element, ParserContext parserContext) {
    Object source = parserContext.extractSource(element);
    registerResourceMappings(parserContext, element, source);
}


本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1877527,如需转载请自行联系原作者


相关文章
|
22天前
|
XML 存储 Java
Spring重要类解析
Spring重要类解析
19 0
|
2月前
|
XML Java 数据格式
Spring 应用上下文探秘:生命周期解析与最佳实践
Spring 应用上下文探秘:生命周期解析与最佳实践
73 0
|
1月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
2月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
34 1
|
20天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
43 1
|
1月前
|
XML Java 开发者
深入解析 Spring 和 Spring Boot 的区别
深入解析 Spring 和 Spring Boot 的区别
|
6天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
14 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
6天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
22 2
从入门到精通:Spring基础注解的全面解析
|
6天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
19 0
切面编程的艺术:Spring动态代理解析与实战
|
6天前
|
Java 关系型数据库 MySQL
高级对象装配:解析Spring创建复杂对象的秘诀
高级对象装配:解析Spring创建复杂对象的秘诀
20 0
高级对象装配:解析Spring创建复杂对象的秘诀

推荐镜像

更多