详解SpringBoot简化配置分析总结

在SpringBoot启动类中,该主类被@SpringBootApplication所修饰,跟踪该注解类,除元注解外,该注解类被如下自定注解修饰。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

让我们简单叙述下它们各自的功能:

  • @ComponentScan:扫描需要被IoC容器管理下需要管理的Bean,默认当前根目录下的
  • @EnableAutoConfiguration:装载所有第三方的Bean
  • @SpringBootConfiguration 作用等同于@Configuration

我们来看下@SpringBootConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
 @AliasFor(
  annotation = Configuration.class
 )
 boolean proxyBeanMethods() default true;
}

可以看到该注解类内包含与@Configuration,其作用与@Configuration并无太大区别,只是多了层属性嵌套。

故: @SpringBootConfiguration + @ComponentScan

将根目录下所有被**@Controller、@Service、@Repository、@Component**等所修饰的类交给IoC容器管理。

那么重点来了,@EnableAutoConfiguration是如何装载第三方Bean的呢?让我们跟踪下它的源码。

首先我们可以看到该类被如下注解修饰:

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})

我们先关注下AutoConfigurationImportSelector这个组件。

// 批量导入第三方的一些Bean
@Import({AutoConfigurationImportSelector.class})

其中该组件的selectImports(AnnotationMetadata annotationMetadata)方法,我们先简述下它的作用:扫描所有需要被管理的第三方Bean并交给IoC容器进行管理。然后我们接着往下追踪。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
 if (!this.isEnabled(annotationMetadata)) {
  return NO_IMPORTS;
 } else {
  // 让我们跟踪到这个方法
  AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
  return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
 }
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
 if (!this.isEnabled(annotationMetadata)) {
  return EMPTY_ENTRY;
 } else {
  AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
  // 获取所有AutoConfiguration的配置类
  List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
  // 下面就是对AutoConfiguration的去重、排除和过滤等操作
  configurations = this.removeDuplicates(configurations);
  Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
  this.checkExcludedClasses(configurations, exclusions);
  configurations.removeAll(exclusions);
  configurations = this.getConfigurationClassFilter().filter(configurations);
  // 我们继续追踪这里
  this.fireAutoConfigurationImportEvents(configurations, exclusions);
  return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
 }
}
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
 List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
 if (!listeners.isEmpty()) {
  // 加了层包装
  AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
  Iterator var5 = listeners.iterator();

  while(var5.hasNext()) {
   AutoConfigurationImportListener listener = (AutoConfigurationImportListener)var5.next();
   this.invokeAwareMethods(listener);
   // 向ConditionEvaluationReport中导入所有AutoConfiguration
   listener.onAutoConfigurationImportEvent(event);
  }
 }

}

可以猜想IoC容器在启动时会将这里的AutoConfiguration中的每个Bean都注入到容器中。这里的源码我们先跟踪到这里,大致了解了下该方法的作用。

那么SpringBoot又是如何取感知第三方的Bean文件呢?

SpringBoot和第三方Bean之间存在一定的规定。即通过对于相应依赖的Jar包中可能存在一个spring.factories文件,在该文件中就记录了需要被IoC容器管理的Bean文件路径,SpringBoot通过该文件确定需要IoC管理的Bean文件位置。对于spring-boot-autoconfiguration的spring.factories文件中,记录着大量xxxAutoConfiguration的类文件位置,这些类都被@Configuration注解标识,即这些配置类会配置多个Bean从而解决spring.factories可能产生的臃肿问题。

Tomcat的加载时机

对于SpringBoot来说它特点不仅是简化配置,还有内嵌容器等特点。那么就有必要探讨Tomcat容器的加载时机。在spring-boot-autoconfiguration的spring.factories文件中存在ServletWebServerFactoryAutoConfiguration配置类的路径,该类会在项目启动时将默认的Tomcat容器已@Bean的方式加载入IoC容器内部。

SpringBoot是如何集中配置呢?

谈论这个问题前我们不妨先按照之前yml或properties的文件配置下

server:
 port: 8080

通过IDE,跟踪到port所配置的成员变量所在类,发现该类被@ConfigurationProperties所修饰,该注解就是将yml或properties中配置按照对应前缀注入到指定类的成员变量。该注解具体实现感兴趣的小伙伴们可以去如下链接学习。   @ConfigurationProperties实现原理与实战

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
 private Integer port;
*******
}

下面两个代码和前述作用大致相同

environment.getProperty("xxx");

@Value("${xxx}")

我们在使用SpringBoot时只需要做哪些事情?

通常我们再使用SpringBoot时只需要在Maven中引入类似如下的starter依赖。

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

最多再需要配置一些类似mybatis这类框架的一些属性参数。而这些starter按照我们之前的逻辑其内部应该存有spring.factories文件,我们先去对应jar包查找下。

如果有些starter的jar包没有找到我们想要的spring.factories文件。我们可以去spring-boot-test-autoconfiguretion中的spring.factories查看下,SpringBoot内部其实已经定义好相当一定数量的AutoConfiguration。

果然该jar包内确实存在spring.factories文件,代码如下。

org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.redis.repository.support.RedisRepositoryFactory

这意味着我们已经简单地了解了SpringBoot如何简化配置,那么我们也应该可以自己来实现一个starter依赖交给SpringBoot来使用,只要在对应Jar包中添加spring.factories文件,在其中添加如下代码。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxxAutoConfiguration

大家若有时间还请实现下自己的starter依赖,对加深这部分理解还是很有帮助的。感兴趣的小伙伴可以看下我做的一个简单的实现。 [自定义starter实现]

最后我们在说下最后@SpringBootApplication中@AutoConfigurationPackage这个注解类,发现其中导入了Registrar组件。

@Import({Registrar.class})

让我们重点关注registerBeanDefinitions这个方法,该方法最终会来到DefaultListableBeanFactory中registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法,将AutoConfigurationPackages.class注册到IoC容器中,然后将主配置类所在包下所有组件导入到SpringIoC容器中

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
 // 里面就这一个方法我们跟踪下
 AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
 // 判断beanDefinitionMap是否存在AutoConfigurationPackages
 if (registry.containsBeanDefinition(BEAN)) {
  BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
  ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
  constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
 } else {
  GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
  beanDefinition.setBeanClass(AutoConfigurationPackages.BasePackages.class);
  beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
  beanDefinition.setRole(2);
  // 将设置好的AutoConfigurationPackages注册到beanDefinitionMap(是不是很熟悉这一步)
  registry.registerBeanDefinition(BEAN, beanDefinition);
 }

}

怎么样,在为我们简化了配置的同时,SpringBoot居然帮我们做了如此多的事情,而我们只需要简单地集中配置其中一部分的属性。关于SpirngBoot我们就探讨到这里,这些内容是阅读一些文章,观看部分讲解和源码的总结,若有错误还请接纳与指教。这是本人的第一篇文章,最后感谢各位的阅读。

到此这篇关于详解SpringBoot简化配置分析总结的文章就介绍到这了,更多相关SpringBoot 简化配置内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • spring boot的maven配置依赖详解

    本文介绍了spring boot的maven配置依赖详解,分享给大家,具体如下: 我们通过引用spring-boot-starter-parent,添加spring-boot-starter-web 可以实现web项目的功能,当然不使用spring-boot-start-web,通过自己添加的依赖包也可以实现,但是需要一个个添加,费时费力,而且可能产生版本依赖冲突.我们来看下springboot的依赖配置: 利用pom的继承,一处声明,处处使用.在最顶级的spring-boot-dependen

  • Spring Boot Redis 集成配置详解

    spring Boot 熟悉后,集成一个外部扩展是一件很容易的事,集成Redis也很简单,看下面步骤配置: 一.添加pom依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> 二.创建 RedisClient.java 注意该类存放的pack

  • Spring Boot使用yml格式进行配置的方法

    1.yml 格式 现在大家发现,在springboot里还是要用到配置文件的. 除了使用.properties外,springboot还支持 yml格式. 个人觉得yml格式的可读性和..properties比起来差不多,有时候还没有不如properties 看起来那么规整. 但是考虑到很多springboot项目会使用yml格式,还是简单讲讲,主要目的还是为了读懂其他人的项目. 2.同样内容,不同写法 如图所示,左边是application.properties的写法,右边是applicati

  • Spring Boot 日志配置方法(超详细)

    默认日志 Logback : 默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台.在运行应用程序和其他例子时,你应该已经看到很多INFO级别的日志了. 从上图可以看到,日志输出内容元素具体如下: 时间日期:精确到毫秒 日志级别:ERROR, WARN, INFO, DEBUG or TRACE 进程ID 分隔符:- 标识实际日志的开始 线程名:方括号括起来(可能会截断控制台输出) Logger名:通常使用源代码的类名 日志内容 添加日志依赖 假如mave

  • Spring boot 默认静态资源路径与手动配置访问路径的方法

    在application.propertis中配置 ##端口号 server.port=8081 ##默认前缀 spring.mvc.view.prefix=/ ## 响应页面默认后缀 spring.mvc.view.suffix=.html # 默认值为 /** spring.mvc.static-path-pattern=/** # 这里设置要指向的路径,多个使用英文逗号隔开,默认值为 classpath:/META-INF/resources/,classpath:/resources/,

  • SpringBoot + Spring Security 基本使用及个性化登录配置详解

    Spring Security 基本介绍 这里就不对Spring Security进行过多的介绍了,具体的可以参考官方文档 我就只说下SpringSecurity核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) 基本环境搭建 这里我们以SpringBoot作为项目的基本框架,我这里使用的是maven的方式来进行的包管理,所以这里先给出集成Spring Security的方式 <dependencies> ... <dependency> <groupI

  • 详解SpringBoot配置连接池

    内置的连接池 目前spring Boot中默认支持的连接池有dbcp,dbcp2, tomcat, hikari三种连接池. 数据库连接可以使用DataSource池进行自动配置. 由于Tomcat数据源连接池的性能和并发,在tomcat可用时,我们总是优先使用它. 如果HikariCP可用,我们将使用它. 如果Commons DBCP可用,我们将使用它,但在生产环境不推荐使用它. 最后,如果Commons DBCP2可用,我们将使用它. 以上的几种连接池,可以通过在配置application文

  • 详解SpringBoot简化配置分析总结

    在SpringBoot启动类中,该主类被@SpringBootApplication所修饰,跟踪该注解类,除元注解外,该注解类被如下自定注解修饰. @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan 让我们简单叙述下它们各自的功能: @ComponentScan:扫描需要被IoC容器管理下需要管理的Bean,默认当前根目录下的 @EnableAutoConfiguration:装载所有第三方的Bean @SpringB

  • 详解SpringBoot自动配置源码

    一.引导加载自动配置类 @SpringBootApplication注解相当于@SpringBootConfiguration.@EnableAutoConfiguration.@ComponentScan这三个注解的整合 @SpringBootConfiguration 这个注解也使用了@Configuration标注,代表当前是一个配置类 @ComponentScan 包扫描,指定扫描哪些注解 @EnableAutoConfiguration 这个注解也是一个合成注解 @AutoConfig

  • 详解SpringBoot自定义配置与整合Druid

    目录 SpringBoot配置文件 优先级 yaml的多文档配置 扩展SpringMVC 添加自定义视图解析器 自定义DruidDataSources About Druid 添加依赖 配置数据源 其他配置 Druid配置类 测试类 数据源监控 监控过滤器filter配置 SpringBoot配置文件 优先级 前面SpringBoot基础有提到,关于SpringBoot配置文件可以是properties或者是yaml格式的文件,但是在SpringBoot加载application配置文件时是存在

  • 详解SpringBoot Schedule配置

    1. 定时任务实现方式 定时任务实现方式: Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行.一般用的较少,这篇文章将不做详细介绍. 使用Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂,有空介绍. SpringBoot自带的Scheduled,可以将它看成一个轻量级的Quartz,而且使用起来比Q

  • 详解SpringBoot Redis自适应配置(Cluster Standalone Sentinel)

    核心代码段 提供一个JedisConnectionFactory  根据配置来判断 单点 集群 还是哨兵 @Bean @ConditionalOnMissingBean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = null; String[] split = node.split(","); Set<HostAndPort> nodes =

  • 详解SpringBoot配置文件启动时动态配置参数方法

    序言 当我们要同时启用多个项目而又要使用不同端口或者变换配置属性时,我们可以在配置文件中设置${变量名}的变量来获取启动时传入的参数,从而实现了动态配置参数,使启用项目更加灵活 例子 server: port: ${PORT:50101} #服务端口 spring: application: name: xc‐govern‐center #指定服务名 eureka: client: registerWithEureka: true #服务注册,是否将自己注册到Eureka服务中 fetchReg

  • 详解Springboot之整合JDBCTemplate配置多数据源

    一.前言 现在在我们的项目中,使用多数据源已经是很常见的,下面,这里总结一下springboot整合jdbcTemplate配置多数据源的代码示例,以方便以后直接使用. 二.配置文件 spring: datasource: datasourceone: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/eesy?serverTimezone=UTC&characterEncoding=utf8&u

  • 详解SpringBoot中自定义和配置拦截器的方法

    目录 1.SpringBoot版本 2.什么是拦截器 3.工作原理 4.拦截器的工作流程 4.1正常流程 4.2中断流程 5.应用场景 6.如何自定义一个拦截器 7.如何使其在Spring Boot中生效 8.实际使用 8.1场景模拟 8.2思路 8.3实现过程 8.4效果体验 9.总结 1.SpringBoot版本 本文基于的Spring Boot的版本是2.6.7 . 2.什么是拦截器 Spring MVC中的拦截器(Interceptor)类似于ServLet中的过滤器(Filter),它

  • 详解springboot整合ehcache实现缓存机制

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. ehcache提供了多种缓存策略,主要分为内存和磁盘两级,所以无需担心容量问题. spring-boot是一个快速的集成框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置. 由于spring-boot无需任何样板化的配置文件,所以spring-boot集成一些其他框架时会有略微的

  • 详解springboot+mybatis-plue实现内置的CRUD使用详情

    mybatis-plus的特性 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作 强大的 CRUD操作:内置通用 Mapper.通用Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 支持 Lambda形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 支持主键自动生成:支持多达 4种主键策略(内含分布式唯一 ID 生成器

随机推荐