Spring Boot自动配置原理与实践

本文深入探讨Spring Boot自动配置的原理,从@EnableAutoConfiguration的启用到Meta-INF/spring.factories文件的解析,揭示自动配置的发现过程。同时,通过RedisAutoConfiguration为例,展示Spring Boot如何利用条件注解实现灵活配置,包括@ConditionalOnClass、@ConditionalOnMissingBean等,以及自动配置类的基本构成部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Spring Boot自动配置的原理介绍

 

  主要从spring boot是如何启动后自动检测自动配置与spring boot如何灵活处理自动配置两个方面讲解,前者主要分析源码,从简单的注解入手到最后的读取spring.facoties文件。后者主要举例RedisAutoConfiguration自动配置来说明spring boot对于相关的配置类bean的通过注解的灵活处理。

1、Spring Boot是如何发现自动配置的?

都知道Spring Boot程序入口处(xxxApplication.java)都会有 @SpringBootApplication 的注解。这个注解表明该程序是主程序入口,也是SpringBoot应用

@SpringBootApplication
public class DemoApplication {

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

}

 

查看 @SpringBootApplication 注解,不难发现是一个组合注解,包括了 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan 。换句话说这三个注解可以替代 @SpringBootApplication 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

 

其中注解  @EnableAutoConfiguration  就是实现SpringBoot自动配置的关键所在,值得注意的是@EnableXXXX注解并不是SpringBoot特有,在Spring 3.x中就已经引出,比如:@EnableWebMvc用来启用Spring MVC而不需要XML配置,@EnableTransactionManagement注释用来声明事务管理而不需要XML配置。如此可见,@EnableXXXX是用来开启某一个特定的功能,从而使用Java来配置,省去XML配置。在SpringBoot中自动配置的开启就是依靠注解  @EnableAutoConfiguration  ,继续查看注解接口 @EnableAutoConfiguration 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

 

其中关键是 @Import({AutoConfigurationImportSelector.class}) ,表示选择所有SpringBoot的自动配置。废话不多说,还得继续看该选择器源码,其中最主要的方法是 getAutoConfiguationEntry 方法,该方法的主要功能是:

获得自动配置---->删除重复自动配置----->删除排除掉的自动配置---->删除过滤掉的自动配置------>最终的自动配置

这里我们主要关注如何获取自动配置,即图中红圈部分,即 getCandidateConfigurations 方法,该方法通过SpringFactoresLoader.loadFactoryNames方法读取某个classpath下的文件获取所有的configurations

注意到: No auto configuration classes found in META-INF/spring.factories..... ,它应该是从META-INF/spring.factories文件中下读取configurations,我们再往下查看方法 SpringFactoresLoader.loadFactoryNames ,该方法果然是读取META-INF/spring.factories文件的,从中获取自动配置键值对。

 

最后,我们找到META-INF/spring.factories文件(位于spring-boot-autoconfigure下)

查看其内容:

...
# 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,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
...

 

 这时候才恍然大悟,原来如此。简单总结起来就是,当SpringBoot应用启动读取自动配置之后,从上到下的相关调用栈(文字简单描述)

  • @EnableAutoConfiguration开启启动配置功能
  • 通过@Import导入AutoConfigurationImportSelector选择器发现(注册)自动配置
  • getAutoConfigurationEntry方法获取并处理所有的自动配置
  • SpringFactoriesLoader.loadFactoryNames读取spring.factories文件并加载自动配置键值对。

 

 2、Spring Boot是如何灵活处理自动配置的?

 

  从spring.factories文件中我们选取RedisAutoConfiguration举例说明,至于为什么选这个呢?这是因为之前我有写过关于Spring Boot整合Redis的相关博文。所以好入手!

首先,还是一样进入RedisAutoConfiguration(Idea大法好,点击进入即可查看代码)

源码如下,主要关注以下几个注解:

1)@ConditionalOnClass在当前classpath下是否存在指定类,若是则将当前的配置注册到spring容器。可见其灵活性。相关的@ConditionalXXX注解是spring 4.x推出的灵活注册bean的注解,称之为“条件注解”。有如下一系列条件注解:

  • @ConditionalOnMissingBean: 当spring容器中不存在指定的bean时,才会注册该Bean。
  • @ConditionalOnMissingClass:当不存在指定的类时,才会注册该bean。
  • @ConditionalOnProperty:根据配置文件中某个属性来决定是否注册该Bean,相对于其它条件注解较为复杂。主要有以下两种情况应用:

  一种是@ConditionalOnProperty(prefix = “mysql”, name = “enable”, havingValue = “true”)表示以为mysql为前缀的mysql.enable属性如果为空或者不是true时不会注册指定Bean,只有mysql.enable属性为true时候才会注册该指定Bean

    一种是@ConditionalOnProperty(prefix = “mysql”, name = “enable”, havingValue = “true”, matchIfMissing = true)matchIfMissing表示如果没有以mysql为前缀的enable属性,则为true表示符合条件,可以注册该指定Bean,默认为false。

  • @ConditionalOnJava:是否是Java应用
  • @ConditionalOnWebApplication:是否是Web应用
  • @ConditionalOnExpression:根据表达式判断是否注册Bean

  ...........剩下的还有很多,在autoconfigure.condition包下...........

    

 

2)@EnableConfigurationProperties让 @ConfigurationProperties 注解的properties类生效并使用。如让RedisProperties生效并注册到Spring容器中,并且使用!

3)@ConditionalOnMissingBean当前Spring容器中没有该bean(name或者class指定),则注册该bean到spring容器。

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

 

 由此可见Spring Boot对于自动配置的灵活性,可以传递给我们一种信息,Spring Boot是如何灵活处理自动配置的?

往大了说,就是你可以选择约定使用大量默认配置简化开发过程,你也可以自定义开发过程中需要的自动配置。往细了说,就是通过各式各样的条件注解注册需要的Bean来实现灵活配置。

那么实现一个自动配置有哪些重要的环节呢?

继续往下看第二部分!

 

二、Spring Boot自动配置的重要组成部分

 

  上面只是对自动配置中几个重要的注解做了简单介绍,但是并没有介绍要开发一个简单的自动配置需要哪些环节(部分),同样地我们还是以RedisAutoConfiguration与RabbitAutoConfiguration为例,主要查看注解头:

RedisAutoConfiguration:

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})

RabbitAutoConfiguration:

@Configuration
@ConditionalOnClass({RabbitTemplate.class, Channel.class})
@EnableConfigurationProperties({RabbitProperties.class})
@Import({RabbitAnnotationDrivenConfiguration.class})

你会发现通常的一般的AutoConfiguration都有@Configuration,@ConditionalOnClass,@EnableConfigurationProperties,@Import 注解:

  • @Configuration:自然不必多说,表示是配置类,是必须存在的!
  • @ConditionalOnClass:表示该配置依赖于某些Class是否在ClassPath中,如果不存在那么这个配置类是毫无意义的。也可以说是该class在配置类中充当重要的角色,是必须存在的!。在后面的自定义spring boot starter中我们可以简单统称为服务类
  • @EnableConfigurationProperties:读取配置文件,需要让相关的Properties生效,每个自动配置都离不开properties属性,是必须存在的!
  • @Import:导入配置类中需要用到的bean,通常是一些配置类。表示此时的自动配置类需要基于一些配置类而实现自动配置功能。当然不是必须的,有些是没有这个注解的,是不需要基于某些配置类的!

那么,可以简单总结得到一个自动配置类主要有以下几部分组成(单纯是根据个人理解总结出来的,没有官方说明)

  • properties bean配置属性:用来读取spring配置文件中的属性,@EnableConfigurationProperties与@ConfigurationProperties结合使用,具体请看下一篇实践stater例子。
  • 该配置类依赖的一些Class,使用@ConditionalOnClass判断;
  • 该配置类依赖的一些配置Bean,使用@Import导入。
  • 可能还有加载顺序的控制,如@AutoConfigureAfter,@AutoConfigureOrder等
  • 一些Bean的加载,往往通过方法返回Object,加@Bean以及一些条件注解来实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值