Spring源码解析之SpringMVC源码解析(一)

8 篇文章 1 订阅
5 篇文章 0 订阅
一、源码阅读环境

用idea快速创建一个springboot 项目 ,在项目添加一个controller 方法,这里就不写创建过程了。主要需要以下

启动类

@SpringBootApplication
public class MVCApplication {
    public static void main (String args[]){
        SpringApplication.run(MVCApplication.class, args);
    }
}

Controller

@Controller
public class MVCDemoController {

    @RequestMapping(value = "/testMVC",method = RequestMethod.GET )
    public String testMVC(){
        return "test";
    }
}
二、源码分析
SpringMVC自动配置

我们知道在SpringBoot中使用SpringMVC的时候是不需要像传统Spring中配置web.xml和配置文件等等的。那么大家知道这是为什么吗

答案就在这个类WebMvcAutoConfiguration里面 以下代码为了方便阅读只保留了部分源码

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
      TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

   public static final String DEFAULT_PREFIX = "";

   public static final String DEFAULT_SUFFIX = "";

   private static final String[] SERVLET_LOCATIONS = { "/" };

   @Bean
   @ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
   @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = true)
   public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
      return new OrderedHiddenHttpMethodFilter();
   }

   @Bean
   @ConditionalOnMissingBean(FormContentFilter.class)
   @ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true)
   public OrderedFormContentFilter formContentFilter() {
      return new OrderedFormContentFilter();
   }

   // Defined as a nested config to ensure WebMvcConfigurer is not read when not
   // on the classpath
   @Configuration
   @Import(EnableWebMvcConfiguration.class)
   @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
   @Order(0)
   public static class WebMvcAutoConfigurationAdapter
         implements WebMvcConfigurer, ResourceLoaderAware {

      private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);

      private final ResourceProperties resourceProperties;

      private final WebMvcProperties mvcProperties;

      private final ListableBeanFactory beanFactory;

      private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;

      final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;

      private ResourceLoader resourceLoader;

      public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties,
            WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
            ObjectProvider<HttpMessageConverters> messageConvertersProvider,
            ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
         this.resourceProperties = resourceProperties;
         this.mvcProperties = mvcProperties;
         this.beanFactory = beanFactory;
         this.messageConvertersProvider = messageConvertersProvider;
         this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider
               .getIfAvailable();
      }

      @Bean
      @ConditionalOnMissingBean
      public InternalResourceViewResolver defaultViewResolver() {
         InternalResourceViewResolver resolver = new InternalResourceViewResolver();
         resolver.setPrefix(this.mvcProperties.getView().getPrefix());
         resolver.setSuffix(this.mvcProperties.getView().getSuffix());
         return resolver;
      }

      @Bean
      @ConditionalOnBean(View.class)
      @ConditionalOnMissingBean
      public BeanNameViewResolver beanNameViewResolver() {
         BeanNameViewResolver resolver = new BeanNameViewResolver();
         resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
         return resolver;
      }

      @Bean
      @ConditionalOnBean(ViewResolver.class)
      @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
      public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
         ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
         resolver.setContentNegotiationManager(
               beanFactory.getBean(ContentNegotiationManager.class));
         // ContentNegotiatingViewResolver uses all the other view resolvers to locate
         // a view so it should have a high precedence
         resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
         return resolver;
      }

      @Bean
      @ConditionalOnMissingBean
      @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
      public LocaleResolver localeResolver() {
         if (this.mvcProperties
               .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
            return new FixedLocaleResolver(this.mvcProperties.getLocale());
         }
         AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
         localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
         return localeResolver;
      }

      @Bean
      public WelcomePageHandlerMapping welcomePageHandlerMapping(
            ApplicationContext applicationContext) {
         return new WelcomePageHandlerMapping(
               new TemplateAvailabilityProviders(applicationContext),
               applicationContext, getWelcomePage(),
               this.mvcProperties.getStaticPathPattern());
      }

      @Bean
      @ConditionalOnMissingBean({ RequestContextListener.class,
            RequestContextFilter.class })
      @ConditionalOnMissingFilterBean(RequestContextFilter.class)
      public static RequestContextFilter requestContextFilter() {
         return new OrderedRequestContextFilter();
      }

      @Configuration
      @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
      public static class FaviconConfiguration implements ResourceLoaderAware {

         private final ResourceProperties resourceProperties;

         private ResourceLoader resourceLoader;

         public FaviconConfiguration(ResourceProperties resourceProperties) {
            this.resourceProperties = resourceProperties;
         }

         @Override
         public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
         }

         @Bean
         public SimpleUrlHandlerMapping faviconHandlerMapping() {
            SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
            mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
            mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
                  faviconRequestHandler()));
            return mapping;
         }

         @Bean
         public ResourceHttpRequestHandler faviconRequestHandler() {
            ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
            requestHandler.setLocations(resolveFaviconLocations());
            return requestHandler;
         }

      }

   }

   /**
    * Configuration equivalent to {@code @EnableWebMvc}.
    */
   @Configuration
   public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {

      private final WebMvcProperties mvcProperties;

      private final ListableBeanFactory beanFactory;

      private final WebMvcRegistrations mvcRegistrations;

      public EnableWebMvcConfiguration(
            ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
            ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
            ListableBeanFactory beanFactory) {
         this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
         this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
         this.beanFactory = beanFactory;
      }

      @Bean
      @Override
      public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
         RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
         adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
               || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
         return adapter;
      }
      @Bean
      @Primary
      @Override
      public RequestMappingHandlerMapping requestMappingHandlerMapping() {
         // Must be @Primary for MvcUriComponentsBuilder to work
         return super.requestMappingHandlerMapping();
      }

      @Bean
      @Override
      public FormattingConversionService mvcConversionService() {
         WebConversionService conversionService = new WebConversionService(
               this.mvcProperties.getDateFormat());
         addFormatters(conversionService);
         return conversionService;
      }

      @Bean
      @Override
      public Validator mvcValidator() {
         if (!ClassUtils.isPresent("javax.validation.Validator",
               getClass().getClassLoader())) {
            return super.mvcValidator();
         }
         return ValidatorAdapter.get(getApplicationContext(), getValidator());
      }

      @Bean
      @Override
      public ContentNegotiationManager mvcContentNegotiationManager() {
         ContentNegotiationManager manager = super.mvcContentNegotiationManager();
         List<ContentNegotiationStrategy> strategies = manager.getStrategies();
         ListIterator<ContentNegotiationStrategy> iterator = strategies.listIterator();
         while (iterator.hasNext()) {
            ContentNegotiationStrategy strategy = iterator.next();
            if (strategy instanceof PathExtensionContentNegotiationStrategy) {
               iterator.set(new OptionalPathExtensionContentNegotiationStrategy(
                     strategy));
            }
         }
         return manager;
      }

   }

   @Configuration
   @ConditionalOnEnabledResourceChain
   static class ResourceChainCustomizerConfiguration {

      @Bean
      public ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
         return new ResourceChainResourceHandlerRegistrationCustomizer();
      }
   }
  
	interface ResourceHandlerRegistrationCustomizer {

		void customize(ResourceHandlerRegistration registration);

	}

仔细看这个类,你就会发现这些自动注入的一些类都是之前需要我们在xml文件中配置的,现在SpringBoot帮我们做了这个操作。这就是大名鼎鼎的约定大于配置

初始化DispatcherServlet

DispatcherServlet是一个实现了Servlet接口的类,Servlet的初始化阶段会调用它的init()方法,而DispatcherServlet的方法是继承自父类HttpServletBean

public final void init() throws ServletException {

   // Set bean properties from init parameters.
  //处理init-param参数,但是SpringBoot中默认是没有的
   PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
   if (!pvs.isEmpty()) {
      try {
         BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
         ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
         bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
         initBeanWrapper(bw);
         bw.setPropertyValues(pvs, true);
      }
      catch (BeansException ex) {
         if (logger.isErrorEnabled()) {
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
         }
         throw ex;
      }
   }

   // Let subclasses do whatever initialization they like.
  // 初始化Servlet,往下看
   initServletBean();
}
/**
 * Overridden method of {@link HttpServletBean}, invoked after any bean properties
 * have been set. Creates this servlet's WebApplicationContext.
 */
@Override
protected final void initServletBean() throws ServletException {
   getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
   if (logger.isInfoEnabled()) {
      logger.info("Initializing Servlet '" + getServletName() + "'");
   }
   long startTime = System.currentTimeMillis();

   try {
      //初始化web容器 重点往下看
      this.webApplicationContext = initWebApplicationContext();
      //扩展点
      initFrameworkServlet();
   }
   catch (ServletException | RuntimeException ex) {
      logger.error("Context initialization failed", ex);
      throw ex;
   }

   if (logger.isDebugEnabled()) {
      String value = this.enableLoggingRequestDetails ?
            "shown which may lead to unsafe logging of potentially sensitive data" :
            "masked to prevent unsafe logging of potentially sensitive data";
      logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
            "': request parameters and headers will be " + value);
   }

   if (logger.isInfoEnabled()) {
      logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
   }
}
protected WebApplicationContext initWebApplicationContext() {
  //获取AnnotationConfigServletWebServerApplicationContext类型的web容器
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
			synchronized (this.onRefreshMonitor) {
        // 刷新应用上下文,这里是重点,接着往下看
				onRefresh(wac);
			}
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
      // 推送事件通知
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
		}

		return wac;
	}

继续往下看DispatcherServlet中onRefresh

/**
 * This implementation calls {@link #initStrategies}.
 */
@Override
protected void onRefresh(ApplicationContext context) {
   initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
  //初始化HandlerMappings
   initHandlerMappings(context);
  //初始化HandlerAdapters
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
   initFlashMapManager(context);
}

可以看到上方这一块代码都是一些常用组件的初始化,初始化的逻辑都比较简单,随意挑取2个看一下

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);
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
         // We keep HandlerMappings in sorted order.
         AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   else {
      try {
         HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
         this.handlerMappings = Collections.singletonList(hm);
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Ignore, we'll add a default HandlerMapping later.
      }
   }

   // 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);
      if (logger.isTraceEnabled()) {
         logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }
}

/**
 * Initialize the HandlerAdapters used by this class.
 * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
 * we default to SimpleControllerHandlerAdapter.
 */
private void initHandlerAdapters(ApplicationContext context) {
   this.handlerAdapters = null;

   if (this.detectAllHandlerAdapters) {
      // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
      Map<String, HandlerAdapter> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
      if (!matchingBeans.isEmpty()) {
         this.handlerAdapters = new ArrayList<>(matchingBeans.values());
         // We keep HandlerAdapters in sorted order.
         AnnotationAwareOrderComparator.sort(this.handlerAdapters);
      }
   }
   else {
      try {
         HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
         this.handlerAdapters = Collections.singletonList(ha);
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Ignore, we'll add a default HandlerAdapter later.
      }
   }

   // Ensure we have at least some HandlerAdapters, by registering
   // default HandlerAdapters if no other adapters are found.
   if (this.handlerAdapters == null) {
      this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
      if (logger.isTraceEnabled()) {
         logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }
}

至此,DispatcherServlet的初始化就完成了移步Spring源码解析之SpringMVC源码解析(二)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值