springboot版本2.6.3
- 启动类入口main方法
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
- 静态SpringApplication.run方法中初始化SpringApplication,并执行run方法
public static ConfigurableApplicationContext run(Class> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
- 初始化SpringApplication
public SpringApplication(Class>... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
//初始化各种参数
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//deduceFromClasspath()方法从类路径推断出Web应用程序类型(REACTIVESERVLETNONE)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//getSpringFactoriesInstances方法从META-INF/spring.factories加载和实例化给定类型接口的实现类
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//该方法用于推断并返回主应用类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
参考博文:深入SpringBoot源码(一)从SpringApplication的构造方法入门源码
ApplicationContextInitializer
# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer, org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
Springboot 内置ApplicationContextInitializer
ApplicationListener
org.springframework.context.ApplicationListener= #应用上下文加载完成后对缓存做清除工作 org.springframework.boot.ClearCachesApplicationListener, #监听双亲应用上下文的关闭事件并往自己的孩子应用上下文中传播 org.springframework.boot.builder.ParentContextCloserApplicationListener, #如果系统文件编码和环境变量中指定的不同则终止应用启动 org.springframework.boot.context.FileEncodingApplicationListener, #根据spring.output.ansi.enabled参数配置AnsiOutput org.springframework.boot.context.config.AnsiOutputApplicationListener, #监听到事件后转发给环境变量context.listener.classes指定的那些事件监听器 org.springframework.boot.context.config.DelegatingApplicationListener, #配置LoggingSystem。使用logging.config环境变量指定的配置或者缺省配置 org.springframework.boot.context.logging.LoggingApplicationListener, org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
Springboot内置ApplicationListener
- run方法(SpringBoot启动核心流程)
public ConfigurableApplicationContext run(String... args) {
//计时
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
//调⽤configureHeadlessProperty设置系统属性java.awt.headless,这⾥设置为true,表示运⾏在服务器端,在没有显示器和⿏标键盘的模式下⼯作,模拟输⼊输出设备功能
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//调用listeners.starting,里面做了什么后续再看 TODO
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//创建⼀个DefaultApplicationArguments对象,它持有着args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/*.class这样的形式,然后一个叫做PathMatchingResourcePatternResolver的类会将该路径下所有的.class文件都加载进来,然后遍历判断是不是有@Component注解,如果有的话,就是我们要装载的BeanDefinition。大致过程就是这样的了。
- 第三个过程:注册BeanDefinition
这个过程通过调用上文提到的BeanDefinitionRegister接口的实现来完成。这个注册过程把载入过程中解析得到的BeanDefinition向IoC容器进行注册。通过上文的分析,我们可以看到,在IoC容器中将BeanDefinition注入到一个ConcurrentHashMap中,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。比如DefaultListableBeanFactory 中的beanDefinitionMap属性。
前面SpringBoot启动流程源码中看到refreshContext()方法,点进去可以看到refresh()方法
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//进行一些刷新前的准备信息,如设置active=true,校验必须的参数等
this.prepareRefresh();
//创建BeanFactory: 默认实现的是ConfigurableListableBeanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//BeanFactory预备工作,设置一些初始化的Bean实例信息
this.prepareBeanFactory(beanFactory);
try {
// BeanFactory准备⼯作完成后进⾏的后置处理⼯作
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册 BeanPostProcessor 的实现类(Bean的后置处理器),在创建bean的前后等执行
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
this.initMessageSource();
// 初始化ApplicationEventMulticaster,事件派发器
this.initApplicationEventMulticaster();
// 创建webServer等
this.onRefresh();
// 注册监听器。就是注册实现了ApplicationListener接⼝的监听器Bean
this.registerListeners();
// 初始化所有⾮懒加载的 (non-lazy-init) 单例Bean.
this.finishBeanFactoryInitialization(beanFactory);
// 发布刷新完成事件,清除资源换成,启动web容器
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
onRefresh()方法
作用是创建内置Servlet容器
//AbstractApplicationContext中的方法
protected void onRefresh() throws BeansException {
}
//子类ServletWebServerApplicationContext的重写方法
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
createWebServer()
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
ServletWebServerFactory factory = this.getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
createWebServer.end();
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var5) {
throw new ApplicationContextException("Cannot initialize servlet context", var5);
}
}
this.initPropertySources();
}
点进factory.getWebServer()
可以看到这里加载了Servlet容器tomcat
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Iterator var4 = this.serverLifecycleListeners.iterator();
while(var4.hasNext()) {
LifecycleListener listener = (LifecycleListener)var4.next();
tomcat.getServer().addLifecycleListener(listener);
}
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var8 = this.additionalTomcatConnectors.iterator();
while(var8.hasNext()) {
Connector additionalConnector = (Connector)var8.next();
tomcat.getService().addConnector(additionalConnector);
}
this.prepareContext(tomcat.getHost(), initializers);
return this.getTomcatWebServer(tomcat);
}
SpringBoot启动流程分析(四):IoC容器的初始化过程
SpringBoot启动流程分析六 refreshContext()
Spring Bean的作用域
- singleton 单例:唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype 原型:每次请求都会创建一个新的 bean 实例。
- request 请求: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
- session 会话:每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
- global-session:全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
Spring Bean 的生命周期主要指的是 singleton bean,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
Spring Bean的生命周期分为四个阶段和多个扩展点。扩展点又可以分为影响多个Bean和影响单个Bean,如BeanPostProcessor、BeanFactoryProcessor、BeanNameAware等。
- 实例化 Instantiation
- 属性复制 Populate
- 初始化 Initialization
- 销毁 Destruction
详细参考博客:一文读懂 Spring Bean 的生命周期
Spring中的bean线程安全吗前面列出了Bean的作用域,原型的Bean是每个线程复制一个,所以是线程安全的,单例的Bean是共享的,没有做线程安全处理。单例Bean又分为有状态和无状态。
- 有状态的bean:就是有实例变量的对象,可以保存数据,是非线程安全的。
- 无状态的bean:就是没有实例变量的对象,不能保存数据,是线程安全的。
在Spring框架中,并没有提供bean的线程安全策略,所以Spring容器中的bean并不具备线程安全的特性,可以改为原型或者用ThreadLocal。
Spring中的bean线程安全吗
Spring如何解决循环依赖问题?为什么是三层缓存?从上面我们可以知道,对象属性的注入在对象实例化之后。
- 单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。
- 构造器的循环依赖:这种依赖spring是处理不了的,直 接抛出BeanCurrentlylnCreationException异常。
- 非单例循环依赖:无法处理。
- singletonObjects:一级缓存,也叫单例池存放已经经历了完整生命周期的Bean对象。
- earlySingletonObjects:二级缓存,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)。
- singletonFactories:三级缓存,Map
> 存放可以生成Bean的工厂。
为什么需要三级缓存
一级缓存存放成品,出现循环依赖需要引入二级缓存存放半成品,有AOP的情况需要第三级缓存存放对象工厂。
如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP(按照bean的生命周期,AOP是在初始化后在后置处理器中处理的),此时会产生另外一个对象-代理对象,这个对象最终会被存放到单例池singletonObjects中,也就是说,对于A而言,它最终的bean对象实际上应该是AOP之后的代理对象而不是原来那个原始对象,但B拿的是原始对象,这就产生冲突:B依赖的A和最终的A不是同一个对象。
Spring如何解决循环依赖
FactoryBean和BeanFactory,ApplicationContext区别BeanFactory:BeanFactory是个bean 工厂,是一个工厂类(接口), 它负责生产和管理bean的一个工厂
是ioc 容器最底层的接口,是个ioc容器,是spring用来管理和装配普通bean的ioc容器(这些bean成为普通bean)。
ApplicationContext:ApplicationContext是BeanFactory 的子接口,包含BeanFactory的所有功能,同时还进行更多的扩展。
FactoryBean:FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的(从容器中获取到的对象不是
“ FactoryBeanTest ” 对象)。
FactoryBean和BeanFactory及ApplicationContext
Spring中的拓展点有哪些BeanFactoryPostProcessor
BeanPostProcessor
ApplicationListener
……
Spring的扩展点都有哪些
- 单例模式:Spring Bean的单例作用域
- 原型模式:Spring Bean的原型作用域
- 模板方法模式:Spring中的JdbcTemplate就是这样的实现
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。
- 观察者模式:使用比较场景是在监听器中而spring中Observer模式常用的地方也是listener的实现。如ApplicationListener
- 工厂方法模式:Bean的生产
- 适配器模式:在Spring中在AOP实现中的Advice和interceptor之间的转换就是通过适配器模式实现的。
- 装饰者模式: 具体的使用在Spring session框架中的SessionRepositoryRequestWrapper使用包装模式对原生的request的功能进行增强,可以将session中的数据和分布式数据库进行同步,这样即使当前tomcat崩溃,session中的数据也不会丢失。
- 代理模式:Spring AOP。
- 策略模式:Spring中在实例化对象的时候用到Strategy模式。XmlBeanDefinitionReader,PropertiesBeanDefinitionReader
- 责任链默认:AOP中的拦截器链
- 委托者模式 :DelegatingFilterProxy,整合Shiro,SpringSecurity的时候都有用到。
干货|Spring框架中用到了哪些设计模式?
设计模式
声明式事务@Transactional,基于AOP。
TransactionInterceptor拦截器
PlatformTransactionManager事务管理器
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
DataSourceTransactionManager支持Mybatis的事务管理器实现类
源码其实是对Connection对象的调用
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
this.logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
} catch (SQLException var5) {
throw this.translateException("JDBC commit", var5);
}
}
事务的隔离级别
- 读未提交
- 读已提交
- 可重复读
- 串行化
事务的传播行为
PROPAGATION_REQUIRED:如果当前有事务,则加入该事务中。如果没有,则新建事务。
PROPAGATION_SUPPORTS:如果当前有事务,则加入该事务中。如果没有,则以非事务状态运行。
PROPAGATION_MANDATORY:如果当前有事务,则加入该事务中。如果没有,则抛出无事务异常
PROPAGATION_REQUIRES_NEW:新建事务。如果当前存在事务,则挂起该事务。
PROPAGATION_NOT_SUPPORTED:非事务状态运行。如果当前存在事务,则挂起该事务。
PROPAGATION_NEVER:非事务状态运行。如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:如果当前有事务,则嵌套事务(父子事务)执行。如果没有,类似PROPAGATION_REQUIRED处理。
DispatcherServlet 前端控制器
HandlerMapping 处理器映射器
HandlerAdapter 处理器适配器
Controller 处理器
ViewResolver 视图解析器
Spring的内容博大精深,以上只做了初步总结,后续再逐步详细完善。



