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,如需转载请自行联系原作者


相关文章
|
8月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
1978 1
|
12月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
303 2
|
10月前
|
XML Java 开发者
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
295 18
|
9月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
410 1
|
11月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
12月前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
193 2
Spring高手之路25——深入解析事务管理的切面本质
|
11月前
|
Android开发 开发者 Python
通过标签清理微信好友:Python自动化脚本解析
微信已成为日常生活中的重要社交工具,但随着使用时间增长,好友列表可能变得臃肿。本文介绍了一个基于 Python 的自动化脚本,利用 `uiautomator2` 库,通过模拟用户操作实现根据标签批量清理微信好友的功能。脚本包括环境准备、类定义、方法实现等部分,详细解析了如何通过标签筛选并删除好友,适合需要批量管理微信好友的用户。
431 7
|
12月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
433 8
|
12月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
233 4

推荐镜像

更多
  • DNS