spring boot 的 自动配置原理

Spring Boot面试杀手锏————自动配置原理 引言 不论在工作中,亦或是求职面试,Spring Boot已经成为我们必知必会的技能项。除了某些老旧的政府项目或金融项目持有观望态度外,如今的各行各业都在飞速的拥抱这个已经不是很新的Spring启动框架。 当然,作为Spring Boot的精髓,自动配置原理的工作过程往往只有在“面试”的时候才能用得上,但是如果在工作中你能够深入的理解Spring Boot自动配置原理,将无往不利。 Spr... 阅读详情

一.Condition

Condition 是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操作。

演示1:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    1. 没有添加坐标前,发现为空,报错
        ConfigurableApplicationContext context =  SpringApplication.run(SpringbootCondition01Application.class, args);
        Object redisTemplate = context.getBean("redisTemplate");
        System.out.println(redisTemplate);
    2. 有添加坐标前,发现有对象
        ConfigurableApplicationContext context =  SpringApplication.run(SpringbootCondition01Application.class, args);
        Object redisTemplate = context.getBean("redisTemplate");
        System.out.println(redisTemplate);
    疑问,他怎么知道的配置哪个类

案例:需求1

在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:

  1. 导入Jedis坐标后,加载该Bean,没导入,则不加载。

案例:需求2

在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:

​ 将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定

​ 实现步骤:

  • 不使用@Conditional(ClassCondition.class)注解
  • 自定义注解@ConditionOnClass,因为他和之前@Conditional注解功能一直,所以直接复制
  • 编写ClassCondition中的matches方法

Condition – 小结

自定义条件:

​ ① 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判断,返回

​ boolean值 。 matches 方法两个参数:

​ • context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。

​ • metadata:元数据对象,用于获取注解属性。

​ ② 判断条件: 在初始化Bean时,使用 @Conditional(条件类.class)注解

SpringBoot 提供的常用条件注解:

一下注解在springBoot-autoconfigure的condition包下

  • ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
  • ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
  • ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean
  • ConditionalOnBean:判断环境中有对应Bean才初始化Bean

可以查看RedisAutoConfiguration类说明以上注解使用

距离演示ConditionalOnProperty

二.@Enable注解

SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理是使用@Import注 解导入一些配置类,实现Bean的动态加载

@Import注解

@Enable底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:

​ ① 导入Bean

​ ② 导入配置类

​ ③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类

​ ④ 导入 ImportBeanDefinitionRegistrar 实现类。

三.@EnableAutoConfiguration 注解

  • 主启动类
    //@SpringBootApplication 来标注一个主程序类
    //说明这是一个Spring Boot应用
    @SpringBootApplication
    public class SpringbootApplication {
       public static void main(String[] args) {
         //以为是启动了一个方法,没想到启动了一个服务
          SpringApplication.run(SpringbootApplication.class, args);
       }
    }
    
  • @SpringBootApplication注解内部
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
        // ......
    }
    

    @ComponentScan

    这个注解在Spring中很重要 ,它对应XML配置中的元素。

    作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中

    @SpringBootConfiguration

    作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;

    //@SpringBootConfiguration注解内部
    //这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
    @Configuration
    public @interface SpringBootConfiguration {}
    //里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用
    @Component
    public @interface Configuration {}
    

    @AutoConfigurationPackage :自动配置包

//AutoConfigurationPackage的子注解
//Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@EnableAutoConfiguration开启自动配置功能

以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration

告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;

AutoConfigurationImportSelector :自动配置导入选择器,给容器中导入一些组件

AutoConfigurationImportSelector.class
			↓
    selectImports方法
    		↓
this.getAutoConfigurationEntry(annotationMetadata)方法
			↓
this.getCandidateConfigurations(annotationMetadata, attributes)方法
			↓
方法体:
 List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        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;
			↓
在所有包名叫做autoConfiguration的包下面都有META-INF/spring.factories文件

总结原理:

  • @EnableAutoConfiguration 注解内部使用 @Import(AutoConfigurationImportSelector.class)来加载配置类。
  • 配置文件位置:META-INF/spring.factories,该配置文件中定义了大量的配置类,当 SpringBoot 应用启动时,会自动加载这些配置类,初始化Bean
  • 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean

四.SpringBoot 启动流程

  1. 基于SpringBoot开发的项目中都会有一个@SpringBootApplication注解配置的启动类,启动类中会有一个main()方法作为启动入口,main()方法中调用SpringApplication.run(),开始启动整个SpringBoot应用程序;
  2. SpringApplication.run()方法中,首先进行初始化,创建SpringApplication对象,通过它的构造方法,完成初始化,读取自动配置核心类;
  3. 通过执行SpringApplication对象的run()方法,完成SpringBoot应用程序的启动逻辑:启动流程的监听、配置环境、打印启动Banner、创建Spring容器、记录启动时间、执行Runner(ApplicationRunner和CommandLineRunner)等启动步骤;

01. 启动:通过配置启动类,运行main()主函数,开始启动

SpringBoot程序都有一个main()方法作为启动入口,main()方法中调用SpringApplication.run(),开始启动整个SpringBoot应用程序。

@SpringBootApplication
public class Springboot01Application {
    public static void main(String[] args) {
        SpringApplication.run(Springboot01Application.class, args);
    }
}

main()方法所在的SpringBoot启动类,需要使用@SpringBootApplication注解,如果需要导入配置文件,可以使用@ImportResource注解;

@SpringBootApplication包括三个注解,功能如下:

  1. @EnableAutoConfiguration:SpringBoot根据spring-boot-autoconfigure-2.5.4.jar的spring.factories文件中声明的自动配置类,完成SpringBoot框架的自动配置;
  2. @SpringBootConfiguration:被标注的类是一个SpringBoot配置类,用于加载bean,提供了一个Spring容器。作用类似Spring的XML配置文件(applicationContext.xml);
  3. @ComponentScan:组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Booter.class所在的包路径下文件,所以最好将该启动类放到根包路径下;

02. 初始化:创建SpringApplication对象

首先,创建SpringApplication对象,通过它的构造方法,完成初始化

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    // 通过SpringApplication()构造方法,进行初始化
    return (new SpringApplication(primarySources)).run(args);
}

SpringApplication的构造方法,用于SpringBoot初始化:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 1.将resourceLoader资源加载器设置为null
    this.resourceLoader = resourceLoader;

    // 2.通过断言,判断加载资源类是否为null
    Assert.notNull(primarySources, "PrimarySources must not be null");

    // 3. 将所要加载的启动类Class对象存入LinkedHashSet集合中,进行去重操作
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

    // 4、推断当前 WEB 应用类型
    // 如果Classpath中加载的类中出现“"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"”
    // 则当前应用类型为基于DispatcherServlet核心处理器的Web应用程序
    this.webApplicationType = WebApplicationType.deduceFromClasspath();

    // 5、应用上线文初始化器,完成自动化配置类的读取
    // 在this.getSpringFactoriesInstances()中,通过调用 SpringFactoriesLoader.loadFactoryNames()方法,读取项目jar文件中所有的META-INF/spring.factories文件
    // spring.factories文件中包含有核心框架接口与实现类的映射配置关系
    // 其中spring-boot-autoconfigure-2.5.4.jar的spring.factories文件包含SpringBoot最重要的Auto Configure自动配置类列表(EnableAutoConfiguration注解)
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

    // 6、设置监听器
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

    // 7、推断主入口应用类
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

03. 运行:调用SpringApplication对象的run()方法

通过调用SpringApplication对象的run(),执行SpringBoot应用程序的启动逻辑:启动流程的监听、配置环境、打印启动Banner、创建Spring容器、记录启动时间、执行Runner(ApplicationRunner和CommandLineRunner)

public ConfigurableApplicationContext run(String... args) {
    	// 1. 创建一个StopWatch计时监控类对象,并执行start方法,用于记录SpringBoot启动时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

		// 2. 创建启动上下文对象
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        
		// 3. 配置Headless属性,Headless模式是在缺少显示屏、键盘或者鼠标时候的系统配置
		this.configureHeadlessProperty();
		
		// 4. 在文件META-INF\spring.factories中
		// 获取SpringApplicationRunListener接口的实现类EventPublishingRunListener对象
		// 通过观察者模式,监听SpringBoot应用程序启动的生命周期(执行run、执行prepareEnvironment、加载Spring容器、刷新容器)
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        
		// 5. 发布启动开始事件
		listeners.starting(bootstrapContext, this.mainApplicationClass); 

        try {
			// 6. 把输入参数转成DefaultApplicationArguments类
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

			// 7. 配置环境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            
			// 6. 打印启动Banner信息
			Banner printedBanner = this.printBanner(environment);

			// 8. 创建Spring容器(ApplicationContext接口实现类对象)
            // 根据WebApplicationType的不同,创建不同类型的ApplicationContext
			// 如果是基于Servlet的Web项目,则创建AnnotationConfigServletWebServerApplicationContext
			// 如果非web项目,则创建AnnotationConfigApplicationContext
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

			// 9. 预处理上下文并刷新
			this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            
			// 10. 记录SpringBoot启动时间结束,
			// 进行日志输出:Started Springboot01Application in 3.581 seconds (JVM running for 4.211)
			stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

			// 11. 发布启动结束事件
            listeners.started(context);
			
			// 12. 调用Runner
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
}
[Spring Boot] 4. Spring Boot实现自动配置原理 入口注解类@EnableAutoConfiguration@SpringBootApplication注解中包含了自动配置的入口注解:@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration 阅读详情

相关推荐

Spring Boot 自动配置 (AutoConfiguration) 原理与实践

掌握 Spring Boot 自动配置,能够更高效地构建 Spring Boot 应用,并更好地理解 Spring Boot 的设计思想。Spring Boot 自动配置是其核心优势,它极大地简化了 Spring 应用的开发。理解自动配置原理,掌握条件注解的使用,以及学会自定义自动配置,是深入 Spring Boot 的关键。是其核心特性,它极大地简化了 Spring 应用的配置,提升了开发效率。开发者可以自定义自动配置类,扩展 Spring Boot 的功能。等,分别负责不同功能的自动配置

weixin_52568491的博客 1980

Spring本地启动Main函数-AnnotationConfigApplicationContext

spring

z69183787的专栏 1339

Spring boot面试题---- Spring Boot 自动配置原理

Spring boot面试题---- Spring Boot 自动配置原理

qq_38737545的博客 3575

springboot 自动配置原理

springboot 自动配置原理、EnableAutoConfiguration、Configuration、ComponentScan、DeferredImportSelector、ImportSelector

杨宇昌的博客 1万+

SpringBoot自动配置原理

Spring Boot通过@EnableAutoConfiguration注解开启自动配置,对jar包下的spring.factories文件进行扫描,这个文件中包含了可以进行自动配置的类,当满足@Condition注解指定的条件时,便在依赖的支持下进行实例化,注册到Spring容器中。通俗的来讲,我们之前在写ssm项目时候,配置了大量坐标和配置内容,搭环境的过程在项目开发中占据了大量时间,Spring Boot的最大的特点就是简化了各种xml配置内容,所以springboot自动配置。...

m0_46420244的博客 2万+

SpringBoot自动配置原理详解

SpringBoot 的核心:自动配置原理详解

真滴不可理喻的博客 1万+

springboot系列--自动配置原理

1、SpringBoot启动时先加载META-INF/spring.factories下所有的自动配置类 xxxxxAutoConfiguration2、每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定3、生效的配置类就会给容器中装配很多组件4、只要容器中有这些组件,相当于这些功能就有了5、用户可以自己定制化配置,有两种方式:a、直接自己写配置类使用@Bean替换底层的组件。

编程不良人 3219

Spring Boot 自动配置原理详解

的原则,根据项目依赖和上下文环境自动配置应用程序。:根据类路径、Bean存在性、配置属性等条件决定是否启用配置。:简化依赖管理和自动配置的整合。优先使用自动配置,必要时通过自定义 Bean 覆盖。编写自动配置类并使用条件注解控制生效逻辑。通过条件注解精确控制配置类的生效条件。Spring Boot 自动配置通过。,负责加载所有自动配置类。),筛选出符合条件的配置类。:触发自动配置的加载流程。定义的优先级加载配置类。参数,输出条件评估详情。键下的所有自动配置类。模式分析配置加载过程。

qq_62112907的博客 2620

Spring Boot自动配置原理详解

技术组件核心功能工作原理启用自动配置导入AutoConfigurationImportSelector选择要导入的配置实现ImportSelector接口,返回需要导入的类名数组Spring Factories机制配置发现机制通过META-INF/spring.factories文件定位配置类条件注解配置条件判断@ConditionalOnXXX系列根据条件决定是否应用配置自动配置排序控制配置加载顺序通过@AutoConfigureOrder控制优先级属性绑定外部化配置。

m0_73889530的博客 1234

Spring Boot 自动配置原理

创建一个自动配置类,并使用注解实现条件化配置:​@BeanSpring Boot自动配置通过和实现。自动配置类通过注解实现条件化配置。自动配置的核心是文件,它定义了所有自动配置类。开发者可以通过自定义自动配置类扩展 Spring Boot 的功能。通过理解自动配置原理,开发者可以更好地掌握 Spring Boot 的工作机制,并能够根据需求进行定制化开发。

Azraelkaxi的博客 1235

Spring Boot自动配置原理解析

在常规的SSM项目中,通常需要用户自己去进行SpringSpring MVC、Mybatis的整合,以及Tomcat的配置。的依赖,在中就已经完成了SpringSpring MVC、Tomcat的整合,通常被称为自动配置。而完成自动配置的关键,在于启动类上的注解:是一个复合注解,其中包含了和Spring Boot的@SpringBootConfiguration:标记当前类是配置类,并且将当前类加入Spring 容器。

西岭千秋雪的博客 1416

Spring Boot 自动配置与启动原理全解析

Spring Boot 的“自动配置”靠的是配合条件注解。启动流程的核心是,它完成了环境准备、Bean 加载、容器创建、Web 容器启动等步骤。灵活可扩展:你可以随时覆盖默认配置,也可以通过监听器、初始化器参与启动流程。

m0_73748193的博客 3048

Spring Boot自动配置原理

Spring Boot自动配置原理 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。它使用“习惯优于配置”的理念可以让你的项目快速运行部署。使用Spring Boot可以不用或者只需要很少的Spring配置。 Spring Boot核心的功能就是自动配置。它会根据在类路径中的jar、类自动配置Bean,当我...

Usher_Ou的博客 8680

深入解析Spring Boot自动配置原理

通过对源码的解析,我们了解到,Spring Boot自动配置机制主要依赖于 @EnableAutoConfiguration 注解,以及 META-INF/spring.factories 文件中的自动配置类列表。这些自动配置类通过条件注解,决定是否将特定的 Bean 注册到 Spring 容器中,从而实现按需配置,简化开发过程。为了解决这一问题,Spring Boot 引入了自动配置的概念,根据项目的依赖和运行环境,自动配置所需的 Bean,从而简化开发过程。

小健学Java的博客 1472

面试官:说一下Spring Boot自动配置原理

那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。除了官方文档为我们提供了大量的属性解释,我们也可以使用IDE的相关提示功能,比如IDEA的自动提示,和Eclipse的YEdit插件,都可以很好的对你需要配置的属性进行提示,下图是使用Eclipse的YEdit插件的效果,Eclipse的版本是:STS 4。

m0_69632475的博客 1087
上一篇: Spring boot 的启动原理
下一篇: HTML常用标签及CSS常用样式
Myleague
博客等级 码龄5年 1粉丝 · 4原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值