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的定制化方式相关推荐

  1. SpringBoot定制化开发

    文章目录 SpringBoot定制化开发 SpringBoot定制化开发 原理分析套路: 先找他对应的场景,然后我们就可以定位到对应的xxxxAutoConfiguration看他内部导入了哪些组件, ...

  2. SpringBoot 定制化原理

    一.定制化的常见方式 修改配置文件 xxxxxCustomizer 编写自定义的配置类 xxxConfiguration:+ @Bean替换.增加容器中默认组件:视图解析器 Web应用 编写一个配置类 ...

  3. [SpringBoot2]定制化原理_SpringBoot定制化组件的几种方式

    定制化原理 定制化的常见方式 ● 修改配置文件: ● xxxxxCustomizer: ● 编写自定义的配置类 xxxConfiguration:+ @Bean替换.增加容器中默认组件:视图解析器 ● ...

  4. SpringBoot使用assembly进行项目定制化打包

    SpringBoot使用assembly进行项目定制化打包 一.项目配置 1.添加插件 (1)编辑项目的 pom.xml 文件,加入 assembly 打包插件: <build><p ...

  5. 平安保险基于 SPI 机制的 RocketMQ 定制化应用

    作者:孙园园|平安人寿资深开发 为什么选用 RocketMQ 首先跟大家聊聊我们为什么会选用 RocketMQ,在做技术选型的过程中,应用场景应该是最先考虑清楚的,只有确定好了应用场景在做技术选型的过 ...

  6. 基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台

    作者 | 陈厚道  冯庆 来源 | 阿里巴巴云原生公众号 导读:本文将对 RocketMQ-Exporter 的设计实现做一个简单的介绍,读者可通过本文了解到 RocketMQ-Exporter 的实 ...

  7. SpringBoot--->>>web-->>定制化原理

    原理分析 在SpringBoot中,通过之前的web开发原理的探究,会发现,SpringBoot底层总能自己根据场景跑起来.流程是:导入场景 -> 对应的AutoConfiguration就会启 ...

  8. Spring Initializr私服搭建和定制化模板

    概述 Spring Initializr是Spring官方提供,用来创建SpringBoot项目的脚手架. Spring官方Spring Initializr:https://start.spring ...

  9. 面向隐私AI的TensorFlow深度定制化实践

    作者 | Rosetta团队 出品 | AI科技大本营(ID:rgznai100) 之前我们整体上介绍了基于深度学习框架开发隐私 AI 框架中的工程挑战和可行解决方案.在这一篇文章中,我们进一步结合 ...

最新文章

  1. 数据结构(04)— 线性顺序表实战
  2. 今日新鲜事python_今日新鲜事励志的句子致自己
  3. 英文Ubuntu安装中文包(locale)的方法
  4. C#3.0扩展方法[转]
  5. Python字符串前加u/r/b的作用
  6. 求封闭曲线面积vc代码_圆锥曲线综合5个类型,逐一突破
  7. estemplate 导入MySQL_[数据库]es~通过ElasticsearchTemplate进行聚合操作
  8. Python os.chdir() 方法
  9. eclipse svn不能忽略文件及文件夹,ignore设置无效 ?
  10. Java学习笔记1——类和对象
  11. DAY04 WINDOWS 文件的共享以及FTP服务器的搭建
  12. 对扩展openflow协议的一点思考
  13. SpringMVC显示上传文件
  14. Service Manager流程,派BC_REPLY,唤醒FregServer流程,返回BR_TRANSACTION_COMPLETE,睡眠等待proc-gt;wait...
  15. 决策树算法的应用python实现_决策树ID3和C4.5算法Python实现源码
  16. 黑马程序员 Python学习笔记之 判断(if)语句
  17. java 基础——函数(方法)
  18. yunu.php,1.1 本地安装云优
  19. VMware搭建linux集群
  20. java图片压缩、图片缩放

热门文章

  1. cad 打开硬件加速卡_绝地求生:如何设置NVIDIA卡使游戏更加流畅高效!及N卡设置原理...
  2. [python网络应用]用python帮你实现疫情自动填报(第一期,目前实现半自动,实现全自动会继续更新)(西北工业大学-翱翔门户疫情填报)
  3. reverse(反转函数)
  4. CSS的基本概念及文字属性、段落属性、背景属性、列表案例符号的样式
  5. filter: grayscale(1); | 网页变灰
  6. B. Numbers on the Chessboard -codeforces1027 -csdn博客
  7. [转] 判断中文,日文(日语),韩文(韩语)的正则表达式
  8. 中国篆刻艺术孙溟㠭作品
  9. 用JAVA写一个关于英寸和厘米之间的换算
  10. Python爬虫练习(一):酷狗飙升榜前200_排行(使用select,find(),find_all()方法)