学习第三篇:【SpringBoot-Labs】芋道 Spring Boot 自动配置原理

本周(8.21-8.27)将学习芋道 Spring Boot的以下文章:
8.21: 快速入门
8.22:Spring Boot 自动配置原理 、Jar 启动原理
8.23:调试环境、 热部署入门、消除冗余代码 Lombok 入门
8.24:对象转换 MapStruct 入门、SpringMVC 入门
8.25: WebFlux 入门、 分布式 Session 入门
8.26:API 接口文档 Swagger 入门、API 接口文档 Swagger Starter 入门
8.27:参数校验 Validation 入门、WebSocket 入门

芋道 Spring Boot 自动配置原理

  • 在 Spring3.0 开始,Spring 提供了 JavaConfig 的方式,允许我们使用 Java 代码的方式,进行 Spring Bean 的创建。

  • 通过在上添加 @Configuration 注解,声明这是一个 Spring 配置类。

  • 通过在方法上添加 @Bean 注解,声明该方法创建一个 Spring Bean。

  • 通过 @Configuration 注解的配置类,可以解决“创建哪些 Bean”的问题

  • @ConditionalOnWebApplication 条件注解,表示当前配置类需要在当前项目是 Web 项目的条件下,才能生效。

  • @ConditionalOnClass 条件注解,表示当前配置类需要在当前项目有指定类的条件下,才能生效。例如:@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })

  • 在 Spring Boot 定义了 @ConfigurationProperties 注解,用于声明配置属性类,将指定前缀的配置项批量注入到该类中。例如 : @EnableConfigurationProperties(ServerProperties.class)

  • 通过 SpringApplication#run(Class primarySource, String... args) 方法,启动 Spring Boot 应用的时候,有个非常重要的组件 SpringFactoriesLoader 类,会读取 META-INF 目录下的 spring.factories 文件,获得每个框架定义的需要自动配置的配置类

  • 如此,原先 @Configuration 注解的配置类,就升级成类自动配置类。这样,Spring Boot 在获取到需要自动配置的配置类后,就可以自动创建相应的 Bean,完成自动配置的功能。

  • 实际上,自动配置只是 Spring Boot 基于 spring.factories 的一个拓展点 EnableAutoConfiguration。我们从上图中,还可以看到如下的拓展点:

    • ApplicationContextInitializer
    • ApplicationListener
    • AutoConfigurationImportListener
    • AutoConfigurationImportFilter
    • FailureAnalyzer
    • TemplateAvailabilityProvider
  • 条件注解并不是 Spring Boot 所独有,而是在 Spring3.1 版本时,为了满足不同环境注册不同的 Bean ,引入了 @Profile 注解。

    @Configuration
    public class DataSourceConfiguration {
    
        @Bean
        @Profile("DEV")
        public DataSource devDataSource() {
            // ... 单机 MySQL
        }
    
        @Bean
        @Profile("PROD")
        public DataSource prodDataSource() {
            // ... 集群 MySQL
        }
        
    }	
    
  • 在 Spring4 版本时,提供了 @Conditional 注解,用于声明在配置类或者创建 Bean 的方法上,表示需要满足指定条件才能生效。示例代码如下:

    @Configuration
    public class TestConfiguration {
    
        @Bean
        @Conditional(XXXCondition.class)
        public Object xxxObject() {
            return new Object();
        }
        
    }
    
    • 其中,XXXCondition 需要我们自己实现 Condition 接口,提供具体的条件实现。
  • 显然,Spring4 提交的 @Conditional 注解非常不方便,需要开发人员自己去拓展。因此,Spring Boot 进一步增强,提供了常用的条件注解:

    • @ConditionalOnBean:当容器里有指定 Bean 的条件下
    • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
    • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
    • @ConditionalOnClass:当类路径下有指定类的条件下
    • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
    • @ConditionalOnProperty:指定的属性是否有指定的值
    • @ConditionalOnResource:类路径是否有指定的值
    • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
    • @ConditionalOnJava:基于 Java 版本作为判断条件
    • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
    • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
    • @ConditionalOnWebApplication:当前项目是 Web项 目的条件下
  • Spring Boot 约定读取 application.yamlapplication.properties 等配置文件,从而实现创建 Bean 的自定义属性配置,甚至可以搭配 @ConditionalOnProperty 注解来取消 Bean 的创建。

  • 在使用 Spring Boot 时,并不会直接引入 spring-boot-autoconfigure 依赖,而是使用 Spring Boot 内置提供的 Starter 依赖。因为 Spring Boot 提供的自动配置类,基本都有 @ConditionalOnClass 条件注解,判断我们项目中存在指定的类,才会创建对应的 Bean。而拥有指定类的前提,一般是需要我们引入对应框架的依赖。

  • Spring Boot 内置了非常多的 Starter,方便我们引入不同框架,并实现自动配置。所以在引入一个starter后,可能会自动配置上其他的stater

  • 在一些场景下,我们需要自己实现自定义 Starter 来达到自动配置的目的。例如说:

    • 三方框架并没有提供 Starter,比如说 SwaggerXXL-JOB 等。
    • Spring Boot 内置的 Starter 无法满足自己的需求,比如说 spring-boot-starter-jdbc 不提供多数据源的配置。
    • 随着项目越来越大,想要提供适合自己团队的 Starter 来方便配置项目,比如说永辉彩食鲜 csx-bsf-all 项目。
  • Spring Boot Starter 的命名规则

    场景命名规则示例
    Spring Boot 内置 Starterspring-boot-starter-{框架}spring-boot-starter-web
    框架 自定义 Starter{框架}-spring-boot-startermybatis-spring-boot-starter
    公司 自定义 Starter{公司}-spring-boot-starter-{框架}zt-spring-boot-starter-test
  • Spring 的核心之一是 IOC,负责管理 Bean 的生命周期。而 Spring Boot 则是对 Java 应用的生命周期的管理。

  • 在 Spring 的年代,我们都是使用 Tomcat 外部容器来实现 Java 应用的运行,Spring 只是其中的一个组件。

  • 在 Spring Boot 的年代,我们使用 Spring Boot 来管理 Java 应用的运行,内嵌的 Tomcat 反而成为其中的一个组件。

总结

springboot的自动配置的原理,依赖于一下几点:

  • 上添加 @Configuration 注解,声明为配置类
  • 方法上添加 @Bean 注解,声明该方法创建一个 Spring Bean
  • 类上添加@EnableConfigurationProperties(YunaiServerProperties.class)使对YunaiServerProperties定义的属性能在yml文件中使用
  • @ConditionalOnClass(HttpServer.class) 表示当类路径下有指定类的条件下,才进行装配,类似于由前提,避免运行时产生ClassNotFound

一个自定义的配置类的自动配置的代码设计如下:

@Configuration // 声明配置类
@EnableConfigurationProperties(YunaiServerProperties.class) // 使 YunaiServerProperties 配置属性类生效
public class YunaiServerAutoConfiguration {

    private Logger logger = LoggerFactory.getLogger(YunaiServerAutoConfiguration.class);

    @Bean // 声明创建 Bean
    @ConditionalOnClass(HttpServer.class) // 需要项目中存在 com.sun.net.httpserver.HttpServer 类。该类为 JDK 自带,所以一定成立。
    public HttpServer httpServer(YunaiServerProperties serverProperties) throws IOException {
        // 创建 HttpServer 对象,并启动
        HttpServer server = HttpServer.create(new InetSocketAddress(serverProperties.getPort()), 0);
        server.start();
        logger.info("[httpServer][启动服务器成功,端口为:{}]", serverProperties.getPort());

        // 返回
        return server;
    }

}

YunaiServerProperties对象如下:

@ConfigurationProperties(prefix = "yunai.server")
public class YunaiServerProperties {

    /**
     * 默认端口
     */
    private static final Integer DEFAULT_PORT = 8000;

    /**
     * 端口
     */
    private Integer port = DEFAULT_PORT;

    public static Integer getDefaultPort() {
        return DEFAULT_PORT;
    }

    public Integer getPort() {
        return port;
    }

    public YunaiServerProperties setPort(Integer port) {
        this.port = port;
        return this;
    }

}

使用时仅需在application.yml中使用YunaiServerProperties中定义的属性即可:

yunai:
	server:
		port: 8888
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值