关键词:
一、springBoot自动化配置原理
1. starter管理机制
通过依赖了解SpringBoot管理了哪些starter
- 通过依赖
spring-boot-dependencies
搜索starter-
发现非常多的官方starter,并且已经帮助我们管理好了版本。 - 项目中使用直接引入对应的
starter
即可,这个场景下需要的依赖就会自动导入到项目中,简化了繁琐的依赖。
所有的场景启动器都依赖于spring-boot-starter
例如druid:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.24</version>
<scope>compile</scope>
</dependency>
这个启动器本身没有代码,通过依赖,构建了springBoot的基础运行环境,
包括spring基础环境,自动化配置基本环境。
org\\springframework\\boot\\spring-boot-starter\\spring-boot-starter-2.5.0.pom 里面的默认依赖
自动化配置依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.5.0</version>
<scope>compile</scope>
</dependency>
spring的IOC容器
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.7</version>
<scope>compile</scope>
</dependency>
。。。。。等等
小结:
- 引入的官方starter依赖默认都可以不写版本
- 如果配置满足您当前开发需要,则默认配置即可
- 自定义的starter,需要引入spring-boot-starter
2. springmvc的自动化配置原理
以web MVC自动化配置原理为例,理解web MVC自动化配置加入了哪些依赖,做了哪些默认配置。
回忆一下:SpringMVC学习时候,我们在 SSM整合时,添加spring及spring web mvc相关依赖
springmvc.xml 配置文件配置了:
1. 扫描controller 所在包
2. 配置annotation-driven支持mvc功能(HandlerMapping, HandlerAdapter)
3. 视图解析器
4. 静态资源
5. 拦截器
6. ……
web.xml 配置:
1. 初始化spring容器
2. 初始化springmvc DispatcherServlet
3. post请求乱码过滤器
部署还需要单独的tomcat
-----------------------------------------------------
也就是说:我们现在需要在开发业务代码前,就必须要准备好这些环境,否则无法完成业务代码,
这就是我们现在的问题。
让这些问题成为过去,现在我们就探索一下SpringBoot是如何帮助我们完成强大而又简单自动化配置的。
以引入web启动器为列:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
小结: 有了SpringBoot以后,让开发人员重点关注业务本身,而不是环境上,提升了开发效率。
3. 底层原理之@Configuration
理解@Configuration的作用和新特性
@Configuration : 标注当前类是一个配置类,spring会加载改配置类
属性 proxyBeanMethods:
true: @Bean标注的方式创建 对象会使用代理方式创建,并且放到spring容器中,单例。
false: @Bean标注的方法执行调用来创建对象,不会进spring容器(多例)。
默认为true
步骤:
1.创建MyConfig配置类,提供方法创建对象,使用@Bean标注
2.创建User实体类,
3.通过spring容器获取配置类对象,调用方法获取对象。
代码演示:
package com.ahcfl.demo2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false) // 标注当前类是一个配置类,spring会加载改配置类,且不会进spring容器(多例模式)。
public class MyConfig
@Bean
public User user()
return new User();
package com.ahcfl.demo2.pojo;
public class User
public User()
System.out.println("对象被创建了");
package com.ahcfl.demo2;
import com.ahcfl.demo2.config.MyConfig;
import com.ahcfl.demo2.pojo.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Demo2Application
public static void main(String[] args)
ConfigurableApplicationContext ac = SpringApplication.run(Demo2Application.class, args);
MyConfig myConfig = ac.getBean(MyConfig.class);
User user = myConfig.user();
User user2 = myConfig.user();
System.out.println(user);
System.out.println(user2);
小结:不常用的bean设置为false,不加入IOC容器中,可以提升springBoot启动速度。
4. 底层原理之@Import
【1】@Import的基础用法
1.导入Bean,会自动执行当前类的构造方法创建对象,存到IOC容器, bean名称为:类的全路径
2.导入配置类,并且类中有 带有@Bean注解方法,创建对象存到IOC容器,bean名称为:默认方法名称
代码演示
package com.ahcfl.demo2;
import com.ahcfl.demo2.config.MyConfig;
import com.ahcfl.demo2.pojo.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import(User.class)
@Import(MyConfig.class)
public class Demo2Application
public static void main(String[] args)
ConfigurableApplicationContext ac = SpringApplication.run(Demo2Application.class, args);
User user = ac.getBean(User.class);
System.out.println(user);
【2】@Import另外两种实现
为讲解源码做铺垫
-
导入 ImportSelector 实现类。会调用接口的selectImports()方法来加载资源。
-
导入 ImportBeanDefinitionRegistrar 实现类,会调用接口的registerBeanDefination()
来向spring注册bean的信息。(将对象放到spring容器中)
5. 底层原理之@Conditional衍生条件装配
作用:条件装配,满足Conditional指定的条件,则进行组件注入,初始化Bean对象到IOC容器
package com.ahcfl.demo2.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig
@ConditionalOnMissingBean(Dog.class) //在没有dog类对象的情况下创建bean
//@ConditionalOnClass(Dog.class) //存在当前类的情况下创建bean
@Bean
public User user()
return new User();
小结:@ConditionalOnXXX 注解存在的意义是:满足条件当前类或者Bean才有效,按需导入。
6. 底层原理之@ConfigurationProperties配置绑定
在springBoot基础中有演示,用于配置文件的自动依赖注入。
7. 自动化配置原理@SpringBootApplication入口分析
理解SpringBoot自动化配置流程中@SpringBootApplication是一个组合注解,及每一个注解的作用
@SpringBootApplication组合注解
【1】@SpringBootConfiguration注解作用
-
@SpringBootConfiguration是对@Configuration注解的包装,
proxyBeanMethods 默认配置 true, full模式(单例模式创建Bean),反之,false为 多例模式
-
标识是一个配置类,所以 引导类也是配置类
【2】@ComponentScan注解作用
- 组件扫描,默认扫描的规则 ( 引导类所在的包及其子包所有带注解的类 )
问题:
- 在引导类中配置 @Bean 注解可以吗?
- 为什么Controller、service类添加完注解后,不需要添加扫描包?
【3】@EnableAutoConfiguration自动配置注解
理解@EnableAutoConfiguration自动化配置核心实现注解
@EnableAutoConfiguration也是一个组合注解
【1】@AutoConfigurationPackage
作用:利用Registrar给容器中导入一系列组件 ,将引导类的所有包及其子包的组件导入进来
点击 Registrar
进入到源码的 register
方法,添加 断点,测试
通过 debug 程序发现,默认情况下 将引导类的所有包及其子包的组件导入进来
【2】@Import(AutoConfigurationImportSelector.class)注解作用
作用:利用selectImports
方法中的 getAutoConfigurationEntry
方法给容器中批量导入工厂配置相关组件
- 调用
AutoConfigurationImportSelector
类中的selectImports
方法 - 调用
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)
获取到所有需要导入到容器中的配置类
- 利用工厂加载
Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)
得到所有的组件 - 从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
小结: 自动化配置默认加载的配置文件在哪?
META-INF/spring.factories
8. 自动化配置原理-按条件开启自动配置类和配置项
- 理解所有的自动化配置虽然会全部加载,但由于底层有大量的@ConditionalOnXXX注解进行判断,所以有很多自动配置类并不能完全开启
- 如果配置生效了,则会加载默认的属性配置类,实现默认的对应场景的自动化配置
以上通过 META-INF/spring.factories
配置文件找到所有的自动化配置类,但 是不是全部的生效的呢?很显然是不可能全部都生效的。
以webmvc自动化配置为例
问题: 这些不用的 starter 的依赖,能不能导入到我们工程里面? 为什么?
导入相关的starter 依赖,才会进行自动配置加载。不用的不必要导入,会降低springBoot启动速度。
9. 自动化配置原理-springBoot源码分析(理解)
理解整个SpringBoot启动的完成自动化配置及属性加载的全过程
【1】 启动类分析
package com.ahcfl;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.ahcfl.mapper")
public class WebApplication
public static void main(String[] args)
SpringApplication.run(WebApplication.class,args);
这里跟SpringBoot有关联的部分有两个,
一个是SpringApplication.run(WebApplication.class, args);
,
一个就是启动类上的注解:@SpringBootApplication
。
分别跟踪两部分内容。
【2】 springBoot启动过程
main函数中的SpringApplication.run(BankApplication.class, args);
就是项目的入口,
也是Spring加载的完整过程,我们从这里开始。
首先跟入run方法,流程如图:
因此,接下来要看的是两部分:
new SpringApplication(primarySources)
:构造函数初始化run(args)
:成员的run方法
[1] SpringApplication构造函数
我们把跟构造函数有关的几个变量和方法提取出来,方便查看:
// SpringApplication.java
/**
* 资源加载器,读取classpath下的文件
*/
private ResourceLoader resourceLoader;
/**
* SpringBoot核心配置类的集合,这里只有一个元素,是我们传入的主函数
*/
private Set<Class<?>> primarySources;
/**
* 当前项目的应用类型
*/
private WebApplicationType webApplicationType;
/**
* ApplicationContextInitializer 数组
*/
private List<ApplicationContextInitializer<?>> initializers;
/**
* ApplicationListener 数组
*/
private List<ApplicationListener<?>> listeners;
public SpringApplication(Class<?>... primarySources)
this(null, primarySources);
// 核心构造函数
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
// 1.记录资源加载器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 2.将传入的启动类装入集合
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 3.判断当前项目的类型,可以是SERVLET、REACTIVE、NONE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 4.初始化 initializers 数组
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 5.初始化 listeners 数组
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
分析说明:
-
ResourceLoader resourceLoader
:Spring中用来加载资源的加载器 -
Class<?>... primarySources
:这里是启动类,本例中就是WebApplication.class -
WebApplicationType.deduceFromClasspath()
:判断当前项目的类型,可以是SERVLET、REACTIVE、NONE,根据当前classpath中包含的class来判断,
影响后续创建的ApplicationContext的类型 【3】
-
getSpringFactoriesInstances(ApplicationContextInitializer.class)
:获取ApplicationContextInitializer类型的实现类对象数组 【4】 -
getSpringFactoriesInstances(ApplicationListener.class)
:获取ApplicationListener类型的实现类对象数组 【5】 -
deduceMainApplicationClass()
:没有实际用途,打印日志,输出当前启动类名称
我们只看难点部分,也就是步骤3、4、5
1)deduceFromClasspath()方法
判断项目类型:
static WebApplicationType deduceFromClasspath()
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null))
return WebApplicationType.REACTIVE;
for (String className : SERVLET_INDICATOR_CLASSES)
if (!ClassUtils.isPresent(className, null))
return WebApplicationType.NONE;
return WebApplicationType.SERVLET;
可以看到判断结果包含3种:
- REACTIVE:要求classpath中包含
org.springframework.web.reactive.DispatcherHandler
,这个是WebFlux中的核心处理器,我们并没有。 - SERVLET:要求classpath中包含
org.springframework.web.servlet.DispatcherServlet
,这是SpringMVC的核心控制器,在classpath中肯定可以找到 - NONE:以上都不满足,就是NONE
2)getSpringFactoriesInstances()方法
在构造函数中被调用了两次,分别加载ApplicationContextInitializer
和ApplicationListener
:
getSpringFactoriesInstances(Class<T> type)
方法的作用是获得指定接口的实现类的实例集合。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type)
// 调用下面的一个重载方法,参数type就是接口的类型
return getSpringFactoriesInstances(type, new Class<?>[] );
// 真正的处理逻辑
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args)
ClassLoader classLoader = getClassLoader();
// 1.先加载指定接口的实现类的名称集合
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 2.根据类的名称,创建实例对象
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 3.排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
这里关键是第1步中,调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)
方法,
是用来获取指定接口的实现类的名称字符串,而后就可以根据名称创建实例了。
例如我们传递的参数是:ApplicationContextInitializer.class
,那么获取的就是ApplicationContextInitializer
下面的实现类的名称字符串集合。
那么这里是如何根据接口找到对应的实现类名称呢?
3)loadFactoryNames加载类名称
那么loadFactoryNames是如何根据接口找到对应的实现类名称呢,继续跟入:
SpringFactoriesLoader.loadFactoryNames(type, classLoader)
方法:
// SpringFactoriesLoader
/**
* 使用指定的类加载器,加载@value #FACTORIES_RESOURCE_LOCATION中记录的,指定factoryClass
* 类型的实现类的全路径名。
* @param factoryClass 需要加载的接口或抽象类
* @param classLoader 用来加载资源的类加载器
*/
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader)
// 获取接口名称
String factoryClassName = factoryClass.getName();
// 从loadSpringFactories(classLoader)方法返回的是一个Map:key是接口名称字符串,值是实现类的名称集合
// 然后就可以调用map的get方法,根据factoryClass名称获取对应的实现类名称数组
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
注意到这里是先调用loadSpringFactories(classLoader)
方法,
此方法方法返回的是一个Map:key是接口名称字符串,值是实现类的名称集合。
那么,loadSpringFactories
方法是如何读取到这样的map呢?上面有截图分析这一部分,代码如下:
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)
// 尝试从缓存中获取结果
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null)
return result;
try
// 从默认路径加载资源文件,地址是:"META-INF/spring.factories"
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
// 创建空map
result = new LinkedMultiValueMap<>();
// 遍历资源路径
while (urls.hasMoreElements())
// 获取某个路径
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 加载文件内容,文件中是properties格式,key是接口名,value是实现类的名称以,隔开
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet())
// 获取key的 名称
String factoryClassName = ((String) entry.getKey()).trim();
// 将实现类字符串变成数组并遍历,然后添加到结果result中
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue()))
result.add(factoryClassName, factoryName.trim());
// 缓存中放一份,下次再加载可以从缓存中读取
cache.put(classLoader, result);
return result;
catch (IOException ex)
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
这个方法是利用ClassLoader
加载classpath下的所有的/META-INF/spring.factories
文件。
注意:所有jar包都会被扫描和查找。
例如,在spring-boot的jar包中,就有这样的文件
spring.factories内容类似这样:
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\\
org.springframework.boot.env.PropertiesPropertySourceLoader,\\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\\
org.springframework.boot.diagnostics.FailureAnalyzers
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\\
org.springframework.boot.ClearCachesApplicationListener,\\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\\
org.springframework.boot.context.FileEncodingApplicationListener,\\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\\
org.springframework.boot.context.config.ConfigFileApplicationListener,\\
org.springframework.boot.context.config.Delegatispringboot源码分析----springboot自动配置原理
自动配置原理1.SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration 2.@EnableAutoConfiguration功能的作用@AutoConfigurationPackage@Import({AutoConfigurationImportSelector.class})public@interfaceEnabl 查看详情
springboot编写自定义的starter
在之前的文章中,我们分析过SpringBoot内部的自动化配置原理和自动化配置注解开关原理。我们先简单分析一下mybatisstarter的编写,然后再编写自定义的starter。mybatis中的autoconfigure模块中使用了一个叫做MybatisAutoConfiguration的自动化... 查看详情
springboot高级原理分析--自定义redis-starter(代码片段)
01:SpringBoot高级原理分析–SpringBoot自动配置:Condition02:SpringBoot高级原理分析–切换内置web服务器03:SpringBoot高级原理分析–@Enable*注解、@Import注解04:SpringBoot高级原理分析–@Import注解05:SpringBoot高级原理分析–@EnableA... 查看详情
面试题:springboot的自启动原理
引言不论在工作中,亦或是求职面试,SpringBoot已经成为我们必知必会的技能项。除了比较老旧的政府项目或金融项目依旧使用如SSM或SSH做单体框架开发项目外,如今的各行各业基于项目的快速开发与发布、迭代更新,都在逐渐... 查看详情
springboot:自动配置源码底层原理分析(代码片段)
...自动配置原理配置文件到底能写什么?怎么写?SpringBoot官方文档中有大量的配置,我们无法全部记住,下面我们就梳理一下最核心的几个部分进行讲解。1.分析自动配置原理以HttpEncodingAutoConfiguration(Http编码... 查看详情
springboot2从入门到入坟|自动配置篇:源码分析之自动包规则原理
写在前面在前面几篇文章中,我给大家介绍了一些SpringBoot的底层注解。接下来,我们就要深入地了解一下SpringBoot的自动配置原理了,我们来看一下SpringBoot到底是怎么神不知鬼不觉的帮我们做了那么多事情的。有些同学可能会说... 查看详情
springboot自动装配定义与自定义starter原理,及如何实现自定义装配
前言SpringBoot自动装配定义与自定义starter,基于约定大于配置的原则,实现Spring组件自动装配的目的。 装配的依赖(方式) 模式注解、@Enable模块、条件装配、工厂加载机制。激活自动化装配、实现自动化装配、配置自动... 查看详情
springboot自动装配定义与自定义starter原理,及如何实现自定义装配
前言SpringBoot自动装配定义与自定义starter,基于约定大于配置的原则,实现Spring组件自动装配的目的。 装配的依赖(方式) 模式注解、@Enable模块、条件装配、工厂加载机制。激活自动化装配、实现自动化装配、配置自动... 查看详情
210630:springboot自动配置-自定义start
参考技术ASpringBoot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:当然,自动配置原理的相关描述,官方文档貌似是没有提及。不过我们不难猜出,SpringBoot的启动类上有一个@SpringBootApplication注解,这个注解是SpringBoot项目... 查看详情
springboot高级原理分析--@enableautoconfiguration注解(代码片段)
01:SpringBoot高级原理分析–SpringBoot自动配置:Condition02:SpringBoot高级原理分析–切换内置web服务器03:SpringBoot高级原理分析–@Enable*注解、@Import注解04:SpringBoot高级原理分析–@Import注解05:SpringBoot高级原理分析–@EnableA... 查看详情
原创001|搭上springboot自动注入源码分析专车
本系列为SpringBoot深度源码专车系列,第一篇发车!专车介绍该趟专车是开往SpringBoot自动注入原理源码分析的专车专车问题SpringBoot何时注入@Autowired标注的属性?如果注入类型的Bean存在多个SpringBoot是如何处理的?专车示例定义接... 查看详情
助力springboot自动配置的条件注解conditionalonxxx分析--springboo
注:该源码分析对应SpringBoot版本为2.1.0.RELEASE1前言本篇接如何分析SpringBoot源码模块及结构?--SpringBoot源码(二)上一篇分析了SpringBoot源码结构及各个模块pom之间的关系后,那么此篇开始就开始解开SpringBoot新特性之一--自动配置... 查看详情
springboot揭秘与实战源码分析-工作原理剖析
...tion4. 扩展阅读3.1. 核心注解3.2. 注入Bean结合《SpringBoot揭秘与实战源码分析-开箱即用,内藏玄机》一文,我们再来 查看详情
springboot入门到精通-springboot自动配置原理(代码片段)
SpringBoot源码解析SpringBoot入门到精通-Spring的注解编程(一)SpringBoot入门到精通-SpringBoot入门(二)SpringBoot入门到精通-Spring的基本使用(三)SpringBoot入门到精通-SpringBoot集成SSM(四)SpringBoot入门到精通-SpringBoot自动配置原理(五)SpringBoot入门... 查看详情
从源码中理解springboot自动装配原理
一、什么是自动装配SpringBoot定义了一套接口规范,这套规范规定:SpringBoot在启动时会扫描外部引用jar包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到Spring容器,并执行类中定义的各种操作。对于外部jar包来说,... 查看详情
springboot学习笔记——自动配置原理(代码片段)
前置知识:SpringBoot学习笔记——SpringBoot简介与HelloWordSpringBoot学习笔记——源码初步解析SpringBoot学习笔记——配置文件yaml学习SpringBoot学习笔记——JSR303数据校验与多环境切换自动配置原理配置文件到底能写什么?怎么写?Spring... 查看详情
自定义springbootstarter三部曲之三:源码分析spring.factories加载过程(代码片段)
欢迎访问我的GitHub本文是《自定义springbootstarter三部曲》系列的终篇,前文中我们开发了一个starter并做了验证,发现关键点在于spring.factories的自动加载能力,让应用只要依赖starter的jar包即可,今天我们来分析Spring和Springboot源码... 查看详情
springboot高级原理分析--@import注解(代码片段)
01:SpringBoot高级原理分析–SpringBoot自动配置:Condition02:SpringBoot高级原理分析–切换内置web服务器03:SpringBoot高级原理分析–@Enable*注解、@Import注解04:SpringBoot高级原理分析–@Import注解05:SpringBoot高级原理分析–@EnableA... 查看详情