Spring Framework学习笔记

  • @Autowired可以标注的地方:

    1. field
    2. constructor
    3. setter
    4. any method
  • @Configuration类主要用于定义bean,@Configuration由于标注有@Component,因此其本身也是一个bean。

  • @Import可以通过以下3中方式工作(参考ConfigurationClassParser):

    1. 直接import一个@Configuration类,比如@EnableScheduling
    2. 通过ImportSelector选择性地引入一个@Configuration类,比如@EnableTransactionManagement
    3. 通过ImportBeanDefinitionRegistrar直接向ApplicationContext中添加bean,比如@EnableAspectJAutoProxy
  • XML方式的autowire,Customer依赖于Person,通过配置autowire属性:


    
    
  • WebApplicationInitializer原理,根据JDK自带的ServiceLoader机制,Spring在spring-web-xxx.jar包的META-INF/services下有个javax.servlet.ServletContainerInitializer文件,里面内容为org.springframework.web.SpringServletContainerInitializer,表示spring将通过SpringServletContainerInitializer初始化容器。该SpringServletContainerInitializer通过@HandlesTypes(WebApplicationInitializer.class)找到所有类型的WebApplicationInitializer实现实际的初始化工作,因此我们自己的程序字需要实现该WebApplicationInitializer接口即可,比如:
public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/example/*");
    }
}

当然,spring推荐的做法是继承AbstractAnnotationConfigDispatcherServletInitializer。对于Tomcat而言,情况还有点不一样,请参考这里。

  • SpringBootServletInitializer主要用于使得Spring Boot程序即能运行Jar中,又能运行与War中。

  • DispatcherServlet维护了一系列的默认bean,可以在org.springframework.web.servlet/DispatcherServlet.properties文件中找到。在此基础上,我们可以通过Java config或者Xml config的方式提供更多的默认配置,比如通过Java config:

@Configuration
@EnableWebMvc
public class WebConfig {
}

或者同等效用的Xml配置:




    


以上两种配置将添加RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver等bean,这些bean在Spring 4的默认DispatcherServlet中是没有的,不过在Spring 5中已经成为DispatcherServlet的默认bean了。除此之外,以上两种配置方式还加入了更多的默认bean,参考这里。

  • DispatchServlet会通过BeanFactoryUtils.beansOfTypeIncludingAncestors查找IoC容器中的各种Spring MVC的bean(比如HandlerMapping子类),也即在定义这些bean时,我们只需要通过@Bean声明即可,而不用担心Spring MVC找不到,比如在WebMvcConfigurationSupport中就定义了各种Bean。

  • DispatchServlet先查找IoC容器中已有的Bean(可以是用户自定义,也可以是@EnableWebMvc),如果有则不启用对应的DispatcherServlet.properties中的bean,如果没有,则为对应DispatcherServlet.properties中的默认配置创建bean加入到ApplicationContext中。

  • WebMvcConfigurationSupport 是Spring MVC的核心配置类,它定义了Spring MVC中的一些核心的骨架级别的Bean加入到IoC容器中,比如RequestMappingHandlerAdapter,HandlerMapping和ContentNegotiationManager等。WebMvcConfigurationSupport在配置的过程中会回调一些方法用于配置更精细的配置这些骨架bean,比如通过addInterceptors()向RequestMappingHandlerMapping中加入实际的Interceptor。

  • @EnableWebMvc会启用DelegatingWebMvcConfiguration,DelegatingWebMvcConfiguration继承自WebMvcConfigurationSupport,由于WebMvcConfigurationSupport中已经定义了Spring MVC的一些骨架级别的bean,因此有个@Configuration类直接打上@EnableWebMvc便可以是Spring MVC工作了,只是此时使用的都是Spring 默认的一些配置。

  • 为了支持定制化配置,WebMvcConfigurationSupport在创建骨架Bean之前提供了很多回调的方法,通过实现这些回调方法便可以达到定制Spring MVC的目的,DelegatingWebMvcConfiguration便提供了所有这些回调方法,但是并不做实际的配置,而是将配置交给了WebMvcConfigurer,WebMvcConfigurationSupport源码如下:


    @Autowired(required = false)
    public void setConfigurers(List configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }


    @Override
    protected void configurePathMatch(PathMatchConfigurer configurer) {
        this.configurers.configurePathMatch(configurer);
    }

请注意这里的@Autowired(required = false),表示它将在IoC容器中找到所有实现了WebMvcConfigurer接口的bean,然后子回调方法中实际调用WebMvcConfigurer来实现定制化工作,比如上例中的configurePathMatch。更多解释,参考这里。

- Spring MVC为我们提供了WebMvcConfigurer的实现`WebMvcConfigurerAdapter`,该类其实什么都不做,专门用来被继承的,也即如果override了WebMvcConfigurerAdapter中的方法,那么便达到了定制化的目的,如果没有override,那么便没有定制化,即保留WebMvcConfigurationSupport的默认配置。

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("home");
    }
}

从上例可以看到,我们使用了WebMvcConfigurerAdapter,由于该类实现了WebMvcConfigurer接口。

  • 通过WebMvcConfigurerAdapter定制化,其实并不是将bean直接加入到IoC容器中,而是通过registry新建(new)一个对象,再将这些对象添加到由WebMvcConfigurationSupport定义的IoC中骨架bean中。Registry对象由WebMvcConfigurationSupport创建,在调用回调函数的时候传给DelegatingWebMvcConfiguration,DelegatingWebMvcConfiguration进而在调用各个WebMvcConfigurerAdapter配置方法的时候将registry传给我们自定义的WebMvcConfigurerAdapter。比如,在WebMvcConfigurerAdapter中有:
@Override
    public void addFormatters(FormatterRegistry registry) {
    }

再举个例子,WebMvcConfigurerAdapter.configureViewResolvers(ViewResolverRegistry registry),ViewResolverRegistry会自动创建ViewResolver(new InternalResourceViewResolver()),然后创建ContentNegotiatingViewResolver,最后将这些ViewResolver添加到IoC容器的ContentNegotiationManager bean中。

  • 在Spring 5中,WebMvcConfigurerAdapter已经不再推荐使用了,而是推荐直接实现WebMvcConfigurer,因为WebMvcConfigurer中已经通过Java 8的default方法定义了配置方法。

  • 在定制Spring MVC配置时,有3种方式:

    1. @Configuration + @EnableWebMvc + 继承WebMvcConfigurerAdapter
    2. @Configuration + 继承WebMvcConfigurationSupport
    3. @Configuration + 继承DelegatingWebMvcConfiguration
  • 不要同时使用@EnableWebMvc与继承WebMvcConfigurationSupport,因为@EnableWebMvc本身便会引入WebMvcConfigurationSupport,因此导致重复配置了WebMvcConfigurationSupport,即bean的重复定义。

  • HandlerMapping与HandlerAdapter对应出现,即DispatchServlet先通过HandlerMapping找到对应可以处理Request的对象或者方法(Handler),然后通过调用HandlerAdapter进行调用。

  • RequestMappingHandlerMapping在初始化时会找到所有@RequestMapping的bean或方法(AbstractHandlerMethodMapping.afterPropertiesSet() -> initHandlerMethods() -> processCandidateBean()->detectHandlerMethods()->getMappingForMethod()->createRequestMappingInfo()->RequestMapping),然后添加到MappingRegistry中,然后当请求来时,直接从MappingRegistry中查找对应的Handler即可。

  • Spring 5中一共有4中HandlerAdapter:

    • RequestMappingHandlerAdapter,最常用的,用于调用标有@ReqeustMapping的方法。
    • HttpRequestHandlerAdapter,用于调用HttpRequestHandler,比较直接原始,并不返回ModelAndView,与Servlet差不多。
    • SimpleControllerHandlerAdapter,用于调用实现了Controller接口的bean。
    • SimpleServletHandlerAdapter,用于直接调用Servelt。

你可能感兴趣的:(Spring Framework学习笔记)