springboot自动配置原理

 一、简介

        Spring Boot 的自动配置机制是其最核心的功能之一,它使得开发者能够快速地搭建应用程序而无需过多的手动配置。下面是对 Spring Boot 自动配置原理的一个概述:

1. Starter POMs (启动器)

Spring Boot 提供了一系列的 Starter POMs,这些 POMs 包含了构建应用所需的依赖项集合。例如,spring-boot-starter-web 包含了 Web 应用所需的所有依赖。

2. Auto-configuration (自动配置)

当引入 Starter POMs 时,Spring Boot 会自动查找并启用对应的自动配置类。自动配置类通常位于 org.springframework.boot.autoconfigure 包及其子包下,并带有 @EnableAutoConfiguration 注解。

关键组件
  • @SpringBootApplication:这是 Spring Boot 应用的主注解,它包含了 @SpringBootConfiguration@EnableAutoConfiguration 和 @ComponentScan。其中 @EnableAutoConfiguration 是启动自动配置的关键。
  • @EnableAutoConfiguration:该注解用来激活自动配置功能。
  • @AutoConfigurationPackage:此注解用于指定自动配置包的位置。
  • @Import:用于导入特定的自动配置类。
配置查找
  • spring.factories:在 META-INF/spring.factories 文件中定义了自动配置类的列表。例如,org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration 会被添加到 Spring 应用上下文中。
  • 条件注解:如 @ConditionalOnClass@ConditionalOnMissingBean@ConditionalOnProperty 等,用于控制自动配置类是否生效。

3. 自动配置类

每个自动配置类都负责为特定的组件或技术栈设置默认配置。这些类通常会检查应用上下文中的 Bean 是否存在,以及环境变量和配置文件中的属性值,从而决定是否激活某些配置。

4. 默认配置和覆盖

Spring Boot 会为很多常用的框架和技术提供默认的配置,但这些配置可以被覆盖。开发者可以通过编写自己的配置类,或者在 application.properties 或 application.yml 文件中修改属性值来覆盖默认配置。

5. 自定义自动配置

如果需要为某个第三方库提供自动配置支持,可以创建自己的自动配置类,并遵循上述的模式。通常需要在 META-INF/spring.factories 文件中注册新的自动配置类。

示例

假设我们使用了 spring-boot-starter-web,那么 Spring Boot 会自动寻找 DispatcherServlet 并配置相关的 Bean。例如,它会自动配置 Tomcat 嵌入式服务器、DispatcherServlet 以及相关组件。

这就是 Spring Boot 自动配置的基本原理。它大大简化了开发过程,使开发者能够专注于业务逻辑而不是繁琐的配置细节。

二、springboot自动配置

1.Condition

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

测试:

思考: SpringBoot 是如何知道要创建哪个 Bean 的?比如 SpringBoot 是如何知道要创建 RedisTemplate 的?

导入坐标

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

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

ClassConditon.java

public class ClassCondition implements Condition {
    /**
     *
     * @param context 上下文对象。用于获取环境,IOC容器,ClassLoader对象
     * @param metadata 注解元对象。 可以用于获取注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //1.需求: 导入Jedis坐标后创建Bean
        //思路:判断redis.clients.jedis.Jedis.class文件是否存在

        boolean flag = true;
        try {
            Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag = false;
        }
        return flag;

    }
}

UserConfig.java

@Configuration
public class UserConfig {

    //@Conditional中的ClassCondition.class的matches方法,返回true执行以下代码,否则反之
    @Bean
    @Conditional(value= ClassCondition.class)
    public User user(){
        return new User();
    }


}

User.java

public class User {

}

启动类

@SpringBootApplication
public class SpringbootCondition01Application {

    public static void main(String[] args) {

        //启动SpringBoot的应用,返回Spring的IOC容器
        ConfigurableApplicationContext context =  SpringApplication.run(SpringbootCondition01Application.class, args);
        //获取Bean,redisTemplate
        //情况1 没有添加坐标前,发现为空
        //情况2 有添加坐标前,发现有对象
//        Object redisTemplate = context.getBean("redisTemplate");
//        System.out.println(redisTemplate);

        /********************案例1********************/
        Object user = context.getBean("user");
        System.out.println(user);


    }

}

1. 没有添加坐标前,发现为空,报错

 2. 有添加坐标前,发现有对象

小结

自定义条件:
① 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判 断,返回 boolean值 。
matches 方法两个参数:
context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
metadata:元数据对象,用于获取注解属性。
② 判断条件: 在初始化Bean时,使用 @Conditional(条件类.class)注解

ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean

ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean

ConditionalOnMissingBean:判断环境中没有对应Bean才初始化

Bean ConditionalOnBean:判断环境中有对应Bean才初始化Bean

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

2.@Enable注解

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

@Import注解

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

① 导入Bean

② 导入配置类

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

④ 导入 ImportBeanDefinitionRegistrar 实现类。

思考 SpringBoot 工程是否可以直接获取jar包中定义的Bean?

 

测试:

创建两个类springboot_enable和springboot_other

其中 springboot-enable-other用于模拟其他jar包

在springboot_enable中导入spring_enable_other坐标

<!--导入坐标-->
        <dependency>
            <groupId>com.apesource</groupId>
            <artifactId>springboot-enable_other-04</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

MyImportBeanDefinitionRegistrar.java

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //AnnotationMetadata注解
        //BeanDefinitionRegistry向spring容器中注入

        //1.获取user的definition对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();

        //2.通过beanDefinition属性信息,向spring容器中注册id为user的对象
        registry.registerBeanDefinition("user", beanDefinition);

    }
}

MyImportSelector.java

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //目前字符串数组的内容是写死的,未来可以设置在配置文件中动态加载
        return new String[]{"com.apesource.domain.User", "com.apesource.domain.Student"};
    }
}

UserConfig.java

@Configuration
public class UserConfig {

    @Bean
    public User userTest() {
        return new User();
    }


}

Student.java

public class Student {
}

User.java

public class User {
}

测试类

@SpringBootApplication
//@Import(User.class)
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
@Import({MyImportBeanDefinitionRegistrar.class})
//@EnableCaching
//@EnableAsync
public class SpringbootEnable03Application {



    public static void main(String[] args) {

        ConfigurableApplicationContext context =  SpringApplication.run(SpringbootEnable03Application.class, args);
        /**
         * Import4中用法:
         *  1. 导入Bean
         *  2. 导入配置类
         *  3. 导入ImportSelector的实现类
         *      查看ImportSelector接口源码
         *          String[] selectImports(AnnotationMetadata importingClassMetadata);
         *          代表将“字符串数组”中的的类,全部导入spring容器
         *  4. 导入ImportBeanDefinitionRegistrar实现类
         *
         */
//        User user = context.getBean(User.class);
//        System.out.println(user);
//
//        Student student = context.getBean(Student.class);
//        System.out.println(student);

        User user = (User) context.getBean("user");
        System.out.println(user);


    }

}

3.@EnableAutoConfiguration 注解 

主启动类


//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//以为是启动了一个方法,没想到启动了一个服务
SpringApplication.run(SpringbootApplication.class, args);
}
}

@SpringBootApplication注解内部

@ComponentScan

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

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

@SpringBootConfiguration

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

@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

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot自动配置原理简述 SpringBoot自动配置SpringBoot的一大特色,它提供了一种简洁的方式来配置应用程序。在SpringBoot中,我们可以通过添加特定的依赖来自动配置应用程序的各种组件,例如数据源、日志、Web服务等。使用自动配置可以大大简化应用程序的配置过程,减少开发人员的工作量,提高开发效率。 自动配置的实现原理是基于Spring的条件化配置机制。SpringBoot会根据应用程序的依赖和当前环境自动配置各种组件。条件化配置可以通过在类上添加@Conditional注解来实现,该注解可以指定一个条件类,只有满足该条件类的条件时,才会进行配置。例如,以下代码示例中,只有当classpath中存在H2数据库驱动程序时,才会自动配置H2的数据源。 @Configuration @ConditionalOnClass(org.h2.Driver.class) public class H2DataSourceAutoConfiguration { // 配置H2数据源 } 除了依赖条件外,SpringBoot还支持很多其他条件,例如环境条件、属性条件、Bean条件等。通过组合这些条件,可以实现更加灵活的自动配置。例如,以下代码示例中,只有当当前环境为开发环境时,才会自动配置开发环境的日志。 @Configuration @Profile("dev") public class DevLoggerAutoConfiguration { // 配置开发环境的日志 } 总之,SpringBoot自动配置机制是基于Spring的条件化配置机制实现的,它可以根据应用程序的依赖和当前环境自动配置各种组件,大大简化了应用程序的配置过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值