)
目录一、EnableAutoConfiguration 核心入口源码解析1. 注解结构源码2. AutoConfigurationImportSelector 核心执行流程3. SpringFactoriesLoader SPI 加载源码4. 自动配置全执行流程图二、Spring Boot 条件注解底层源码解析1. 条件注解顶层设计2. ConditionalOnClass 源码解析3. ConditionalOnMissingBean 源码解析4. ConditionalOnProperty 源码解析5. 两阶段条件过滤总结三、MyBatis 自动配置源码实战解析1. 自动配置 SPI 入口2. MybatisAutoConfiguration 全类源码解析3. Mapper 扫描自动配置原理4. 属性绑定 MybatisProperties四、Spring Boot AOP 自动配置源码解析1. AopAutoConfiguration 自动配置类2. 自动开启原理五、Spring Boot Jar 包启动底层源码解析1. 可执行 Fat Jar 结构2. JarLauncher 启动流程源码3. 嵌套 Jar 加载原理4. 类加载机制的双亲委派适配六、面试速记总结一、EnableAutoConfiguration 核心入口源码解析自动配置的核心触发点就是EnableAutoConfiguration注解它被组合在SpringBootApplication中是所有自动配置类的总开关。1. 注解结构源码// org.springframework.boot.autoconfigure.EnableAutoConfiguration Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited AutoConfigurationPackage Import(AutoConfigurationImportSelector.class) public interface EnableAutoConfiguration { // 全局开关配置项配置spring.boot.enableautoconfigurationfalse可关闭所有自动配置 String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration; // 按类型排除指定自动配置类 Class?[] exclude() default {}; // 按全类名字符串排除指定自动配置类 String[] excludeName() default {}; }解析AutoConfigurationPackage将主启动类所在的包路径注册到容器中作为后续组件扫描、自动配置包扫描的根路径。Import(AutoConfigurationImportSelector.class)这是自动配置的核心通过 Spring 的ImportSelector机制批量向容器中导入所有自动配置类。exclude/excludeName提供手动排除能力用户可以关闭不需要的自动配置。2. AutoConfigurationImportSelector 核心执行流程selectImports()方法是 ImportSelector 的核心方法返回的字符串数组就是最终要导入到容器的配置类全限定名完整执行逻辑如下Override public String[] selectImports(AnnotationMetadata annotationMetadata) { // 1. 校验全局开关spring.boot.enableautoconfigurationfalse则直接返回空不加载任何自动配置 if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 2. 加载所有候选自动配置类 执行第一阶段条件过滤 AutoConfigurationEntry autoConfigurationEntry getAutoConfigurationEntry(annotationMetadata); // 3. 返回最终符合条件的配置类全限定名 return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }核心方法getAutoConfigurationEntry完整步骤protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 读取注解上的exclude属性获取用户指定排除的配置类 AnnotationAttributes attributes getAttributes(annotationMetadata); // 1. SPI加载从spring.factories读取所有EnableAutoConfiguration对应的配置类 ListString configurations getCandidateConfigurations(annotationMetadata, attributes); // 2. 去重移除重复的配置类 configurations removeDuplicates(configurations); // 3. 排除移除用户通过exclude/excludeName指定的配置类 SetString exclusions getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); // 4. 第一阶段过滤执行AutoConfigurationImportFilter按类存在性过滤 configurations getConfigurationClassFilter().filter(configurations); // 5. 发布自动配置导入事件 fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }3. SpringFactoriesLoader SPI 加载源码所有自动配置类的发现都依赖SpringFactoriesLoader这是 Spring Boot 扩展机制的底层基石。// org.springframework.core.io.support.SpringFactoriesLoader public static ListString loadFactoryNames(Class? factoryType, Nullable ClassLoader classLoader) { String factoryTypeName factoryType.getName(); // 从缓存中读取没有则扫描所有spring.factories文件 return loadSpringFactories(classLoader) .getOrDefault(factoryTypeName, Collections.emptyList()); } private static MapString, ListString loadSpringFactories(ClassLoader classLoader) { // 先查缓存避免重复扫描 MapString, ListString result cache.get(classLoader); if (result ! null) { return result; } result new HashMap(); try { // 扫描类路径下所有Jar包中的META-INF/spring.factories文件 EnumerationURL urls classLoader.getResources(FACTORIES_RESOURCE_LOCATION); while (urls.hasMoreElements()) { URL url urls.nextElement(); UrlResource resource new UrlResource(url); // 读取properties格式的配置文件 Properties properties PropertiesLoaderUtils.loadProperties(resource); // 按key分组value用逗号拆分多个实现类 for (Map.Entry?, ? entry : properties.entrySet()) { String factoryTypeName ((String) entry.getKey()).trim(); String[] factoryImplementationNames StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); for (String factoryImplementationName : factoryImplementationNames) { result.computeIfAbsent(factoryTypeName, key - new ArrayList()) .add(factoryImplementationName.trim()); } } } // 存入缓存整个应用生命周期只扫描一次 cache.put(classLoader, result); } catch (IOException ex) { throw new IllegalArgumentException(Unable to load factories from location [ FACTORIES_RESOURCE_LOCATION ], ex); } return result; }解析采用全局缓存机制类加载器维度缓存扫描结果应用启动过程中只扫描一次避免重复 IO。支持多 Jar 包扩展第三方 Starter 只需要在自己的 Jar 里放spring.factories文件就能被自动发现实现开箱即用。标准的 SPI 思想面向接口编程框架定义接口第三方提供实现完全解耦。4. 自动配置全执行流程图二、Spring Boot 条件注解底层源码解析条件注解是自动配置的「智能开关」保证只有符合环境的配置类才会生效避免无效 Bean 的创建。1. 条件注解顶层设计所有条件注解都基于 Spring 原生的Conditional元注解 Condition匹配接口Spring Boot 在此基础上做了大量业务封装。// Spring原生顶层条件接口 FunctionalInterface public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }Spring Boot 提供了抽象基类SpringBootCondition统一了日志输出、匹配记录、异常处理等通用逻辑所有内置条件注解都继承自它。2. ConditionalOnClass 源码解析作用类路径下存在指定的类时配置类才生效是自动配置中最常用的第一阶段过滤条件。// 注解定义 Target({ ElementType.TYPE, ElementType.METHOD }) Retention(RetentionPolicy.RUNTIME) Documented Conditional(OnClassCondition.class) public interface ConditionalOnClass { Class?[] value() default {}; String[] name() default {}; }核心匹配逻辑// OnClassCondition核心匹配方法 Override protected ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { // 读取注解中指定的类名 ListString onClasses getCandidates(metadata, ConditionalOnClass.class); if (onClasses null) { return ConditionOutcome.match(); } ListString missing new ArrayList(); for (String candidate : onClasses) { // 核心通过ClassUtils.isPresent判断类是否能被加载 if (!ClassUtils.isPresent(candidate, context.getClassLoader())) { missing.add(candidate); } } if (!missing.isEmpty()) { return ConditionOutcome.noMatch(required class not found: missing); } return ConditionOutcome.match(); }设计说明注解同时支持Class类型和String类型参数生产环境优先用字符串形式。如果直接写 Class 类型类不存在时编译就会报错用字符串可以安全地通过反射判断这是典型的编译期规避方案。属于第一阶段过滤条件在自动配置类被注册为 Bean 定义之前就执行不满足的类直接不会进入容器性能开销极低。3. ConditionalOnMissingBean 源码解析作用容器中不存在指定类型的 Bean 时才创建当前 Bean是「用户配置优先自动配置兜底」的核心实现。// OnBeanCondition核心匹配逻辑 private boolean hasBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanType) { // 遍历容器中所有Bean定义判断是否存在对应类型的Bean String[] beanNames beanFactory.getBeanNamesForType(BeanUtils.resolveClassName(beanType, null)); return beanNames.length 0; }源码踩坑与执行时机执行阶段属于第二阶段条件在所有 Bean 定义都注册完成后、Bean 实例化之前执行。顺序依赖判断结果强依赖配置类的加载顺序。如果自动配置类比用户自定义的 Bean 先加载判断时用户 Bean 还没注册会导致自动配置错误生效。解决方案Spring Boot 通过AutoConfigureAfter强制指定加载顺序比如数据源自动配置必须在连接池自动配置之后执行所有自动配置类都默认排在用户自定义 Bean 之后。4. ConditionalOnProperty 源码解析作用根据配置文件中的属性值决定是否生效常用于功能开关。Target({ ElementType.TYPE, ElementType.METHOD }) Retention(RetentionPolicy.RUNTIME) Documented Conditional(OnPropertyCondition.class) public interface ConditionalOnProperty { String[] value() default {}; // 配置项key String havingValue() default ; // 匹配的值 boolean matchIfMissing() default false; // 配置不存在时是否默认匹配 }核心逻辑从Environment中读取指定 key 的配置值与havingValue对比一致则匹配如果配置不存在按matchIfMissing的值决定是否通过。典型应用spring.aop.autotrue控制 AOP 自动配置matchIfMissingtrue表示默认开启。5. 两阶段条件过滤总结阶段代表注解执行时机作用第一阶段ConditionalOnClass、ConditionalOnWebApplication自动配置类导入前粗筛不满足的类直接不进入容器性能开销小第二阶段ConditionalOnMissingBean、ConditionalOnBeanBean 实例化前细筛基于容器中已有的 Bean 做判断保证用户配置优先三、MyBatis 自动配置源码实战解析MyBatis 的自动配置是学习自动设计思想的最佳实战完整覆盖了「SPI 注册 条件注解 属性绑定 Bean 生成」的全流程。1. 自动配置 SPI 入口MyBatis 官方 Starter 在mybatis-spring-boot-autoconfigure包的META-INF/spring.factories中注册了自动配置类org.springframework.boot.autoconfigure.EnableAutoConfiguration\ org.mybatis.spring.boot.autoconfigure.MybatisAutoConfigurationSpring Boot 启动时通过 SPI 扫描到这个配置类纳入自动配置管理。2. MybatisAutoConfiguration 全类源码解析Configuration // 条件1类路径下必须存在SqlSessionFactory、SqlSessionFactoryBean也就是引入了mybatis核心包 ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) // 条件2容器中必须有且只有一个DataSource Bean也就是数据源配置完成 ConditionalOnSingleCandidate(DataSource.class) // 绑定配置文件中mybatis开头的属性 EnableConfigurationProperties(MybatisProperties.class) // 加载顺序必须在数据源自动配置完成之后再执行 AutoConfigureAfter(DataSourceAutoConfiguration.class) public class MybatisAutoConfiguration { private final MybatisProperties properties; private final Interceptor[] interceptors; // 构造注入配置属性和插件 public MybatisAutoConfiguration(MybatisProperties properties, ObjectProviderInterceptor[] interceptorsProvider) { this.properties properties; this.interceptors interceptorsProvider.getIfAvailable(); } // 创建SqlSessionFactorySpring整合MyBatis的核心对象 Bean ConditionalOnMissingBean // 容器没有SqlSessionFactory时才创建用户自定义优先 public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory new SqlSessionFactoryBean(); factory.setDataSource(dataSource); // 读取配置文件中的mapper-locations Resource[] mapperLocations this.properties.resolveMapperLocations(); if (mapperLocations ! null mapperLocations.length 0) { factory.setMapperLocations(mapperLocations); } // 读取type-aliases-package配置 if (StringUtils.hasText(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } // 注册分页等插件 if (this.interceptors ! null this.interceptors.length 0) { factory.setPlugins(this.interceptors); } return factory.getObject(); } // 创建SqlSessionTemplate线程安全的SqlSession实现 Bean ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ExecutorType executorType this.properties.getExecutorType(); if (executorType ! null) { return new SqlSessionTemplate(sqlSessionFactory, executorType); } return new SqlSessionTemplate(sqlSessionFactory); } }解析类上的 4 个注解共同构成生效条件引入了 MyBatis 依赖 数据源已就绪 绑定配置 顺序控制。EnableConfigurationProperties将application.yml中的配置注入到MybatisProperties对象中实现配置与代码的分离。两个Bean方法都加了ConditionalOnMissingBean用户如果自己定义了 SqlSessionFactory自动配置的就会失效完全遵循用户优先的原则。3. Mapper 扫描自动配置原理MapperScan注解负责扫描 Mapper 接口并注册为 Bean底层通过MapperScannerConfigurer实现Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) Documented Import(MapperScannerRegistrar.class) Repeatable(MapperScans.class) public interface MapperScan { String[] value() default {}; // 扫描包路径 }MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口在 Bean 定义注册阶段扫描指定包下的接口为每个 Mapper 接口生成动态代理 Bean注册到容器中。4. 属性绑定 MybatisPropertiesConfigurationProperties(prefix MybatisProperties.MYBATIS_PREFIX) public class MybatisProperties { public static final String MYBATIS_PREFIX mybatis; private String configLocation; private String[] mapperLocations; private String typeAliasesPackage; private ExecutorType executorType; // getter/setter省略 }对应application.yml中的配置mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.entity configuration: map-underscore-to-camel-case: trueConfigurationProperties的底层原理是通过ConfigurationPropertiesBindingPostProcessor这个 Bean 后置处理器从 Environment 中读取对应前缀的配置通过反射 setter 方法注入到 JavaBean 中。四、Spring Boot AOP 自动配置源码解析Spring Boot 对 AOP 做了开箱即用的封装无需手动添加EnableAspectJAutoProxy注解引入依赖即可生效。1. AopAutoConfiguration 自动配置类Configuration // 条件1类路径存在AspectJ相关类也就是引入了spring-boot-starter-aop ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class }) // 条件2配置spring.aop.autotrue默认缺省时也匹配默认开启 ConditionalOnProperty(prefix spring.aop, name auto, havingValue true, matchIfMissing true) public class AopAutoConfiguration { // 分支1CGLIB代理模式spring.aop.proxy-target-classtrue时生效默认 Configuration(proxyBeanMethods false) ConditionalOnProperty(prefix spring.aop, name proxy-target-class, havingValue true, matchIfMissing true) static class CglibAutoProxyConfiguration { Bean public static BeanFactoryPostProcessor aopConfigurer() { return beanFactory - { // 注册自动代理创建器开启CGLIB代理 AopConfigUtils.registerAutoProxyCreatorIfNecessary(beanFactory); AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(beanFactory); }; } } // 分支2JDK动态代理模式配置为false时生效 Configuration(proxyBeanMethods false) ConditionalOnProperty(prefix spring.aop, name proxy-target-class, havingValue false) static class JdkDynamicAutoProxyConfiguration { Bean public static BeanFactoryPostProcessor aopConfigurer() { return beanFactory - { AopConfigUtils.registerAutoProxyCreatorIfNecessary(beanFactory); AopConfigUtils.forceAutoProxyCreatorToUseInterfaceProxying(beanFactory); }; } } }解析采用嵌套配置类 条件注解的方式实现了两种代理模式的无缝切换默认使用 CGLIB 代理。matchIfMissing true是默认生效的关键用户不配置时就走默认值体现约定大于配置的思想。最终通过AopConfigUtils向容器中注册AnnotationAwareAspectJAutoProxyCreator这是 Spring AOP 的核心后置处理器负责扫描切面、生成动态代理对象。2. 自动开启原理原生 Spring 中需要手动加EnableAspectJAutoProxy才能开启 AOPSpring Boot 自动配置做了两件事替代了这个注解自动注册了AnnotationAwareAspectJAutoProxyCreator这个 Bean 后置处理器和注解的作用完全一致。通过配置项控制代理目标类模式替代了注解的proxyTargetClass属性。五、Spring Boot Jar 包启动底层源码解析Spring Boot 可以通过java -jar xxx.jar直接启动本质是自定义了类加载器解决了 JDK 原生不支持嵌套 Jar 加载的问题。1. 可执行 Fat Jar 结构Spring Boot 打包生成的 Jar 包叫可执行 JarFat Jar内部结构和普通 Jar 完全不同MANIFEST.MF核心配置Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.example.DemoApplicationMain-ClassJVM 执行java -jar时的入口类是 Spring Boot 自定义的JarLauncher。Start-Class我们业务代码的主启动类由 JarLauncher 负责加载启动。2. JarLauncher 启动流程源码JarLauncher是启动入口核心职责是创建自定义类加载器加载嵌套 Jar 中的类然后调用业务主类的 main 方法。// org.springframework.boot.loader.JarLauncher public class JarLauncher extends ExecutableArchiveLauncher { public static void main(String[] args) throws Exception { // 启动入口创建JarLauncher实例并执行launch方法 new JarLauncher().launch(args); } protected void launch(String[] args) throws Exception { // 1. 注册自定义URL协议处理器支持嵌套Jar的URL解析 JarFile.registerUrlProtocolHandler(); // 2. 创建自定义类加载器LaunchedURLClassLoader加载BOOT-INF下的所有类和Jar ClassLoader classLoader createClassLoader(getClassPathArchives()); // 3. 获取Start-Class调用其main方法启动Spring Boot应用 launch(args, getMainClass(), classLoader); } }3. 嵌套 Jar 加载原理JDK 原生的URLClassLoader只能加载 Jar 包中的 class 文件不能加载 Jar 包里面嵌套的 Jar 文件。Spring Boot 的解决方案自定义 JarFile 实现重写了 Jar 的解析逻辑支持读取 Jar 内部的 Jar 条目把嵌套 Jar 也当成可读取的资源。自定义 URLStreamHandler注册了自定义的jar:协议处理器能够解析jar:file:/xxx.jar!/BOOT-INF/lib/yyy.jar格式的嵌套 Jar URL。自定义类加载器 LaunchedURLClassLoader继承自 URLClassLoader把所有嵌套 Jar 的 URL 都加入类路径重写类加载逻辑优先加载应用内的类。4. 类加载机制的双亲委派适配LaunchedURLClassLoader遵循双亲委派模型但做了针对性优化优先从当前类加载器应用类加载器加载业务类和依赖包避免和系统类加载器的依赖冲突。BOOT-INF/classes优先级高于BOOT-INF/lib保证业务类优先于依赖类加载。核心系统类如java.lang.*依然委派给启动类加载器保证 JDK 核心类的安全。六、面试速记总结自动配置入口EnableAutoConfiguration通过Import导入AutoConfigurationImportSelector借助SpringFactoriesLoaderSPI 扫描所有spring.factories中的自动配置类。条件两阶段过滤第一阶段ConditionalOnClass类存在性粗筛第二阶段ConditionalOnMissingBeanBean 存在性细筛用户配置优先自动配置兜底。MyBatis 自动配置SPI 注册配置类 → 数据源就绪后生效 → 读取配置属性 → 创建 SqlSessionFactory、SqlSessionTemplate → Mapper 扫描生成代理 Bean。AOP 自动配置引入依赖默认生效嵌套配置类实现 CGLIB/JDK 代理切换自动注册 AOP 核心后置处理器替代手动加注解。Jar 启动原理JarLauncher作为 JVM 入口自定义类加载器解决嵌套 Jar 加载问题最终调用业务主类的 main 方法启动 Spring 容器。最后学习源码的终极目的不是记住代码而是吸收 Spring 团队的架构设计思想这些方法论可以直接复用到自己的系统设计中。掌握原理把通用能力下沉成开箱即用的依赖培养底层问题排查、架构设计与技术选型的能力。