对SpringBoot的自动配置原理@EnableAutoConfiguration(2.3.1版本)进行分析(小白理解的,欢迎大佬留言指出错误)

    技术2025-02-12  20

    前言: 什么是组件??? 百度百科给的答案: 组件(Component)是对数据和方法的简单封装。 C++ Builder中,一个组件就是一个从TComponent派生出来的特定对象。组件可以有自己的属性和方法。属性是组件数据的简单访问者。方法则是组件的一些简单而可见的功能。使用组件可以实现拖放式编程、快速的属性处理以及真正的面向对象的设计。 一些大佬给出的答案: 1.)组件是一种实现现预订功能的模块。 2.)组件是对数据和方法的简单封装,简而言之,组件就是一种特殊的对象。 3.)以上两者都有,组件是从本质上讲是和中特殊的对象,但从功能上讲又是一种实现预订功能的模块。 我的理解: 假如一个汽车是一个容器,那么他的发动机,中控系统,车身就是这个容器中的几个组件,拿发动机这个组件来说,它有自己的一些属性,也可以实现一些前进,倒车,挂挡的这些功能。然后汽车这个容器通过导入组件来实现自己的功能的过程就是程序实现的过程。而组件又是通过多个类来实现的,也就是你的发动机需要多个类实现。 组件是对数据和方法的简单封装,实现一些预订功能,组件对外暴露一个或多个接口,供外界调用,组件内部由多个类来协同实现指定的功能。 什么是ioc容器??? IOC全称:Inversion of Control,意思是控制反转。那么什么叫控制反转?提出这个概念目的是解决什么?   那我们首先来回答第一个问题(什么叫控制反转?):在我们平时用java写程序的时候,如果要用到别的类,那么我们会创建一个类的对象–new Object()。这样的话这个对象是由自己主动创建的,与使用该类的对象的耦合程度很高。   而控制反转就是spring的一个容器来创建对象,在一个类中需要另一个类的对象时,只需要从该容器中取出来就是了,该对象的控制权在该容器中,控制权发生了反转。   第二个问题(提出这个概念的目的是什么?):IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。   提到IOC就不得不提DI(依赖注入)。 DI全称:Dependency Injection,意思是依赖注入。那么这个概念怎么理解?   自然是从字面拆分来理解:依赖谁?注入谁?谁依赖?谁注入?目的是什么?   第一个问题(依赖谁?):应用程序依赖于IOC容器   第二个问题(注入谁?):IOC容器将应用程序需要的对象和资源注入到应用程序里面。   第三个问题(谁依赖?):应用程序依赖。(这里也可以看到控制反转的概念,一般而言,我们平时写代码需要资源时,就是从该类中主动去获取,使用IOC后,从IOC中获取)   第四个问题(谁注入?):IOC容器向应用程序中注入资源。   第五个问题(目的是什么?):依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。 那么IOC和DI的关系呢?   个人理解一句话:IOC容器中的对象需要依赖注入来完成具体的配置。两者其实是一种概念的不同方面所看待。

    接下来就通过对SpringBoot源码的一个分析自动配置的原理 java 注解,从名字上看是注释,解释。 先通过一个小注解分析一下>>>>> 如图中@RestController注解点进去看看,标注了@Controller @ResponseBody,也就是告诉我们@RestController它实现了@Controller@ResponseBody这两个功能。所以说不用向以前一样,对一个类添加两个注解了。 步入正题开始分析SpringBoot的自动配置原理。 我们点击@SpringBootApplication注解,看到他就被表注为 @EnableAutoConfiguration,再接着点进入到如下页面。 第一步: 利用EnableAutoConfigurationImportSelector给容器中导入一些组件。 第二步 此时@import就是导入组件AutoConfigurationImportSelector 进入这个组件内部看看,他都给我们提供了什么。 看这两个方法。 getCandidateConfigurations方法中, SpringFactoriesLoader.loadFactoryNames(),扫描如上图jar包类路径下 META-INF/spring.factories,把扫描到的这些组件加载到容器里,EnableAutoConfiguration.class(类名)下边所有的值。 此时已经将所有待配置的组件加载到了容器里。 第三步: 此时才开始真正的将每一个组件都进行配置。 每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中了;用他们来做自动配置; 每一个自动配置类进行自动配置功能。 第四步: 以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理.我们找进去,看到这个配置类里有什么我们就能配置什么 HttpEncodingAutoConfiguration的注解,分析一下

    //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件 @Configuration( proxyBeanMethods = false ) //启动指定类的ConfigurationProperties功能; //将配置文件中对应的值和ServerProperties绑定起来; //并把ServerProperties加入到ioc容器中。 @EnableConfigurationProperties({ServerProperties.class}) //Spring底层@Conditional注解 //根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效; //判断当前应用是否是web应用,如果是,当前配置类生效 @ConditionalOnWebApplication( type = Type.SERVLET ) //判断当前项目有没有这个类 @ConditionalOnClass({CharacterEncodingFilter.class}) /** * 判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的 * 即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的; */ @ConditionalOnProperty( prefix = "server.servlet.encoding", value = {"enabled"}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration { private final Encoding properties; //只有一个有参构造器的情况下,参数的值就会从容器中拿 public HttpEncodingAutoConfiguration(ServerProperties properties) { this.properties = properties.getServlet().getEncoding(); } @Bean @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE)); return filter; } @Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取 public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() { return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties); } static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered { private final Encoding properties; LocaleCharsetMappingsCustomizer(Encoding properties) { this.properties = properties; } public void customize(ConfigurableServletWebServerFactory factory) { if (this.properties.getMapping() != null) { factory.setLocaleCharsetMappings(this.properties.getMapping()); } } public int getOrder() { return 0; } } }

    如图:我们做一个例子(之前版本在spring.http.encoding.*里) 现在写在这里,我们能看到都能对什么属性操作。 SpringBoot启动会加载大量的自动配置类 我们看我们需要的功能有没有SpringBoot默认写好的自动配置类 再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了) 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值

    xxxxAutoConfigurartion:自动配置类; xxxxProperties:封装配置文件中相关属性;

    Processed: 0.009, SQL: 9