SpringBoot入门(三)——入口类解析
本文来自网易云社区
上一篇介绍了起步依赖,这篇我们先来看下SpringBoot项目是如何启动的。
入口类
再次观察工程的Maven配置文件,可以看到工程的默认打包方式是jar格式的。
<packaging>jar</packaging>
SpringBoot默认的打包方式为jar,并且内嵌web容器。因此我们可以用运行jar包的方式启动一个web程序:
java -jar xxx.jar
linux服务器上可以用下面命令让服务常驻:
nohup java -jar xxx.jar &
我们知道jar包方式运行需要main方法,SpringBoot已为我们自动生成,这个类便是项目启动入口。
我的项目名是blog-demo,对应生成的main方法在BlogDemoApplication.java,其代码如下:
@SpringBootApplicationpublic class BlogDemoApplication { public static void main(String[] args) {
SpringApplication.run(BlogDemoApplication.class, args);
}
}
main方法中执行SpringApplication的静态方法run,并将当前类和启动参数传入。
静态方法中实例化一个SpringApplication,并调用实例的run方法:
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) { return new SpringApplication(primarySources).run(args);
}
先来看下调用的SpringApplication的构造方法:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null"); // 这里的primarySources就是我们传入的入口类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 推断应用类型
this.webApplicationType = deduceWebApplicationType(); // 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class)); // 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 很有意思的方法,通过异常栈获取应用入口类
this.mainApplicationClass = deduceMainApplicationClass();
}
注意我们传入的启动类被保存到了primarySources变量中,将作为后续context加载beans时的资源,其他细节不再展开。
接着看实例的run方法:
/**
* 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); // 创建上下文
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, 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, listeners, exceptionReporters, ex); throw new IllegalStateException(ex);
}
listeners.running(context); return context;
}
通过方法注释也可以看出来该run方法引发了一系列复杂的内部调用和加载过程,从而创建了一个SpringContext。
在prepareContext方法中会解析我们传入的入口类,解析其上的注解。下面来看下入口类上的注解。
@SpringBootApplication
入口类上的注解@SpringBootApplication是SpringBoot自动配置的关键。其定义如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {
...
}
说明它是@ComponentScan、@SpringBootConfiguration和@EnableAutoConfiguration三个注解的组合。
@ComponentScan
@ComponentScan是Spring框架原有的注解,在spring-context组件下,用来开启自动扫描Bean并解析注解注入。
可以用basePackages指定扫描的包,缺省情况下默认扫描被注解类所在的包。SpringBoot项目中一般会将入口类放在顶层目录,这样默认就会扫描整个项目。
@SpringBootConfiguration
@SpringBootConfiguration是SpringBoot新增的注解,在spring-boot组件下,定义如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration { }
相当于注解@Configuration,配备了该注解的类就能够以JavaConfig的方式完成一些配置,可以不再使用XML配置。
所以在入口类内也可以以JavaConfig的方式定义Bean。
@EnableAutoConfiguration
@EnableAutoConfiguration是SpringBoot新增的注解,在spring-boot-autoconfigurate组件下,它是SpringBoot开启自动配置的关键。放到下一节再讲。
小结
这一节简单解析了SpringBoot的入口类,一个由SpringBoot自动生成的java类,虽然只有短短几行代码,却引发了Spring上下文的创建的一系列事件。
首先SpringBoot将入口类传入作为资源的起点,当解析到入口类的时候发现其上的注解又开启了自动配置和包扫描,这样我们自定义的Bean就会被加载进去完成创建和依赖。
网易云新用户大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者金港生授权发布。
SpringBoot入门(三)——入口类解析的更多相关文章
- 尚硅谷springboot学习5-主入口类说明
package com.atguigu; import org.springframework.boot.SpringApplication; import org.springframework.b ...
- SpringBoot入门02-配置类
引入 Spring Boot的底层已经有了Spring MVC Spring Boot习惯优先的思想,很多配置都是可省的 不需要配置web.xml文件 不需要服务层的xml配置 不需要dao层的xml ...
- springboot 入门三- 读取配置信息二(读取属性文件方式)
在上篇文章中简单介绍自带读取方式.springboot提供多种方式来读取 一.@ConfigurationProperties(value="my") 支持更灵活的绑定及元数据的支 ...
- SpringBoot入门 (三) 日志配置
上一篇博文记录了再springboot项目中读取属性文件中配置的属性,本文学习在springboot项目中记录日志. 日志记录在项目中是很常见的一个功能了,对排查问题有很大帮助,也可以做分类分析及统计 ...
- SpringBoot入门(五)——自定义配置
本文来自网易云社区 大部分比萨店也提供某种形式的自动配置.你可以点荤比萨.素比萨.香辣意大利比萨,或者是自动配置比萨中的极品--至尊比萨.在下单时,你并没有指定具体的辅料,你所点的比萨种类决定了所用的 ...
- SpringBoot入门(四)——自动配置
本文来自网易云社区 SpringBoot之所以能够快速构建项目,得益于它的2个新特性,一个是起步依赖前面已经介绍过,另外一个则是自动配置.起步依赖用于降低项目依赖的复杂度,自动配置负责减少人工配置的工 ...
- SpringBoot入门(二)——起步依赖
本文来自网易云社区 在前一篇我们通过简单几步操作就生成了一个可以直接运行的Web程序,这是因为SpringBoot代替我们做了许多工作,概括来讲可以分为起步依赖和自动配置.这一篇先来看看起步依赖. 项 ...
- SpringBoot入门(一)——开箱即用
本文来自网易云社区 Spring Boot是什么 从根本上来讲Spring Boot就是一些库的集合,是一个基于"约定优于配置"的原则,快速搭建应用的框架.本质上依然Spring, ...
- SpringBoot入门学习看这一篇就够了
1.SpringBoot是什么? SpringBoot是一套基于Spring框架的微服务框架. 2.为什么需要SpringBoot 由于Spring是一个轻量级的企业开发框架,主要的功能就是用于整合和 ...
随机推荐
- U盘安装centos7.1出现dracut问题的超简单解决方法
恰好今天有空,于是抽空回忆一下之前U盘安装CENTOS7时遇到的一个大坑.U盘装系统习惯了,就顺手用大白菜工具刻了一个CentOS 7.1的minimun ISO镜像到U盘,于是噩梦开始了.如果有人像 ...
- python:while 语句的使用方法
while语句: count = 0 while True: print(count) count += 1 if count == 10: break 实例: 计算n!,若:n = 5:则:n! = ...
- Synchronized块同步变量的误区
我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特性的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...
- 文件 md5 查看 命令
Windows命令查看文件MD5 certutil -hashfile yourfilename.ext MD5 certutil -hashfile yourfilename.ext SHA1 ...
- 114. Flatten Binary Tree to Linked List (Stack, Tree; DFS)
Given a binary tree, flatten it to a linked list in-place. For example, Given 1 / \ 2 5 / \ \ 3 4 6 ...
- MAXOS 进程管理
ps -ef|grep +程序名 注意进程名区分大小写 linux上进程有5种状态:1. 运行(正在运行或在运行队列中等待)2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)3. 不可中 ...
- spring4-2-bean配置-4-bean之间的关系
- Bigtable:一个分布式的结构化数据存储系统
Bigtable:一个分布式的结构化数据存储系统 摘要 Bigtable是一个管理结构化数据的分布式存储系统,它被设计用来处理海量数据:分布在数千台通用服务器上的PB级的数据.Google的很多项目将 ...
- Java工具类之Apache的Commons Lang和BeanUtils
Apache Commons包估计是Java中使用最广发的工具包了,很多框架都依赖于这组工具包中的一部分,它提供了我们常用的一些编程需要,但是JDK没能提供的机能,最大化的减少重复代码的编写. htt ...
- [C++] NULL VS nullptr
NULL VS nullptr