SpringBoot的自动装配原理

简介: SpringBoot的自动装配原理

正文


SpringBoot是如何将相关组件装配到IOC的容器里面的?这个是核心的问题。


一、主启动类


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/08/03
 */
@EnableAsync // 开启是否支持异步的操作
@SpringBootApplication // 声明当前的应用是SpringBoot的应用
public class StartMain {
    public static void main(String[] args) {
        SpringApplication.run(StartMain.class, args);
    }
}


二、@SpringBootApplication注解的功能


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // SpringBoot的配置 与 @Configuration的作用类似,都是可以自动发现配置的
@EnableAutoConfiguration // 开启自动的装配的功能个
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
// 上面的 @ComponentScan 是包扫描方案,扫描哪些包
public @interface SpringBootApplication {


三、@EnableAutoConfiguration的功能


一共提供了@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)两个核心的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {


3.1 @AutoConfigurationPackage注解的功能


自动的配置我们的主启动类上面的包名

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}

AutoConfigurationPackages.Registrar.class的主要的作用就是注册一个GenericBeanDefinition的bean的定义给IOC的容器。

将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;


3.2 AutoConfigurationImportSelector的功能


AutoConfigurationImportSelector:导入哪些组件的选择器;

将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;

会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件, 并配置好这些组件;

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports
@Override
  public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
    }
    // 家在自动配置的属性
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
        .loadMetadata(this.beanClassLoader);
    // 获取到自己配置的相关信息,这里面也返回了我们需要自动配置的类的信息
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
        annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  }

接下来分析:getAutoConfigurationEntry方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
    }
  // 获取到注解的属性信息
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
  // 获取到候选的配置信息,这一步也就是加载了所有的自动配置的信息,一会主要分析的就是这个方法
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
  // 去除掉重复的配置信息
    configurations = removeDuplicates(configurations);
  // 根据以前的配置,获取到所有需要排除的信息
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  // 校验需要排除的配置类的信息
    checkExcludedClasses(configurations, exclusions);
  // 执行移除的操作
    configurations.removeAll(exclusions);
  // 过滤一下配置的信息与获取到的后信息是否有问题
    configurations = filter(configurations, autoConfigurationMetadata);
  // 首先获取到所有的配置的监听器,之后配置listener.onAutoConfigurationImportEvent(event);
    fireAutoConfigurationImportEvents(configurations, exclusions);
  //返回操作的对象
    return new AutoConfigurationEntry(configurations, exclusions);
  }


3.3 getCandidateConfigurations


这个是主要的返回我们候选配置类的基本信息:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  // 显然,和我们以前分析的一样,都是从META-INF/spring.factories获取到所有的EnableAutoConfiguration的组件并且进行返回。
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
        getBeanClassLoader());
  // 判断是否为空,默认肯定不是空的,因为spring-boot-autoconfigure-2.2.2.RELEASE.jar已经为我们配置了一些主要的的自动配置类。
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
        + "are using a custom packaging, make sure that file is correct.");
    return configurations;
  }


四、如何将组件加入到IOC容器呢?


4.1 META-INF/spring.factories文件到底是什么样的


首先,在spring-boot-autoconfigure-2.2.2.RELEASE.jar里面,我们可以找到下面的文件

9.png

查看一下内容

# Auto Configure
# 可以看到一些自动配置的信息
# 全类名=自动配置类的集合
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
...


4.2 举例说明如何自动配置


我们用org.springframework.boot.autoconfigure.aop.AopAutoConfiguration为例子,来看一看如何的自动配置

// 说明当前是一个配置类
@Configuration(proxyBeanMethods = false)
// 判断当前是否配置了 spring.aop 的相关的配置
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
  @Configuration(proxyBeanMethods = false)
  // 当 Advice 存在的是欧,这个配置是生效的
  @ConditionalOnClass(Advice.class)
  static class AspectJAutoProxyingConfiguration {
    @Configuration(proxyBeanMethods = false)
    @EnableAspectJAutoProxy(proxyTargetClass = false)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
        matchIfMissing = false)
    static class JdkDynamicAutoProxyConfiguration {
    }
    @Configuration(proxyBeanMethods = false)
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
        matchIfMissing = true)
    static class CglibAutoProxyConfiguration {
    }
  }
  @Configuration(proxyBeanMethods = false)
  // 不存在 org.aspectj.weaver.Advice这个类,是生效的
  @ConditionalOnMissingClass("org.aspectj.weaver.Advice")
  @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
      matchIfMissing = true)
  static class ClassProxyingConfiguration {
    ClassProxyingConfiguration(BeanFactory beanFactory) {
      if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }
    }
  }
}

通过上面的分析,其实我们可以发现,我们可以根据特定的环境分别的配置我们的组件,何时生效以及何时不生效,也就是这样,实现了SpringBoot的自动装配的最终的效果,实现了SpringBoot的精髓功能。


五、后记


@Conditional派生注解:

必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;

@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项
相关文章
|
2月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
37 0
|
10天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
17天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
67 14
|
2月前
|
Java Spring
SpringBoot自动装配的原理
在Spring Boot项目中,启动引导类通常使用`@SpringBootApplication`注解。该注解集成了`@SpringBootConfiguration`、`@ComponentScan`和`@EnableAutoConfiguration`三个注解,分别用于标记配置类、开启组件扫描和启用自动配置。
62 17
|
2月前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
40 2
|
2月前
|
Java 容器
springboot自动配置原理
启动类@SpringbootApplication注解下,有三个关键注解 (1)@springbootConfiguration:表示启动类是一个自动配置类 (2)@CompontScan:扫描启动类所在包外的组件到容器中 (3)@EnableConfigutarion:最关键的一个注解,他拥有两个子注解,其中@AutoConfigurationpackageu会将启动类所在包下的所有组件到容器中,@Import会导入一个自动配置文件选择器,他会去加载META_INF目录下的spring.factories文件,这个文件中存放很大自动配置类的全类名,这些类会根据元注解的装配条件生效,生效
|
6月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
130 0
|
3月前
|
Java Spring 容器
springboot @RequiredArgsConstructor @Lazy解决循环依赖的原理
【10月更文挑战第15天】在Spring Boot应用中,循环依赖是一个常见问题,当两个或多个Bean相互依赖时,会导致Spring容器陷入死循环。本文通过比较@RequiredArgsConstructor和@Lazy注解,探讨它们解决循环依赖的原理和优缺点。@RequiredArgsConstructor通过构造函数注入依赖,使代码更简洁;@Lazy则通过延迟Bean的初始化,打破创建顺序依赖。两者各有优势,需根据具体场景选择合适的方法。
130 4
|
4月前
|
Java 应用服务中间件 API
Vertx高并发理论原理以及对比SpringBoot
Vertx 是一个基于 Netty 的响应式工具包,不同于传统框架如 Spring,它的侵入性较小,甚至可在 Spring Boot 中使用。响应式编程(Reactive Programming)基于事件模式,通过事件流触发任务执行,其核心在于事件流 Stream。相比多线程异步,响应式编程能以更少线程完成更多任务,减少内存消耗与上下文切换开销,提高 CPU 利用率。Vertx 适用于高并发系统,如 IM 系统、高性能中间件及需要较少服务器支持大规模 WEB 应用的场景。随着 JDK 21 引入协程,未来 Tomcat 也将优化支持更高并发,降低响应式框架的必要性。
Vertx高并发理论原理以及对比SpringBoot
|
4月前
|
Java 开发者 数据格式
【Java笔记+踩坑】SpringBoot基础4——原理篇
bean的8种加载方式,自动配置原理、自定义starter开发、SpringBoot程序启动流程解析
【Java笔记+踩坑】SpringBoot基础4——原理篇