Springboot 个性化配置SpringMVC
Springboot 个性化配置SpringMVC
Springboot很重要的一个功能就是整合了各种spring相关框架以及其他在开发场景中通用的包和需要配置的类。达到的效果就是以前需要写非常多的配置类以及XML文件,现在只需要在porm中配置:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.7.RELEASE</version> </parent> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> </dependencies>
其中spring-boot-starter-xxx就是spring官方 给出的各种应用场景的打包,当然我们可以自己打包一些场景。但是什么都打包好了,如果我要自己配置,那怎么办呢?
1 SpringMVC自动配置
要想自己配置一些个性化的设置,那么要了解springboot是如何进行自动化配置以及配置了哪些东西的。
加载入口
springboot的启动路口相对于tomocat来说要明显一点,至少这里有了一个主类,最关键的就是这个@SpringBootApplication
注解。
@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class,args);}}
@SpringBootApplication
注解里面主要有三个注解:
@SpringBootConfiguration 表明这是一个Configuration
@ComponentScan 用于标注扫哪些包
@EnableAutoConfiguration 开启自动配置
其中完成的两个动作
- @AutoConfigurationPackage 里面是 @Import({Registrar.class})
- @Import({AutoConfigurationImportSelector.class}) 关键的就是把AutoConfigurationImportSelector.class注册到容器当中
在整个SpringBoot当中会见到非常多的xxxAutoConfiguration类,这里面储备的就是各种相关的配置。而对于SpringMVC来说,主要的配置就在WebMvcAutoConfiguration中。
看一下WebMvcAutoConfiguration的注解
@Configuration(proxyBeanMethods = false
) // 不会创建代理对象
@ConditionalOnWebApplication(type = Type.SERVLET
) // web应用才初始化
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) //这些类加载了才初始化
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) //不存在这个类才初始化
@AutoConfigureOrder(-2147483638) //加载顺序
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}) //这些类加载后再初始化
public class WebMvcAutoConfiguration {}
而这个WebMvcAutoConfiguration中还有许多内部类,这些内部类也被@Configuration注解修饰,也同样会被加载到容器中,因此就会被加载。
2 个性化配置某个类
在WebMvcAutoConfiguration的内部类WebMvcAutoConfigurationAdapter中有这样一段代码
@Configuration(proxyBeanMethods = false)@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})@Order(0)public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {public void configurePathMatch(PathMatchConfigurer configurer) {configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());configurer.setUseRegisteredSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());// 配置路径解析this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {String servletUrlMapping = dispatcherPath.getServletUrlMapping();if (servletUrlMapping.equals("/") && this.singleDispatcherServlet()) {// 配置urlPathHelperUrlPathHelper urlPathHelper = new UrlPathHelper(); // 打断点urlPathHelper.setAlwaysUseFullPath(true);configurer.setUrlPathHelper(urlPathHelper);}});}}
如果我们需要自定义这个UrlPathHelper,那么我们有以下三种方式:
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own
@Configuration
class of typeWebMvcConfigurer
but without@EnableWebMvc
.不用@EnableWebMvc注解。使用
@Configuration
+WebMvcConfigurer
自定义规则新建一个类继承**
WebMvcConfigurer
**并重写需要的方法,然后使用@Configuration修饰
If you want to provide custom instances of
RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
, orExceptionHandlerExceptionResolver
, and still keep the Spring Boot MVC customizations, you can declare a bean of typeWebMvcRegistrations
and use it to provide custom instances of those components.声明
WebMvcRegistrations
改变默认底层组件使用自定义的**
WebMvcRegistrations
类来替换springboot帮我们定义的WebMvcRegistrations
**
If you want to take complete control of Spring MVC, you can add your own
@Configuration
annotated with@EnableWebMvc
, or alternatively add your own@Configuration
-annotatedDelegatingWebMvcConfiguration
as described in the Javadoc of@EnableWebMvc
.使用
@EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC
这里采用第一种方式。因此我们写了以下代码
@Configuration
public class MvcConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {//重写代码UrlPathHelper urlPathHelper = new UrlPathHelper();urlPathHelper.setAlwaysUseFullPath(false); // 打断点configurer.setUrlPathHelper(urlPathHelper);}
}
以及
/**
*这里我没有什么好方式,就直接写了controller,通过访问本机ip:端口/test来调用这个方法,打印注册的WebMvcConfigurer.class
*这里实现了ApplicationContextAware接口用于拿到上下文对象
*/
@RestController
public class HelloController implements ApplicationContextAware {@AutowiredApplicationContext ac;@RequestMapping("/test")public void test01(){String[] beanNamesForType = ac.getBeanNamesForType(WebMvcConfigurer.class);for (String s : beanNamesForType) {System.out.println(s);}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {ac = applicationContext;}}
上文两个地方打了断点,分别是系统实现的WebMvcAutoConfigurationAdapter
以及我们自己实现的MvcConfig
,我们看看系统注册了哪些继承了WebMvcConfigurer
的类
第一次断点:
可以看到先注册了系统配置的类,是从WebMvcConfigurationSupport调用的。这个设置其实是在一个普通方法内,而上层的逻辑是会调用这个方法的,所以才走到了这里。
我们放行,进入到第二个方法:
这里可以看到都出现了这个WebMvcConfigurerComposite这个configurePathMatch方法。
这个方法其实是
// WebMvcConfigurerComposite
public void configurePathMatch(PathMatchConfigurer configurer) {Iterator var2 = this.delegates.iterator();while(var2.hasNext()) {WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();delegate.configurePathMatch(configurer);}}
所以就是一前一后的进行调用而已。
Springboot如何保证我们自定义的WebMvcConfigurer
实现类在系统自定义的之后调用呢?
因为这个delegate是有序的。了解Spring初始化的朋友会知道,在初始化类的时候因为依赖输入,每个类初始化的时间是不一定的。所以最后注入到List中的所有WebMvcConfigurer
的实现类顺序也是不定的。但是我们这里可以按照顺序来注册,大家会想到WebMvcAutoConfigurationAdapter
有一个注解@Order(0)
意思就是需要排序,排在最前面,代码如下:
// DefaultListableBeanFactory
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {if (result instanceof List) {if (((List<?>) result).size() > 1) {//如果获取到的结果是一个List并且长度大于一,那就找是否存在合适的比较器,存在就比较Comparator<Object> comparator = adaptDependencyComparator(matchingBeans); //OrderComparatorif (comparator != null) {((List<?>) result).sort(comparator);}}}
}
原本result是自定义的排在第一,系统定义的排在第二,比较后就变化了。
事实上是先初始化了自定义的类。但是在初始化DelegatingWebMvcConfiguration时对其中的configurers进行依赖注入时获取对象,在获取对象的中途,又初始化了WebMvcAutoConfigurationAdapter
,就按照系统配置先,而用户自定义后,这样实现用户自定义在后面调用,从而覆盖系统的配置。反言之,如果你给自定义的加一个@Order(0)
注解,这样设置就失败了。
@Configuration(proxyBeanMethods = false
)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();public DelegatingWebMvcConfiguration() {}@Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);}}
}
这里还有一个细节,如何判断有@Order
注解和没有@Order
注解的类谁先谁后,根据前面我们认为没有注解的话,就排最后,这里我们可以看OrderComparator$doComparator
代码。因为两个都没有实现PriorityOrdered接口,所以前面都是false,最后使用getOrder方法取出这个取出这个值才行。
系统的类标注了@Order(0)
,自定义的没有标注,就是返回最大值LOWEST_PRECEDENCE
=2147483648
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderComparator.OrderSourceProvider sourceProvider) {//o1 是PriorityOrdered 则为trueboolean p1 = o1 instanceof PriorityOrdered;//o2 是PriorityOrdered 则为trueboolean p2 = o2 instanceof PriorityOrdered;if (p1 && !p2) {// p1是而p2不是,则返回小于return -1;} else if (p2 && !p1) {// 反之返回大于,也就是说没有注解@Order的是比较大的return 1;} else {// 都实现了,就看谁注解的小int i1 = this.getOrder(o1, sourceProvider);int i2 = this.getOrder(o2, sourceProvider);return Integer.compare(i1, i2);}}
总结
这里大家大概对Springboot的自动装配有点点了解了。一般前面的装配流程大部分博文将的比较多,Springboot根据应用场景将大部分的配置都配置好了,所以你基本就添加一个Springboot的依赖就可以开始开发业务的流程。
但是就我个人来说,我觉得boot对新手(不了解Spring系列底层源码)来说不是特别友好,虽然你可以什么都不想就直接用,那非常方便。但是碰到需要自定义的一些场景就会容易出问题,而且容易知其然而不知其所以然。例如我对SpringMVC就总觉得很抽象,虽然前端这样写,后端这样写就行,但是因为tomcat之类的服务器帮我们处理了太多,导致总觉得有点不太顺畅,但是也不影响开发。但是在时间充分的情况下还是多了解了解远离比较好,毕竟不要被卡脖子嘛。
后面的流程因为在学习的时候没找到答案,所以我是一步步debug出来的,虽然有些博主大概说过,但是从源码的角度看更加的直接,希望能对大家了解这个装配流程和自定义有所帮助。
Springboot 个性化配置SpringMVC相关推荐
- SpringBoot之配置嵌入式Servlet容器
1.概述 文章目录 1.概述 2.如何修改SpringBoot的默认配置 3.定制和修改Servlet容器的相关配置 4.注册Servlet三大组件 5.替换为其他嵌入式Servlet容器 6.嵌入式 ...
- 这样讲 SpringBoot 自动配置原理,你应该能明白了吧
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:你在我家门口 juejin.im/post/5ce5effb ...
- SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置入门介绍
springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发. 比如不使用springboot而使用SpringMVC作为web框架进行开发 ...
- springboot起步配置和自动配置原理
一.起步配置 1.起步配置Ctrl+左键进入 2.springboot自动识别resources目录下以application开头的配置文件 3.spring-boot-starter-parent又 ...
- SpringBoot | 自动配置原理
微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 这个月过去两天了,这篇文章才跟大家见面,最近比较累,大家见谅下.下班后闲着无聊看了下 SpringBoot 中的自动配置,把我 ...
- 注解不自动导包_玩转SpringBoot2.X:SpringBoot自动配置原理大揭秘
我们在使用SpringBoot的时候,是不是觉得特方便,根本不需要我们去配置什么端口号,应用名称,又比如我们再整合redis的时候,其实也不需要我们去指定端口号,IP,都会有默认的.是不是特方便.那么 ...
- SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理
springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发. 比如不使用springboot而使用SpringMVC作为web框架进行开发 ...
- 第9步 spring 配置 springmvc配置
spring配置 有5个网址 springboot 再讲一遍 spring的学习最好的方法是运行 官方demo 学习它里面的配置 . 我们不可能一下子理解spring里面的源码 spri ...
- SpringBoot 自动配置原理
创建项目 通过Spring Initialize创建SpringBoot项目 而接下来要说的是关于配置文件的事情.关乎配置文件可以参考官方文档. 对于配置文件来说到底在配置文件里面可以进行配置那些内容 ...
最新文章
- 字符串处理函数C语言实现(一)
- codevs 4560 NOIP2015 D2T2 子串
- 五天带你学完《计算机网络》·第三天·传输层
- MySQL性能优化最佳实践 - 02 MySQL数据库性能衡量
- 十万个为什么儿童版_《虹猫蓝兔十万个为什么》上架爱奇艺奇巴布绘本馆
- java请求并行方案_让 Yar Java Client 支持执行并行请求,ExecutorService 的使用
- 命令行cmd跳转到其他地址
- VIIRS SDR数据预处理(一)
- C++:使用类方法根据四点计算四面体体积
- EPUB、CAJ 、PDF 格式的区别,windows上有什么好用的epub阅读器
- Font Awesome 是一套绝佳的图标字体库和CSS框架
- 【备读学术论文总览】研究方向论文清单
- Mysql中的循环语句
- 7款最流行的在线项目管理工具
- 宝塔面板可以建立静态网站吗?如何部署一个静态页面?
- Linux函数exec
- 筑基期第一式:SpringMVC源码解析
- 华师在线计算机考试登陆不上,华师在线首页登录网址
- 你还在问我Bean的生命周期?带你看看一个Spring Bean从诞生到逝去的九次人生转折!
- 手把手带你写代码,完美实现Java分页功能
热门文章
- NAS数据迁移到对象存储太麻烦?90分钟纳管1000万文件了解一下
- 硬盘柱面损坏怎么办_硬盘有坏道就不能用了吗?别再吃哑巴亏了,今天跟人人再说一次...
- HJZS-E202电源监视继电器(断电延时)
- SQL 创建数据库,创建表
- 北京交通大学计算机科学与技术研究生分数线,2019北京交通大学研究生分数线汇总(含2016-2019历年复试)...
- vue实现Tab切换功能
- 用c++写一百以内的质数
- 使用MobLink点击链接打开app
- 全球最大的黑客门户网站--黑客基地
- Selenium之悬浮菜单定位