-
@Autowired可以标注的地方:
- field
- constructor
- setter
- any method
-
@Configuration类主要用于定义bean,@Configuration由于标注有@Component,因此其本身也是一个bean。
-
@Import可以通过以下3中方式工作(参考ConfigurationClassParser):
- 直接import一个@Configuration类,比如
@EnableScheduling
- 通过ImportSelector选择性地引入一个@Configuration类,比如
@EnableTransactionManagement
- 通过ImportBeanDefinitionRegistrar直接向ApplicationContext中添加bean,比如
@EnableAspectJAutoProxy
。
- 直接import一个@Configuration类,比如
-
XML方式的autowire,Customer依赖于Person,通过配置
autowire
属性:
<bean id="customer" class="com.mkyong.common.Customer" autowire="byName" />
<bean id="person" class="com.mkyong.common.Person" />
- 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配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
</beans>
以上两种配置将添加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<WebMvcConfigurer> 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种方式:
- @Configuration + @EnableWebMvc + 继承WebMvcConfigurerAdapter
- @Configuration + 继承WebMvcConfigurationSupport
- @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。
- RequestMappingHandlerAdapter,最常用的,用于调用标有
网友评论