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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

本文主要内容是根据一个常见的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,如需转载请自行联系原作者


相关文章
|
1月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
|
2月前
|
XML Java 开发者
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
89 18
|
3月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
3月前
|
Android开发 开发者 Python
通过标签清理微信好友:Python自动化脚本解析
微信已成为日常生活中的重要社交工具,但随着使用时间增长,好友列表可能变得臃肿。本文介绍了一个基于 Python 的自动化脚本,利用 `uiautomator2` 库,通过模拟用户操作实现根据标签批量清理微信好友的功能。脚本包括环境准备、类定义、方法实现等部分,详细解析了如何通过标签筛选并删除好友,适合需要批量管理微信好友的用户。
141 7
|
4月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
287 2
|
4月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
97 2
|
4月前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
191 0
|
4月前
|
前端开发 Java Maven
深入解析:如何用 Spring Boot 实现分页和排序
深入解析:如何用 Spring Boot 实现分页和排序
201 2
|
4月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
86 4
|
4月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
127 8

热门文章

最新文章

推荐镜像

更多