SpringBoot源码解读与原理分析(入门)
简介:
- 由Pivotal团队提供的全新框架
- 其设计目的是用来简化新Spring应用的初始搭建以及开发过程
- 使用了特定的方式来进行配置
- 快速应用开发领域
运行原理以及特点
特点:
- 可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
- 内嵌Tomcat或Jetty等Servlet容器;
- 提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
- 尽可能自动配置Spring容器;
- 提供准备好的特性,如指标、健康检查和外部化配置;
- 绝对没有代码生成,不需要XML配置。
运行原理:
重点:
(一)约定优于配置
90%以上的项目呢,配置都差不多,所以呢spring团队,就搞出了一个通用的配置,以后我们程序猿就不需要再去配置这些繁杂的配置了. 如果用的ssm,所有的maven依赖,版本,都需要我们程序猿去控制,去找依赖,并且互相配合依赖.依赖没有配合好,jar冲突,,出了问题就需要程序猿去解决,一般非常耗时的.
补充:约定优于配置也被称为习惯优于配置、约定大于配置
提示:全局配置名称,默认 application
配置文件优先级:有config>无configh properties > yml > yaml
(二)开箱即用
- 内嵌Tomcat或Jetty等Servlet容器;
- 用来简化新Spring应用的初始搭建以及开发过程
- 每一个stater都是一个场景功能
<!--引入web starter启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
(三)程序入口
/*
springboot启动类,服务类
@SpringBootApplication是一个复合注解(包括@ComponentScan,和@SpringBootConfiguration,@EnableAutoConfiguration)
*/
@SpringBootApplicationpublicclassDemo0817Application{publicstaticvoidmain(String[] args){
SpringApplication.run(Demo0817Application.class, args);}//main 程序的入口}
(四)常用注解
字段 | 说明 |
---|---|
@ComponentScan | 自动扫描组件,可自发配置一些Bean |
@Configuration | 等同于 spring 的 XML 配置文件 |
@EnableAutoConfiguration | 根据jar依赖自动配置Spring应用 |
@SpringBootApplication | 给springBoot自动进行必要的配置(@Configuration ,@EnableAutoConfiguration 和 @ComponentScan) |
@ResponseBody | 异步获取数据 |
@Controller | 定义控制类 |
@RequestMapping | 负责URL到Controller中的具体参数的映射 |
@Import | 导入其他配置类 |
@ImportResourc | 加载xml配置文件 |
@Autowired | 自动导入依赖的Bean |
@Service | 修饰Server层 |
@Repository | 可以确保 DAO 或者 repositories 提供异常转译,这个注解修饰的 DAO 或者 repositories 类会被 ComponetScan 发现并配置,同时也不需要为它们提供 XML 配置项 |
@Bean | 等同于xml中配置的Bean |
@Value | 注入值给配置类 |
@Inject | 等同于@Autowired(无required 属性) |
@Component | 泛指组件 |
@Qualifier | 当有多个同一类型的 Bean 时,可以用 @Qualifier(“name”) 来指定。与 @Autowired 配合使用。@Qualifier 只描述符除了能根据名字进行注入,还能更详细的控制如何选择候选者 |
@Resource | @Resource(name=”name”,type=”type”) 默认 byName 与@Autowired类似 |
还有JPA和springMVC以及全局异常处理可通过超连接访问
实例化SpringApplication
SpringApplication初始化时主要做三件事情:
- 根据classpath下是否存在(ConfigurableWebApplicationContext)判断是否要启动一个web applicationContext
- SpringFactoriesInstances加载classpath下所有可用的ApplicationContextInitializer
- SpringFactoriesInstances加载classpath下所有可用的ApplicationListener
publicSpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources){this.resourceLoader= resourceLoader;
Assert.notNull(primarySources,"PrimarySources must not be null");this.primarySources=newLinkedHashSet<>(Arrays.asList(primarySources));//1.根据classpath下是否存在(ConfigurableWebApplicationContext)判断是否要启动一个web applicationContextthis.webApplicationType= WebApplicationType.deduceFromClasspath();//2.SpringFactoriesInstances加载classpath下所有可用的ApplicationContextInitializersetInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));//3.SpringFactoriesInstances加载classpath下所有可用的ApplicationListenersetListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass=deduceMainApplicationClass();}
执行run方法
代码如下:
public ConfigurableApplicationContextrun(String... args){
StopWatch stopWatch=newStopWatch();
stopWatch.start();
ConfigurableApplicationContext context=null;
Collection<SpringBootExceptionReporter> exceptionReporters=newArrayList<>();configureHeadlessProperty();//1.遍历SpringApplication初始化过程中加载的SpringApplicationRunListeners
SpringApplicationRunListeners listeners=getRunListeners(args);//2.调用starting()监听SpringApplication的启动
listeners.starting();try{
ApplicationArguments applicationArguments=newDefaultApplicationArguments(args);//3.加载SpringBoot配置环境
ConfigurableEnvironment environment=prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);//4.设置banner属性
Banner printedBanner=printBanner(environment);//5.创建ConfigurableApplicationContext(应用配置上下文)
context=createApplicationContext();
exceptionReporters=getSpringFactoriesInstances(SpringBootExceptionReporter.class,newClass[]{ ConfigurableApplicationContext.class}, context);//6.将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联prepareContext(context, environment, listeners, applicationArguments, printedBanner);//7.实例化beanrefreshContext(context);afterRefresh(context, applicationArguments);
stopWatch.stop();if(this.logStartupInfo){newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}
listeners.started(context);callRunners(context, applicationArguments);}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters, listeners);thrownewIllegalStateException(ex);}try{
listeners.running(context);}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters,null);thrownewIllegalStateException(ex);}return context;}
遍历SpringApplication初始化过程中加载的SpringApplicationRunListeners:
private SpringApplicationRunListenersgetRunListeners(String[] args){
Class<?>[] types=newClass<?>[]{ SpringApplication.class, String[].class};returnnewSpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types,this, args));}
调用Starting()监听SpringApplication的启动:
publicvoidstarting(){//遍历所有的SpringApplicationRunListener,调用starting()方法监听SpringApplication的启动for(SpringApplicationRunListener listener:this.listeners){
listener.starting();}}
加载SpringBoot配置环境
加载SpringBoot配置环境,如果是通过web容器发布,会加载StandardEnvironment。将配置文件(Environment)加入到监听器对象中(SpringApplicationRunListeners)private ConfigurableEnvironmentprepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments){// Create and configure the environment//如果environment不为空直接返回 || 如果是web环境则直接实例化StandardServletEnvironment类 || 如果不是web环境则直接实例化StandardEnvironment类
ConfigurableEnvironment environment=getOrCreateEnvironment();//配置环境信息configureEnvironment(environment, applicationArguments.getSourceArgs());//通知所有的监听者,环境已经准备好了
listeners.environmentPrepared(environment);bindToSpringApplication(environment);if(!this.isCustomEnvironment){
environment=newEnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}
ConfigurationPropertySources.attach(environment);return environment;}
初始化ConfigurableApplicationContext
publicenum WebApplicationType{/**
* The application should not run as a web application and should not start an
* embedded web server.
*/// 应用程序不是web应用,也不应该用web服务器去启动NONE,/**
* The application should run as a servlet-based web application and should start an
* embedded servlet web server.
*///应用程序应作为基于servlet的web应用程序运行,并应启动嵌入式servlet web(tomcat)服务器SERVLET,/**
* The application should run as a reactive web application and should start an
* embedded reactive web server.
*///应用程序应作为 reactive web应用程序运行,并应启动嵌入式 reactive web服务器。REACTIVE;}
根据webEnvironment是否是web环境创建默认的contextClass,
AnnotationConfigEnbeddedWebApplicationContext(通过扫描所有注解类来加载bean)和ConfigurableWebApplicationContext),最后通过BeanUtils实例化上下文对象,并返回。protected ConfigurableApplicationContextcreateApplicationContext(){//根据webEnvironment是否是web环境创建默认的contextClass
Class<?> contextClass=this.applicationContextClass;if(contextClass==null){try{switch(this.webApplicationType){caseSERVLET://AnnotationConfigServletWebServerApplicationContext
contextClass= Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;caseREACTIVE://AnnotationConfigReactiveWebServerApplicationContext
contextClass= Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default://AnnotationConfigApplicationContext
contextClass= Class.forName(DEFAULT_CONTEXT_CLASS);}}catch(ClassNotFoundException ex){thrownewIllegalStateException("Unable create a default ApplicationContext, "+"please specify an ApplicationContextClass",
ex);}}//BeanUtils实例化上下文对象return(ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}
将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联
privatevoidprepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner){//设置上下文的environment
context.setEnvironment(environment);//应用上下文后处理postProcessApplicationContext(context);//在context refresh之前,对其应用ApplicationContextInitializerapplyInitializers(context);//上下文准备
listeners.contextPrepared(context);//打印启动日志和启动应用的profileif(this.logStartupInfo){logStartupInfo(context.getParent()==null);logStartupProfileInfo(context);}// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory= context.getBeanFactory();//向beanFactory注册单例bean:命令行参数bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if(printedBanner!=null){//向beanFactory注册单例bean:banner bean
beanFactory.registerSingleton("springBootBanner", printedBanner);}if(beanFactoryinstanceofDefaultListableBeanFactory){((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// Load the sources//获取SpringApplication的primarySources属性
Set<Object> sources=getAllSources();
Assert.notEmpty(sources,"Sources must not be empty");//将bean加载到应用上下文load(context, sources.toArray(newObject[0]));//向上下文添加ApplicationListener,并广播ApplicationPreparedEvent事件
listeners.contextLoaded(context);}
~bean的实例化完成