springboot加载bean过程探索
springboot一般通过以下main方法来启动项目
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
查看源码发现加载的主要逻辑写在了
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//1.创建容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//2.把bean装载进容器context中去
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
} try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
下面重点讲"把bean装载进容器context中去"的这个方法prepareContext(context, environment, listeners, applicationArguments, printedBanner)的逻辑
方法的代码实现逻辑如下:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources 也就要加载的声明配置的类,这里是声明了@SpringBootApplication的DemoApplication
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//把声明了@SpringBootApplication的类加载进容器的具体实现
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
load方法的具体实现:
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
*/
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//这个BeanDefinationLoader的实现类为org.springframework.boot.BeanDefinitionLoader,为springboot自定义的一个beanDefination的加载器,专门用来加载配置声明的类的
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
//org.springframework.boot.BeanDefinitionLoader把beanDefination加载进spring的BeanDefinationRegistry中的方法
loader.load(); }
以下为org.springframework.boot.BeanDefinitionLoader的loan方法实现逻辑:
private int load(Class<?> source) {
if (isGroovyPresent()
&& GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
if (isComponent(source)) {
//通过org.springframework.context.annotation.AnnotatedBeanDefinitionReader.AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry)来注册注解扫描的类定义
this.annotatedReader.register(source);
return 1;
}
return 0;
}
org.springframework.context.annotation.AnnotatedBeanDefinitionReader的作用是啥呢?来看看
AnnotatedBeanDefinitionReader类的注释:
/**
* Convenient adapter for programmatic registration of annotated bean classes.
* This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
* the same resolution of annotations but for explicitly registered classes only.
*
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @author Phillip Webb
* @since 3.0
* @see AnnotationConfigApplicationContext#register
*/
public class AnnotatedBeanDefinitionReader
意思就是:
用于声明bean类的编程注册的方便的适配器,
这是ClassPathBeanDefinitionsCanner的替代方法,应用
声明类解析,但仅限于显式注册的类。
springboot加载bean过程探索的更多相关文章
- spring加载Bean的解析过程(二)
1.例如: BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring.xml")); User user ...
- spring加载bean流程解析
spring作为目前我们开发的基础框架,每天的开发工作基本和他形影不离,作为管理bean的最经典.优秀的框架,它的复杂程度往往令人望而却步.不过作为朝夕相处的框架,我们必须得明白一个问题就是sprin ...
- IoC 之加载 Bean:总结
上文中我们将bean已经加载到了IOC容器中,接下来我们将把IOC加载Bean出来进行代码解析 备注:(有些解释是参考别个博客的相关解释 )一起探讨请加我QQ:1051980588 bean 的初始化 ...
- Spring多种加载Bean方式简析
1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: <bean id="dictionaryRelMap" class="java.ut ...
- 【死磕 Spring】----- IOC 之 加载 Bean
原文出自:http://cmsblogs.com 先看一段熟悉的代码: ClassPathResource resource = new ClassPathResource("bean.xm ...
- sping加载bean都发生了些什么
问题描述:使用@Autowired注入的类,没有实例化 //Controller @RequestMapping(value="/deepblue") @Controller pu ...
- spring Boot加载bean
1.SpringBoot中加载bean,可以使用注解@compenent直接加载到applicationContext容器中 2.在直接类@Configuration中,手动注册bean,如:
- log4j的学习和log4j在程序中使用的加载作用过程
昨天进行代码评审的时候,大家都纠结在了日志信息应该如何输出上,其实我想大家应该一直都在使用log4j来对日志信息进行输出,但是未想应该有很大一部分人对log4j是不了解的,我遇到这个问题的时候也到网上 ...
- Springboot 加载配置文件源码分析
Springboot 加载配置文件源码分析 本文的分析是基于springboot 2.2.0.RELEASE. 本篇文章的相关源码位置:https://github.com/wbo112/blogde ...
随机推荐
- Vue访问权限
设置权限 <script> export default { created(){ if(this.$store.state.userStore.role !== 'manager'){ ...
- 【vue+axios】一个项目学会前端实现登录拦截
原文链接:github.com 一个项目学会vue全家桶+axios实现登录.拦截.登出功能,以及利用axios的http拦截器拦截请求和响应. 前言 该项目是利用了Github 提供的persona ...
- js小功能3:一个简单的计算器功能
html: <input type='text' id='txt1' /> <select id='select'> <option value='+'>+< ...
- mysql 触发器 if then elseif else 的运用
create procedure dbname.proc_getGrade (stu_no varchar(20),cour_no varchar(10)) BEGIN declare stu_gra ...
- centos7 php7.3
./configure --prefix=/root/php/php-7.3.10/output \ --with-mhash \ --with-openssl \ --with-mysqli=sha ...
- python异常:常见异常、处理、断言、自定义异常
一.异常是什么 二.常见异常 三.异常处理 四.不太常用语法 五.主动判处异常 六.断言 七.使用场景 八.自定义异常类型 一.异常是什么 """ 什么是异常? 异常是错 ...
- New!Devexpress WPF各版本支持VS和SQL Server版本对应图
点击获取DevExpress v19.2.3完整版试用下载 本文主要为大家介绍DevExpress WPF各大版本支持的VS版本和支持的.Net版本图,Devexpress WPF v19.2.3日前 ...
- JZOJ 5988 珂学计树题 (Burnside引理)
什么神题a-没学过Burnside引理a学了也做不来系列-考场没怎么看这题,上最后十分钟打了样例就溜了-然后这题爆0了. Here CODE #include <cctype> #incl ...
- Spring Boot 中初始化资源的几种方式(转)
假设有这么一个需求,要求在项目启动过程中,完成线程池的初始化,加密证书加载等功能,你会怎么做?如果没想好答案,请接着往下看.今天介绍几种在Spring Boot中进行资源初始化的方式,帮助大家解决和回 ...
- 如何获取到一个form中的所有子控件?
使用yield关键字,非常的方便 private static IEnumerable<Control> GetChildren(Control frmRootDock) { if (fr ...