springboot的定制化方式
springboot的定制化原理
个人理解,springboot设计目标就是希望利用提供各种默认约定配置,代替配置,从而达到简略配置的目的。
实现原理就是利用类似SPI机制,通过AutoConfigurationImportSelector,从而读取所有的classpath里的MATA_INF/META-INF/spring.factories里的自动配置类,配合对应Conditional注解从而有条件的注册对应的自动配置类,而@EnableConfigurationProperties绑定配置到对应的配置类,从而提供默认配置和个性化配置。达到修改配置后,对应的服务功能也修改。
所以我们个性化使用springboot,通常可以直接引入对应的starter,修改配置,自然就能达到开箱即用的效果。
定制化springboot
现在比较常见的个性化自己配置的有4个方式。
修改配置
从springboot的整体流程可以看出,springboot的默认配置基本都是通过绑定对应的配置类,从而注入对应的bean到容器中。
自然修改配置就能达到个性化自己的配置。
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
容器中注入自己的bean
从自动注入原理也能知道,自动配置是配合Conditional注解注解有条件的注入,因此如果我们破坏这个条件,自然也能打破自动注入,注入自己的bean。
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix(this.mvcProperties.getView().getPrefix());resolver.setSuffix(this.mvcProperties.getView().getSuffix());return resolver;
}
比如这个,springboot的自动注入InternalResourceViewResolver类的 前提是容器中没有对应的类,
如果我们申明一个对应类的@Bean,自然容器中存在的就我们声明的bean。
通过实现XXXCustomizer达到修改配置的效果
官方通过类似定义XXXCustomizer格式的类,预留了一个修改点给用户,从而达到个性化配置的效果。
我们追踪一下ServletWebServerFactoryCustomizer。
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {return new ServletWebServerFactoryCustomizer(serverProperties);
}
平平无奇的注入bean。那么哪里使用了呢。
下面有个实现了ImportBeanDefinitionRegistrar的BeanPostProcessorsRegistrar
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {...public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (this.beanFactory != null) {this.registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class);this.registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class);}}
里面的registerBeanDefinitions,我们可以看到,注册了两个类,WebServerFactoryCustomizerBeanPostProcessor,ErrorPageRegistrarBeanPostProcessor。
从命名就可以看出,WebServerFactoryCustomizerBeanPostProcessor就是WebServerFactoryCustomizer的后置处理器,
点进去看看。
public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {...private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {customizer.customize(webServerFactory);});}
可以看出,里面循环调用了customizer的customize,那么我们就可以在里面修改webServerFactory,
因为是BeanPostProcessor从而可以在注册bean到容器前修改配置。
通过XXXConfigurer修改配置
追踪WebMvcConfigurer
我们拿WebMvcConfigurer举例,说明一下为什么我们实现WebMvcConfigurer接口就能达到自定义配置的效果。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {/** 开启跨域 */@Overridepublic void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路由registry.addMapping("/**")// 设置允许跨域请求的域名.allowedOriginPatterns("*").allowedHeaders("*")// 是否允许证书(cookies).allowCredentials(true)// 设置允许的方法.allowedMethods("*")// 跨域允许时间.maxAge(30 * 24 * 3600L);}
}
我们常通过这样类型的配置类配置.
怎么就能修改配置呢。
我们知道springboot是通过读取所有的classpath里的MATA_INF/META-INF/spring.factories里的自动配置,从而注入XXXAutoConfiguration的类,而
对应类里会有对应的注入bean。
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration
我们可以看出,WebMvcAutoConfiguration的注入条件是容器中没有WebMvcConfigurationSupport类的bean。
我们看下下面的实现
@Configuration
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware
我们可以看出,他导入了WebMvcAutoConfiguration.EnableWebMvcConfiguration,绑定了WebMvcProperties.class, ResourceProperties.class.
@Configurationpublic static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
@Configurationpublic 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); } }
这样我们就很清楚了,我们WebMvcAutoConfigurationAdapter级联注册EnableWebMvcConfiguration,而EnableWebMvcConfiguration继承WebMvcConfigurationSupport,而里面setConfigurers注入了所有的实现了WebMvcConfigurer的实现类。
我们来追踪下怎么注入的HttpMessageConverter。
@Configurationpublic class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware
我们看到DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport,而WebMvcConfigurationSupport里面有几个方法却有@bean注解,说明一定有那个注解类注册了这个类,我们看下WebMvcConfigurationSupport实现类。
@Configuration@ComponentScan({"org.activiti.rest.exception", "org.activiti.rest.service.api"})@ConditionalOnClass(WebMvcConfigurationSupport.class)@EnableAsyncpublic class DispatcherServletConfiguration extends WebMvcConfigurationSupport
可以看到DispatcherServletConfiguration继承了这个WebMvcConfigurationSupport
protected final List<HttpMessageConverter<?>> getMessageConverters() { if (this.messageConverters == null) { this.messageConverters = new ArrayList(); this.configureMessageConverters(this.messageConverters); if (this.messageConverters.isEmpty()) { this.addDefaultHttpMessageConverters(this.messageConverters); } this.extendMessageConverters(this.messageConverters); } return this.messageConverters; }
可以看到,实现方法是getMessageConverters,里面调用了this.configureMessageConverters(this.messageConverters);调用子类添加HttpMessageConverter。this.extendMessageConverters(this.messageConverters);调用子类的extendMessageConverters的方法。
自然就对应我们WebMvcConfigurer的configureMessageConverters重写HttpMessageConverter,而extendMessageConverters继承。
看下是谁调用的
@Beanpublic RequestMappingHandlerAdapter requestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter(); adapter.setContentNegotiationManager(this.mvcContentNegotiationManager()); adapter.setMessageConverters(this.getMessageConverters()); adapter.setWebBindingInitializer(this.getConfigurableWebBindingInitializer()); adapter.setCustomArgumentResolvers(this.getArgumentResolvers()); adapter.setCustomReturnValueHandlers(this.getReturnValueHandlers()); if (jackson2Present) { adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice())); adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice())); } AsyncSupportConfigurer configurer = new AsyncSupportConfigurer(); this.configureAsyncSupport(configurer); if (configurer.getTaskExecutor() != null) { adapter.setTaskExecutor(configurer.getTaskExecutor()); } if (configurer.getTimeout() != null) { adapter.setAsyncRequestTimeout(configurer.getTimeout()); } adapter.setCallableInterceptors(configurer.getCallableInterceptors()); adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors()); return adapter;}
这里注册了RequestMappingHandlerAdapter,而里面注入了HttpMessageConverter。 adapter.setMessageConverters(this.getMessageConverters());
那么自此,逻辑就清晰了,为什么我们继承WebMvcConfigurer就能实现添加HttpMessageConverter。
为什么我们
@Configurationpublic class WebMvcConfig extends WebMvcConfigurationSupport
继承WebMvcConfigurationSupport,会覆盖 @EnableAutoConfiguration 关于 WebMvcAutoConfiguration。
因为自动注入WebMvcAutoConfiguration的注入条件是容器中没有WebMvcConfigurationSupport类的bean。而我们如果继承WebMvcConfigurationSupport就得自己注入对应的所有类。
而@EnableWebMvc
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})@Documented@Import({DelegatingWebMvcConfiguration.class})public @interface EnableWebMvc {}
也级联配置了DelegatingWebMvcConfiguration,这个也继承WebMvcConfigurationSupport,所以@EnableWebMvc就跟我们容器内实现继承WebMvcConfigurationSupport一样的效果。
springboot的定制化方式相关推荐
- SpringBoot定制化开发
文章目录 SpringBoot定制化开发 SpringBoot定制化开发 原理分析套路: 先找他对应的场景,然后我们就可以定位到对应的xxxxAutoConfiguration看他内部导入了哪些组件, ...
- SpringBoot 定制化原理
一.定制化的常见方式 修改配置文件 xxxxxCustomizer 编写自定义的配置类 xxxConfiguration:+ @Bean替换.增加容器中默认组件:视图解析器 Web应用 编写一个配置类 ...
- [SpringBoot2]定制化原理_SpringBoot定制化组件的几种方式
定制化原理 定制化的常见方式 ● 修改配置文件: ● xxxxxCustomizer: ● 编写自定义的配置类 xxxConfiguration:+ @Bean替换.增加容器中默认组件:视图解析器 ● ...
- SpringBoot使用assembly进行项目定制化打包
SpringBoot使用assembly进行项目定制化打包 一.项目配置 1.添加插件 (1)编辑项目的 pom.xml 文件,加入 assembly 打包插件: <build><p ...
- 平安保险基于 SPI 机制的 RocketMQ 定制化应用
作者:孙园园|平安人寿资深开发 为什么选用 RocketMQ 首先跟大家聊聊我们为什么会选用 RocketMQ,在做技术选型的过程中,应用场景应该是最先考虑清楚的,只有确定好了应用场景在做技术选型的过 ...
- 基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台
作者 | 陈厚道 冯庆 来源 | 阿里巴巴云原生公众号 导读:本文将对 RocketMQ-Exporter 的设计实现做一个简单的介绍,读者可通过本文了解到 RocketMQ-Exporter 的实 ...
- SpringBoot--->>>web-->>定制化原理
原理分析 在SpringBoot中,通过之前的web开发原理的探究,会发现,SpringBoot底层总能自己根据场景跑起来.流程是:导入场景 -> 对应的AutoConfiguration就会启 ...
- Spring Initializr私服搭建和定制化模板
概述 Spring Initializr是Spring官方提供,用来创建SpringBoot项目的脚手架. Spring官方Spring Initializr:https://start.spring ...
- 面向隐私AI的TensorFlow深度定制化实践
作者 | Rosetta团队 出品 | AI科技大本营(ID:rgznai100) 之前我们整体上介绍了基于深度学习框架开发隐私 AI 框架中的工程挑战和可行解决方案.在这一篇文章中,我们进一步结合 ...
最新文章
- 数据结构(04)— 线性顺序表实战
- 今日新鲜事python_今日新鲜事励志的句子致自己
- 英文Ubuntu安装中文包(locale)的方法
- C#3.0扩展方法[转]
- Python字符串前加u/r/b的作用
- 求封闭曲线面积vc代码_圆锥曲线综合5个类型,逐一突破
- estemplate 导入MySQL_[数据库]es~通过ElasticsearchTemplate进行聚合操作
- Python os.chdir() 方法
- eclipse svn不能忽略文件及文件夹,ignore设置无效 ?
- Java学习笔记1——类和对象
- DAY04 WINDOWS 文件的共享以及FTP服务器的搭建
- 对扩展openflow协议的一点思考
- SpringMVC显示上传文件
- Service Manager流程,派BC_REPLY,唤醒FregServer流程,返回BR_TRANSACTION_COMPLETE,睡眠等待proc-gt;wait...
- 决策树算法的应用python实现_决策树ID3和C4.5算法Python实现源码
- 黑马程序员 Python学习笔记之 判断(if)语句
- java 基础——函数(方法)
- yunu.php,1.1 本地安装云优
- VMware搭建linux集群
- java图片压缩、图片缩放
热门文章
- cad 打开硬件加速卡_绝地求生:如何设置NVIDIA卡使游戏更加流畅高效!及N卡设置原理...
- [python网络应用]用python帮你实现疫情自动填报(第一期,目前实现半自动,实现全自动会继续更新)(西北工业大学-翱翔门户疫情填报)
- reverse(反转函数)
- CSS的基本概念及文字属性、段落属性、背景属性、列表案例符号的样式
- filter: grayscale(1); | 网页变灰
- B. Numbers on the Chessboard -codeforces1027 -csdn博客
- [转] 判断中文,日文(日语),韩文(韩语)的正则表达式
- 中国篆刻艺术孙溟㠭作品
- 用JAVA写一个关于英寸和厘米之间的换算
- Python爬虫练习(一):酷狗飙升榜前200_排行(使用select,find(),find_all()方法)