一、为什么要使用Springboot?🌼
我们使用ssm开发项目的时候,需要编写大量的XML文件,繁琐的配置,这样会导致开发效率低下和部署效率等等问题。那怎么解决呢?使用我们的Springboot!!!
二、Springboot概述 🌷
Spring Boot是一种基于Spring框架的快速开发应用程序的工具。我们从Springboot官网来介绍
特征(优点):
● 创建独立的Spring应用程序
● 直接嵌入Tomcat、Jetty或Under拖车(不需要部署WAR文件)
● 提供固执己见的“初学者”依赖关系,以简化构建配置
● 尽可能自动配置Spring和第三方库
● 提供生产准备功能,如度量、健康检查和外部化配置。
● 绝对不需要生成代码,也不需要xml配置。
1、Springboot原理 💖
Springboot的核心注解
SpringBoot的 核心注解是 @SpringBootApplication ,@SpringBootApplication 是一个组合注解。
@Target({ElementType.TYPE})
@Target 注解通常与 Element 类一起使用。Element 是一个枚举类,定义了可以被注释应用的不同目标元素类型。 @Target({ElementType.TYPE}) 是Java中的元注解,用于指定被注解的注解可以应用的目标元素类型。
@Retention(RetentionPolicy.RUNTIME)
@@Retention 注解通常与 RetentionPolicy 枚举一起使用,用于指定注解的保留策略。
在使用
@Retention
注解时,需要传入一个RetentionPolicy
值,指定注解的保留策略。
@SpringBootConfiguration
@SpringBootConfiguration 是 Spring Boot 框架的注解之一,用于表示一个类为Spring Boot 的配置类。具体来说,@SpringBootConfiguration 注解是 @Configuration 注解的派生注解。它用于告诉Spring Boot 框架,被标记的类是一个配置类,其中可以包含一些配置信息、Bean的定义或其他配置相关的操作。
@EnableAutoConfiguration
用于自动配置应用程序所需的各种配置和依赖项。
具体来说,@EnableAutoConfiguration 注解告诉 Spring Boot 框架启用自动配置机制,它会根据 classpath 下的依赖和配置,尝试推断和自动配置应用程序所需的 Bean。
@ComponentScan
用于配置组件扫描的注解
@ComponentScan
,它用于告诉 Spring 框架在指定的包中扫描并注册组件(例如,被@Component
、@Service
、@Repository
或@Controller
注解标记的类)。其中,
excludeFilters
属性用于指定排除某些组件的过滤器。在这个例子中,定义了两个过滤器:
第一个过滤器:
type = FilterType.CUSTOM
表示使用自定义的过滤器类型。classes = {TypeExcludeFilter.class}
指定了要使用的过滤器类,即TypeExcludeFilter
类。 这个过滤器用于排除特定类型的组件。第二个过滤器:
type = FilterType.CUSTOM
表示使用自定义的过滤器类型。classes = {AutoConfigurationExcludeFilter.class}
指定了要使用的过滤器类,即AutoConfigurationExcludeFilter
类。 这个过滤器用于排除自动配置的组件。
2、SpringBoot启动流程 💖
从我们的主启动类入手,即是标注着@SpringBootApplication注解并且有着 main() 方法的类,如下一段代码:
Run() 方法
首先执行的是我们的 run 方法:
它里面做了两件事情 ,分别是创建 SpringApplication 和执行 run() 方法。
如何创建SpringApplication?
① 设置应用类型
这个过程非常重要,直接决定了项目的类型,应用类型分为三种,都在WebApplicationType
这个枚举类中,如下:
1、NONE :顾名思义,什么都没有,正常流程走,不额外的启动web容器,比如Tomcat。 没有:顾名思义,什么都没有,正常流程走,不额外的启动容器,比如Tomcat。
2、SERVLET:基纡servlet 的web程序,需要启动内嵌的servlet web容器,比如Tomcat 。 Servlet:基纡Servlet的Web程序,需要启动内嵌的Servlet Web容器,比如Tomcat。
3、REACTIVE :基于reactive的web程序,需要启动内嵌reactive web容器。
判断的依据很简单,就是加载对应的类,比如加载了 DispatchServlet 等则会判断是 Servlet 的web程序。源码如下:
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
这里我引入了是 spring-boot-starter-web ,肯定是 Servlet 的web程序。
② 设置初始化器(Initializer)
初始化器 ApplicationContextInitializer 是个好东西,用于 IOC 容器刷新之前初始化一些组件,比如 ServletContextApplicationContextInitializer。
那么如何获取初始化器呢?
相对重要的就是第一步获取初始化器的名称了,这个肯定是 全类名 了,详细源码肯定在 loadFactoryNames() 方法中了,跟着源码进入,最终调用的是 #SpringFactoriesLoader.loadSpringFactories() 方法。
loadSpringFactories () 方法就不再详细解释了,其实就是从类路径 META-INF/spring.factories 中加载 ApplicationContextInitializer 的值。
注:上图中的只是一部分初始化器,因为 spring.factories 文件不止一个。
③ 设置监听器(Listener)
监听器 (ApplicationListener) 这个概念在 Spring 中就已经存在,主要用于监听特定的事件( ApplicationEvent ),比如IOC容器刷新、容器关闭等。
SpringApplication 的构建都是为了 run() 方法启动做铺垫,构造方法中总共就有几行代码,最重要的部分就是设置应用类型、设置初始化器、设置监听器。
注意:
初始化器和这里的监听器都要放置在
spring.factories
文件中才能在这一步骤加载,否则不会生效,因此此时IOC容器
还未创建,即使将其注入到IOC容器
中也是不会生效的。
执行run()方法
①、获取、启动运行过程监听器
SpringApplicationRunListener
这个监听器和ApplicationListener
不同,它是用来监听应用程序启动过程的,接口的各个方法含义如下:
public interface SpringApplicationRunListener {
// 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
void starting();
// 当environment构建完成,ApplicationContext创建之前,该方法被调用
void environmentPrepared(ConfigurableEnvironment environment);
// 当ApplicationContext构建完成时,该方法被调用
void contextPrepared(ConfigurableApplicationContext context);
// 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
void contextLoaded(ConfigurableApplicationContext context);
// 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
void started(ConfigurableApplicationContext context);
// 在run()方法执行完成前该方法被调用
void running(ConfigurableApplicationContext context);
// 当应用运行出错时该方法被调用
void failed(ConfigurableApplicationContext context, Throwable exception);
}
②、环境构建
这一步主要用于加载系统配置以及用户的自定义配置(
application.properties
),源码如下,在run()
方法中:
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
③、创建IOC容器
context = createApplicationContext();
根据
webApplicationType
决定创建的类型,很显然,我这里的是servlet
,因此创建的是AnnotationConfigServletWebServerApplicationContext
。
④、IOC容器的前置处理
这一步真是精华了,在刷新容器之前做准备,其中有一个非常关键的操作:将启动类注入容器,为后续的自动化配置奠定基础。源码如下:
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
⑤、刷新容器
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
//调用创建的容器applicationContext中的refresh()方法
((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/**
* 刷新上下文环境
*/
prepareRefresh();
/**
* 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/**
* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
* 添加ApplicationContextAwareProcessor处理器
* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
*/
prepareBeanFactory(beanFactory);
try {
/**
* 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
*/
postProcessBeanFactory(beanFactory);
/**
* 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
* 执行对应的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
/**
* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
* 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
*/
registerBeanPostProcessors(beanFactory);
/**
* 初始化上下文中的资源文件,如国际化文件的处理等
*/
initMessageSource();
/**
* 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
*/
initApplicationEventMulticaster();
/**
* 给子类扩展初始化其他Bean
*/
onRefresh();
/**
* 在所有bean中查找listener bean,然后注册到广播器中
*/
registerListeners();
/**
* 设置转换器
* 注册一个默认的属性值解析器
* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
*/
finishBeanFactoryInitialization(beanFactory);
/**
* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
* 即对那种在spring启动后需要处理的一些类,这些类实现了ApplicationListener<ContextRefreshedEvent>,
* 这里就是要触发这些类的执行(执行onApplicationEvent方法)
* 另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
*/
finishRefresh();
}
finally {
resetCommonCaches();
}
}
}
⑥、IOC容器的后置处理
默认为空,如果有自定义需求可以重写,比如打印一些启动结束日志等。
afterRefresh(context, applicationArguments);
⑦、发出结束执行的事件
同样是
EventPublishingRunListener
这个监听器,广播ApplicationStartedEvent
事件。
public void started(ConfigurableApplicationContext context) {
context . publishEvent(new ApplicationS tartedEvent(this .application, this .args, context));
AvailabilityChangeEvent . publish (context, Livenessstate . CORRECT) ;
}
⑧、执行Runners
Spring Boot
提供了两种Runner
让我们定制一些额外的操作,分别是CommandLineRunner
和ApplicationRunner
callRunners(context, applicationArguments);