注入自定义组件
当我们开发Web项目时,当想增加自定义组件的时候,可以通过如下几种方式来实现
- 实现WebMvcConfigurer接口
- 继承WebMvcConfigurerAdapter
- 继承WebMvcConfigurationSupport
继承WebMvcConfigurerAdapter的方式已经被废弃了,为什么被废弃呢?
我们在开发的过程中提供一个接口时,一般会同时提供一个Adapter类,Adapter类实现这个接口。我们就可以继承这个Adapter类,按照需求覆盖相应的方式,而不用实现接口,然后一大堆方法没有实现。java8之后,接口可以有默认方法,这样只实现接口也可以实现按需覆盖,Adapter类就用不到了,因此WebMvcConfigurerAdapter类就被废弃了
我们一般通过如下三种方式配置web应用(xml和JavaConfig的方式不分析了,基本不用)
- @EnableWebMvc+WebMvcConfigurer接口(spring mvc,spring boot)
- 继承WebMvcConfigurationSupport(spring mvc,spring boot)
- WebMvcConfigurer接口(spring boot应用)
@EnableWebMvc+WebMvcConfigurer接口
用@EnableWebMvc开发一个web项目
基于ServletContainerInitializer启动spring容器
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
@EnableWebMvc
@ComponentScan("com.javashitang")
public class AppConfig {
}
注册拦截器
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SystemInterceptor());
}
}
拦截器
public class SystemInterceptor extends HandlerInterceptorAdapter {
Logger log = LoggerFactory.getLogger(SystemInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("request-starttime", System.currentTimeMillis());
log.info("request enter:{}", request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
Long startTime = (Long) request.getAttribute("request-starttime");
if (startTime != null) {
long cost = System.currentTimeMillis() - startTime;
log.info("request cost:[" + request.getRequestURI() + ", "
+ request.getQueryString() + "] " + cost);
}
}
}
@RestController
public class UserController {
@RequestMapping("user")
public String index(@RequestParam("userId") String userId) {
return "hello " + userId;
}
}
@EnableWebMvc会导入DelegatingWebMvcConfiguration
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@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);
}
}
}
DelegatingWebMvcConfiguration会把用户增加的mvc配置自动注入到configurers中,configurers其实就是List<WebMvcConfigurer>的封装类
DelegatingWebMvcConfiguration的父类WebMvcConfigurationSupport会注入web项目所需要的相关组件
当注入这些组件的时候,会把WebMvcConfigurer接口中增加的各种配置,添加到这些组件中
继承WebMvcConfigurationSupport
可以看到@EnableWebMvc的主要作用就是引入WebMvcConfigurationSupport类,所以我们可以直接将这个类注入到容器,按需重写方法即可
SpringBoot项目+WebMvcConfigurer接口
当spring boot项目中,当配置如下依赖时,WebMvcAutoConfiguration配置类会被激活
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
而WebMvcAutoConfiguration会注入EnableWebMvcConfiguration类,而这个类的父类是DelegatingWebMvcConfiguration(会注入web项目需要的组件),所以WebMvcConfigurer接口的相关配置会注入到所需要的组件中(和@EnableWebMvc+WebMvcConfigurer的场景一个道理)
@Configuration(proxyBeanMethods = false)
@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
当我们觉得spring boot自动装配的web组件不符合我们的期望时,我们可以注入一个WebMvcConfigurationSupport类,或者加上EnableWebMvc注解(会导入WebMvcConfigurationSupport类),因为WebMvcAutoConfiguration生效的条件之一是
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),即容器中没有类型为WebMvcConfigurationSupport的Bean
总结
当我们使用spring mvc应用开发时,可以用如下方法自定义组件
- @EnableWebMvc+WebMvcConfigurer
- 继承WebMvcConfigurationSupport
而用spring boot开发web应用时,通过WebMvcConfigurer接口来自定义配置即可,需要的web组件会自动注入。如果觉得spring boot自动注入的组件不符合你的期望时,你可以通过如下方式自定义注入
- @EnableWebMvc+WebMvcConfigurer
- 继承WebMvcConfigurationSupport
参考博客
[1]https://zhuanlan.zhihu.com/p/82346557