Springboot 04 starter

如果创建新的 Springboot 项目,目录结构类似于下图。

目录规范来自构建工具 maven/gradle,而不是 Spring 框架。

图片来自《Springboot 实战第 4 版》

@SpringBootApplication 注解的类是应用程序启动类,实现两个功能:自动配置,启动引导。

@SpringBootApplication 注解由以下三个注解组成。

@EnableAutoConfiguration:启动自动配置。

@ComponentScan:启动组件扫描。

@SpringBootConfiguration:表示是配置类。

main 方法启动程序。

java 复制代码
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
       SpringApplication.run(MyApplication.class, args);
    }
}

起步依赖

Springboot starter 定义好组件和配置文件。用户引用依赖即可使用功能,无需管理依赖,无需担心版本,无需配置参数。比如 spring-boot-starter-web 依赖可以让用户快速搭建 web 服务。

xml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

spring-boot-starter-web 依赖包含 spring-boot-starter,spring-boot-starter 依赖 spring-boot-autoconfigure。正是 spring-boot-autoconfigure 实现自动配置。

spring-boot-autoconfigure

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中定义 Springboot 提供的自动配置类。文件每一行是一个自动配置类,类名后缀均是 AutoConfiguration。Springboot 程序启动时会尝试自动加载所有配置类 bean。

org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration自动配置类向 IOC 容器注册名为 dispatcherServlet 的 bean。

java 复制代码
package org.springframework.boot.autoconfigure.web.servlet;
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 最高优先级
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class) // 在 ServletWebServerFactoryAutoConfiguration 之后执行,确保环境就绪
@ConditionalOnWebApplication(type = Type.SERVLET) // 仅在应用是 servlet web 应用生效
@ConditionalOnClass(DispatcherServlet.class) // 要求 JVM 能够加载 DispatcherServlet 类,向容器注册 bean
public class DispatcherServletAutoConfiguration {
	@Configuration(proxyBeanMethods = false) // 配置类
	@Conditional(DefaultDispatcherServletCondition.class) // 确保不存在其他 dispatcherServlet 实例,避免重复注册
	@ConditionalOnClass(ServletRegistration.class) // 要求 JVM 能够加载 ServletRegistration 类,向容器注册 bean
	@EnableConfigurationProperties(WebMvcProperties.class) // 启动配置属性绑定,将配置文件中 spring.mvc 前缀的属性注入到 webMvcProperties 对象
	protected static class DispatcherServletConfiguration {
		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
			configureThrowExceptionIfNoHandlerFound(webMvcProperties, dispatcherServlet);
			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
			dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
			return dispatcherServlet;
		}
}

三方包 starter

mybatis-plus-boot-starter分享三方包 starter。starter 引入Springboot 的 spring-boot-autoconfigure 和 自己定义的 mybatis-plus-spring-boot-autoconfigure。

xml 复制代码
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-spring-boot-autoconfigure</artifactId>
      <version>3.5.4.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <scope>compile</scope>
    </dependency>

在 mybatis-plus-spring-boot-autoconfigure 包的META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports定义自动配置类。

复制代码
com.baomidou.mybatisplus.autoconfigure.MybatisPlusInnerInterceptorAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration

源码仓库。自动配置类向 IOC 容器注册名为 sqlSessionFactory 的 bean。

java 复制代码
@SuppressWarnings("ConstantConditions")
@org.springframework.context.annotation.Configuration // 配置类
@ConditionalOnClass({SqlSessionFactory.class, MybatisSqlSessionFactoryBean.class}) // 要求 JVM 能够加载 SqlSessionFactory MybatisSqlSessionFactoryBean 类
@ConditionalOnBean(DataSource.class) // 要求 IOC 容器包含 DataSource 类型的 bean
@EnableConfigurationProperties(MybatisPlusProperties.class) // 启动配置属性绑定,将配置文件中 mybatis-plus 前缀的属性注入到 MybatisPlusProperties 对象
@AutoConfigureAfter(DataSourceAutoConfiguration.class) // 在 DataSourceAutoConfiguration 之后执行,确保环境就绪
public class MybatisPlusAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }
        GlobalConfiguration globalConfig;
        if (!ObjectUtils.isEmpty(this.properties.getGlobalConfig())) {
            globalConfig = this.properties.getGlobalConfig().convertGlobalConfiguration();
        } else {
            globalConfig = new GlobalConfiguration();
        }
        MybatisConfiguration configuration = this.properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
            configuration = new MybatisConfiguration();
        }
        if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
            for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
                customizer.customize(configuration);
            }
        }
        factory.setConfiguration(configuration);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }
        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }
        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }
        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }
        // TODO 自定义枚举包
        if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) {
            factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage());
        }
        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }
        //注入填充器
        if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class, false,
            false).length > 0) {
            MetaObjectHandler metaObjectHandler = this.applicationContext.getBean(MetaObjectHandler.class);
            globalConfig.setMetaObjectHandler(metaObjectHandler);
        }
        //注入主键生成器
        if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false,
            false).length > 0) {
            IKeyGenerator keyGenerator = this.applicationContext.getBean(IKeyGenerator.class);
            globalConfig.setKeyGenerator(keyGenerator);
        }
        //注入sql注入器
        if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false,
            false).length > 0) {
            ISqlInjector iSqlInjector = this.applicationContext.getBean(ISqlInjector.class);
            globalConfig.setSqlInjector(iSqlInjector);
        }
        factory.setGlobalConfig(globalConfig);
        return factory.getObject();
    }
相关推荐
LZQqqqqo1 小时前
C# 中生成随机数的常用方法
java·算法·c#
葵续浅笑1 小时前
LeetCode - 合并两个有序链表 / 删除链表的倒数第 N 个结点
java·算法·leetcode
太阳伞下的阿呆5 小时前
本地环境vue与springboot联调
前端·vue.js·spring boot
无限大65 小时前
只出现一次的数字:从暴力美学到位运算神技的进化之路
后端·面试
宇寒风暖5 小时前
Flask 框架全面详解
笔记·后端·python·学习·flask·知识
seabirdssss5 小时前
错误: 找不到或无法加载主类 原因: java.lang.ClassNotFoundException
java·开发语言
你的人类朋友5 小时前
❤️‍🔥为了省内存选择sqlite,代价是什么
数据库·后端·sqlite
还是鼠鼠5 小时前
tlias智能学习辅助系统--SpringAOP-进阶-通知顺序
java·后端·mysql·spring·mybatis·springboot
飞翔的佩奇5 小时前
基于SpringBoot+MyBatis+MySQL+VUE实现的名城小区物业管理系统(附源码+数据库+毕业论文+开题报告+部署教程+配套软件)
数据库·vue.js·spring boot·mysql·毕业设计·mybatis·小区物业管理系统