<mvc:annotation-driven> 和 @EnableWebMvc 解析

<mvc:annotation-driven> 和 @EnableWebMvc 解析

这两个起到的作用是类似的(避免重复注册,二选一即可), 都是注册了大部分spring mvc开发所需的bean(HandlerMapping,HandlerAdapter等等),

还有根据包存在添加messageConverter(例如jackson,以支持@ResponseBody).

源码分析基于Spring 5.2.5, 为了简洁会省去部分源码.

前言

即使没有<mvc:annotation-driven>, DispatcherServlet一样会生成默认的映射器,适配器,视图解析器等.

public class DispatcherServlet extends FrameworkServlet {
    private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
    
	protected void initStrategies(ApplicationContext context) {
		// ...
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}    
    private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			}
		}
		// ...
		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		}
	}
}

从上述代码看出, DispatcherServlet会先从beanFactory中寻找所需要的bean, 若没找到, 则会加载默认配置(从jar包中的DispatcherServlet.properties读取)

由tomcat容器加载Servlet#init,最终执行该段代码

<mvc:annotation-driven>

MvcNamespaceHandler得出该标签由AnnotationDrivenBeanDefinitionParser处理, 为了简化手动配置, 其中注册了很多bean(具体看源码).

该类还在静态代码块中判断jar包存在与否, 从而注册对应的HttpMessageConverter, (比如,处理@RequestBody/ResponseBody的参数/返回值的消息转换器).

// 注意不要找错包
package org.springframework.web.servlet.config;

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    static {
        // ...
		ClassLoader classLoader = AnnotationDrivenBeanDefinitionParser.class.getClassLoader();
		jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
		gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
	}
    
    public BeanDefinition parse(Element element, ParserContext context) {
        // ... 在这里注册bean
    }
}

@EnableWebMvc

该注解引入了@Import(DelegatingWebMvcConfiguration.class), 起到的作用与上面类似.

//----------------------------- 子类
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    
	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

	@Autowired(required = false)
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addWebMvcConfigurers(configurers);
		}
	}
}
//----------------------------- 父类
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    @Bean
	public HandlerMapping defaultServletHandlerMapping() {
		DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
		configureDefaultServletHandling(configurer);
		return configurer.buildHandlerMapping();
	}    
  
    //还有其他@Bean...
}

先看子类 DelegatingWebMvcConfiguration, 从第7行看出, 子类主要做的是找到在spring注册的所有WebMvcConfigurer和重写方法(以便后续直接遍历调用).

再看父类WebMvcConfigurationSupport, 该类同<mvc:annotation-driven>, 也是注册了很多bean(通过@Bean方式), 也存在类似的静态代码块判断jar包.

与<mvc:annotation-driven>不同的是, 在@Bean方法体内, 会调用WebMvcConfigurer(用户自定义)对应的方法, 以便于自定义配置这些bean.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值