
一、自动配置在传统 Spring时代你要用数据库得自己写一堆配置DataSource、JdbcTemplate、事务管理器……要用 MVC也得自己配置视图解析器、消息转换器……每个常用组件都要写大量Bean或 XML麻烦又容易出错。Spring Boot 的目标自动帮你把常用组件配好只要你在项目里引入对应的起步依赖starter就几乎可以开箱即用起步依赖中的bean对象会自动注入到IOC容器中。我们现在注入第三方bean的方式不是自动配置。二、自动配置-源码分析2-1、SpringBootApplication你平常写的启动类就是这样标注的SpringBootApplication public class DemoApp { … }它其实是一个组合注解里面包含SpringBootConfiguration相当于ConfigurationComponentScan包扫描EnableAutoConfiguration← 自动配置的关键2-2、EnableAutoConfiguration打开自动配置开关。内部用了Import(AutoConfigurationImportSelector.class)这句的意思交给AutoConfigurationImportSelector来决定要导入哪些配置类。2-3、AutoConfigurationImportSelector它实现了ImportSelector接口里面有一个selectImports()方法String[] selectImports(…)这个方法会去扫描META-INF/spring.factories或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports这些文件在spring-boot-autoconfigure这个 jar 包里。里面列出了大量自动配置类例如org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration …2-4、自动配置类每个自动配置类本质上就是一个普通的Configuration例如AutoConfiguration ConditionalOnClass(DispatcherServlet.class) public class DispatcherServletAutoConfiguration { Bean public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); } }它们一般都加了各种条件注解 ConditionalConditionalOnClassclasspath 有这个类才加载ConditionalOnMissingBean容器里没同类 Bean 才创建默认的ConditionalOnProperty看配置文件开关2-5、流程串起来应用启动→ 执行SpringBootApplicationEnableAutoConfiguration生效 → 调用AutoConfigurationImportSelector.selectImports()读取spring.factories/.imports文件 → 找到所有自动配置类按条件注解筛选有类、有依赖、没被用户覆盖、配置开关打开…注册满足条件的 Bean如 DispatcherServlet、数据源、MVC 相关组件…2-6、通俗总结Spring Boot 的自动配置就是启动时去jar 包里的配置文件里找所有可能的配置类然后根据条件注解判断要不要加载满足条件的就自动注册 Bean如 Web 容器、数据源、MVC 组件…。你不用手写样板配置Boot 帮你搞定如果不想用或要自定义直接写自己的 Bean 或关掉开关即可。三、自己封装一个Spring Boot Starter的基本套路这张图演示的是把第三方 jarcommon-pojo里的类做成 Spring Boot 自动配置然后在业务项目里“零配置”使用的完整流程。可以按步骤看①CommonConfig—— 普通的配置类Configuration public class CommonConfig { ConditionalOnProperty(prefix country, name {name,system}) Bean public Country country(Value(${country.name}) String name, Value(${country.system}) String system) { return new Country(name, system); } Bean public Province province() { return new Province(); } }作用把Country、Province这两个第三方类注册成 Spring Bean。ConditionalOnProperty只有当配置文件里有country.name和country.system时才创建Country。Bean返回实例交给 IoC 容器管理。如果只是单独项目使用可以直接Import(CommonConfig.class)但如果想封装成starter还需要后面的步骤。②CommonAutoConfig—— 自动配置类AutoConfiguration Import(CommonConfig.class) public class CommonAutoConfig {}用AutoConfiguration或老版本的Configuration 条件注解声明这是一个自动配置类。Import(CommonConfig.class)把真正声明 Bean 的CommonConfig引入。关键点用户项目不用自己Import(CommonConfig.class)而是通过自动配置机制自动加载。③/④ 注册到spring.factories或.imports在common-pojo-1.0-SNAPSHOT.jar的resources/META-INF/spring/下老版本Spring Boot 2.xspring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration\ cn.itcast.config.CommonAutoConfig新版本3.x 推荐org.springframework.boot.autoconfigure.AutoConfiguration.imports cn.itcast.config.CommonAutoConfig作用告诉 Spring Boot“当有人引入我的 jar 时把CommonAutoConfig作为自动配置类。”业务项目右边SpringBootApplication public class SpringbootRegistApplication { }用户项目什么都不用写只要引入了common-pojo这个依赖并在application.yml配好country.name、country.system。Spring Boot 启动时会扫描到 jar 包里的AutoConfiguration.imports。把CommonAutoConfig加入。CommonAutoConfig又Import了CommonConfig。满足条件注解后自动创建Country、ProvinceBean。 总结流程写一个配置类CommonConfig里面Bean注册需要的对象配合条件注解。写一个自动配置入口CommonAutoConfigAutoConfigurationImport(CommonConfig)。在 jar 包的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports写入CommonAutoConfig的全类名。用户只要引入这个 jar 在配置文件里写参数Spring Boot 会自动帮他装配好 Bean无需在业务代码手动Import或Bean。这就是自己封装一个Spring Boot Starter的基本套路。①②写配置类③④注册到spring.factories/.imports业务项目直接用SpringBootApplication即“开箱即用”。项目简单只有一个配置类 ↓ 直接 AutoConfiguration imports 文件 ↓ 不需要 Import不需要第二层包装 项目复杂配置要拆成多个类 ↓ 写一个 AutoConfiguration 主入口 ↓ 主入口用 Import 导入多个 Configuration 子配置 ↓ imports 文件里只写主入口约定俗成的分工是AutoConfiguration→ 只给真正的自动配置入口用必须出现在imports文件里Configuration→给被Import导入的辅助配置类用示例拆分成多个类复杂场景当你的 starter 要配置的东西很多数据源、缓存、Web、安全……全写在一个类里会很长。这时候需要拆分。但imports文件里如果写一堆类会变得很乱// 这样写太散了不好维护 com.example.CommonDataSourceConfig com.example.CommonCacheConfig com.example.CommonWebConfig com.example.CommonSecurityConfig所以常见的做法是Step 1写一个主入口类只负责组装AutoConfiguration AutoConfigureAfter(DataSourceAutoConfiguration.class) Import({CommonDataSourceConfig.class, CommonCacheConfig.class, CommonWebConfig.class}) public class CommonAutoConfiguration { // 这个类可以什么都不做就是个总开关 }Step 2把具体配置拆成普通Configuration类Configuration(proxyBeanMethods false) public class CommonDataSourceConfig { Bean public DataSource commonDataSource() { ... } } Configuration(proxyBeanMethods false) public class CommonCacheConfig { Bean public CacheManager commonCacheManager() { ... } }Step 3imports文件里只写主入口com.example.autoconfigure.CommonAutoConfiguration四、小结五、自定义starter示例步骤一快速创建两个mavne工程步骤二配置dmybatis-spring-boot-atutoconfigure工程的pom.xml文件添加依赖。仿照以上的依赖进行添加。步骤三编写自动配置类// 标识当前类是一个自动配置类 AutoConfiguration public class MybatisAutoConfig { // 注入SqlSessionFactoryBean Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean sqlSessionFactoryBean new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; } // 注入MapperScannerConfigure Bean public MapperScannerConfigurer mapperScannerConfigurer(BeanFactory beanFactory){ MapperScannerConfigurer mapperScannerConfigurer new MapperScannerConfigurer(); // 扫描的包启动类所在的包及其子包 ListString packages AutoConfigurationPackages.get(beanFactory); String p packages.get(0); mapperScannerConfigurer.setBasePackage(p); // 扫描的注解 mapperScannerConfigurer.setAnnotationClass(Mapper.class); return mapperScannerConfigurer; } }步骤四声明自动配置类的全类名目的让这个自定义的自动配置类被springboot读取到。4-1、创建.import配置文件配置文件名可以直接从添加的依赖中获取在dmybatis-spring-boot-atutoconfigure工程中创建相同路径的文件。4-2、在配置文件中添加自动配置类的全类名步骤五dmybatis-spring-boot-starter模块添加依赖管理!-- 引入自动配置模块对应的依赖 -- dependency groupIdorg.example/groupId artifactIddmybatis-spring-boot-autoconfigure/artifactId version1.0-SNAPSHOT/version /dependency !-- 将自动配置模块中的所有依赖也引入 -- !-- 目的方便以后排除添加新的版本的依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId version3.1.2/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId version3.1.2/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.19/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version3.0.4/version /dependency步骤六删除多余的pakages步骤七将项目中的mybatis-spring-boot-starter替换为自定义的starter其余代码均不变