Spring MVC源码解析:自定义组件的注入方式有多少种?

在这里插入图片描述

注入自定义组件

当我们开发Web项目时,当想增加自定义组件的时候,可以通过如下几种方式来实现

  1. 实现WebMvcConfigurer接口
  2. 继承WebMvcConfigurerAdapter
  3. 继承WebMvcConfigurationSupport

继承WebMvcConfigurerAdapter的方式已经被废弃了,为什么被废弃呢?

我们在开发的过程中提供一个接口时,一般会同时提供一个Adapter类,Adapter类实现这个接口。我们就可以继承这个Adapter类,按照需求覆盖相应的方式,而不用实现接口,然后一大堆方法没有实现。java8之后,接口可以有默认方法,这样只实现接口也可以实现按需覆盖,Adapter类就用不到了,因此WebMvcConfigurerAdapter类就被废弃了

我们一般通过如下三种方式配置web应用(xml和JavaConfig的方式不分析了,基本不用)

  1. @EnableWebMvc+WebMvcConfigurer接口(spring mvc,spring boot)
  2. 继承WebMvcConfigurationSupport(spring mvc,spring boot)
  3. 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应用开发时,可以用如下方法自定义组件

  1. @EnableWebMvc+WebMvcConfigurer
  2. 继承WebMvcConfigurationSupport

而用spring boot开发web应用时,通过WebMvcConfigurer接口来自定义配置即可,需要的web组件会自动注入。如果觉得spring boot自动注入的组件不符合你的期望时,你可以通过如下方式自定义注入

  1. @EnableWebMvc+WebMvcConfigurer
  2. 继承WebMvcConfigurationSupport

参考博客

[1]https://zhuanlan.zhihu.com/p/82346557

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java识堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值