springboot源码分析

一:SpringBoot

1、SpringBoot三大特性

1、帮助开发者快速整合第三方框架(原理Maven依赖封装)

2、内嵌服务器(原理Java语言创建服务器)

3、完全注解形式替代XML(原理包装Spring体系注解)spring-boot-starter-web 整合Spring,SpringMVC

2、SpringBoot与SpringCloud概念

SpringCloud的RPC远程调用依赖SpringMVC编写接口(Http+json)

SpringCloud是微服务一站式解决方案,基于SpringBoot之上搭建起来的

3、常用注解归纳

@EnableAutoConfiguration:启动SpringMVC,启动时,扫包范围当前包下

@ComponentScan:启动时扫包范围

@Configuration:标识当前类为配置类,结合@Bean注入bean

@SpringBootApplication:整合前面三个注解,扫包范围当前同级包及子包

4、SpringBoot整合多数据源

1.分包名(推荐使用)

2.注解形式:

@EnableTransactionManager注解默认开启

多数据源分布式事务问题产生在同一个项目中,有多个不同的数据库连接( jta+automic )两阶段提交协议。将数据源统一交给全局xa事务管理

5、全局捕获异常

@ControllerAdvice:标识为异常切面类

@ExceptionHandler(XXX.class):拦截异常(异常类型.class)

6、多环境版本

本地开发,测试环境,预生产环境,生产环境...

application.yml:指定读取的环境:

    spring:  
        profiles:    
            active: dev #默认为开发环境

二、SpringBoot源码分析

1、自定义starter

@Configuration:等同于xml配置,结合@Bean使用

自定义starter

1.引入autoconfiguration依赖:自动注入

2.META-INF/spring.factories:配置EnableAutoConfiguration=自定义configuration

3.引入process依赖,编写配置文件有提示

4.打入maven仓库

2、源码分析

首先是项目启动类:

1public static void main(String[] args) { 2 SpringApplication.run(SsgSearchApplication.class, args); 3 } 4 5 public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { 6 return run(new Class[]{primarySource}, args); 7 } 8 9public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { 10 return (new SpringApplication(primarySources)).run(args); 11 }

一:创建SpringApplication对象过程:new SpringApplication(primarySources)

1public SpringApplication(Class<?>... primarySources) { 2 this((ResourceLoader)null, primarySources); 3 } 4 5public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { 6 this.sources = new LinkedHashSet(); 7 this.bannerMode = Mode.CONSOLE; 8 this.logStartupInfo = true; 9 this.addCommandLineProperties = true; 10 this.addConversionService = true; 11 this.headless = true; 12 this.registerShutdownHook = true; 13 this.additionalProfiles = new HashSet(); 14 this.isCustomEnvironment = false; 15 this.resourceLoader = resourceLoader; 16 Assert.notNull(primarySources, "PrimarySources must not be null"); 17 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); 18 //程序进入这里,选择启动方式 19 this.webApplicationType = WebApplicationType.deduceFromClasspath(); 20 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); 21 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); 22 this.mainApplicationClass = this.deduceMainApplicationClass(); 23 }

二:this.webApplicationType = WebApplicationType.deduceFromClasspath();

1static WebApplicationType deduceFromClasspath() { 2 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)) { 3 //1.使用响应式web启动 4 return REACTIVE; 5 } else { 6 String[] var0 = SERVLET_INDICATOR_CLASSES; 7 int var1 = var0.length; 8 9 for(int var2 = 0; var2 < var1; ++var2) { 10 String className = var0[var2]; 11 if (!ClassUtils.isPresent(className, (ClassLoader)null)) { 12 //2.不会内嵌web服务器,最终通过外部tomcat服务器运行 13 return NONE; 14 } 15 } 16 //程序分支走到这里 17 //3.应用程序基于servlet应用程序,并且嵌入web server服务器 18 return SERVLET; 19 } 20 } 21 22//将spring上下文相关类注入到spring容器中 23this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

1//将spring监听相关类注入到spring容器中 2this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

1this.mainApplicationClass = this.deduceMainApplicationClass(); 2 3 //获取启动的class 4private Class<?> deduceMainApplicationClass() { 5 try { 6 StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace(); 7 StackTraceElement[] var2 = stackTrace; 8 int var3 = stackTrace.length; 9 10 for(int var4 = 0; var4 < var3; ++var4) { 11 StackTraceElement stackTraceElement = var2[var4]; 12 if ("main".equals(stackTraceElement.getMethodName())) { 13 return Class.forName(stackTraceElement.getClassName()); 14 } 15 } 16 } catch (ClassNotFoundException var6) { 17 } 18 19 return null; 20 } 21 22return (new SpringApplication(primarySources)).run(args); 23 24 public ConfigurableApplicationContext run(String... args) { 25 26 StopWatch stopWatch = new StopWatch(); 27 //记录启动开启时间 28 stopWatch.start(); 29 ConfigurableApplicationContext context = null; 30 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); 31 this.configureHeadlessProperty(); 32 SpringApplicationRunListeners listeners = this.getRunListeners(args); 33 listeners.starting(); 34 35 Collection exceptionReporters; 36 try { 37 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); 38 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); 39 this.configureIgnoreBeanInfo(environment); 40 //打印控制台输出的banner图 41 Banner printedBanner = this.printBanner(environment); 42 context = this.createApplicationContext(); 43 exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); 44 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); 45 this.refreshContext(context); 46 this.afterRefresh(context, applicationArguments); 47 //记录启动结束时间 48 stopWatch.stop(); 49 if (this.logStartupInfo) { 50 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); 51 } 52 53 listeners.started(context); 54 this.callRunners(context, applicationArguments); 55 } catch (Throwable var10) { 56 this.handleRunFailure(context, var10, exceptionReporters, listeners); 57 throw new IllegalStateException(var10); 58 } 59 60 try { 61 listeners.running(context); 62 return context; 63 } catch (Throwable var9) { 64 this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); 65 throw new IllegalStateException(var9); 66 } 67 } 68 69/** * 应用启动入口 */ 70@SpringBootApplication 71 72@SpringBootConfiguration 73@EnableAutoConfiguration 74@ComponentScan 75 76@EnableAutoConfiguration 77 78//选择器方式注入到我们的IOC容器 79@Import({AutoConfigurationImportSelector.class}) 80public @interface EnableAutoConfiguration { 81 82protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { 83 if (!this.isEnabled(annotationMetadata)) { 84 return EMPTY_ENTRY; 85 } else { 86 AnnotationAttributes attributes = this.getAttributes(annotationMetadata); 87 //这里拿到配置类109个,最终选择性注册到IOC容器中去 88 //META-INF/spring.factories下的EnableAutoConfiguration下的109个类,如果引入了,就会加载第三方配置的启动类 89 //加载DispatcherServletAutoConfiguration 90 //加载ServletWebServerFactoryAutoConfiguration 91 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); 92 configurations = this.removeDuplicates(configurations); 93 Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); 94 this.checkExcludedClasses(configurations, exclusions); 95 configurations.removeAll(exclusions); 96 configurations = this.filter(configurations, autoConfigurationMetadata); 97 this.fireAutoConfigurationImportEvents(configurations, exclusions); 98 return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); 99 } 100 }

1ServletWebServerFactoryAutoConfiguration 2 3 @Bean 4 public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { 5 return new ServletWebServerFactoryCustomizer(serverProperties); 6 } 7 8 public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) { 9 this.serverProperties = serverProperties; 10 } 11 12@ConfigurationProperties( 13 prefix = "server", 14 ignoreUnknownFields = true 15) 16public class ServerProperties { 17 private Integer port; 18 private InetAddress address; 19 @NestedConfigurationProperty 20 private final ErrorProperties error = new ErrorProperties(); 21 private Boolean useForwardHeaders; 22 private String serverHeader; 23 private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L); 24 private Duration connectionTimeout; 25 @NestedConfigurationProperty 26 private Ssl ssl; 27 @NestedConfigurationProperty 28 private final Compression compression = new Compression(); 29 @NestedConfigurationProperty 30 private final Http2 http2 = new Http2(); 31 private final ServerProperties.Servlet servlet = new ServerProperties.Servlet(); 32 private final ServerProperties.Tomcat tomcat = new ServerProperties.Tomcat(); 33 private final ServerProperties.Jetty jetty = new ServerProperties.Jetty(); 34 private final ServerProperties.Undertow undertow = new ServerProperties.Undertow(); 35 36@Configuration 37@AutoConfigureOrder(-2147483648) 38@ConditionalOnClass({ServletRequest.class}) 39@ConditionalOnWebApplication( 40 type = Type.SERVLET 41) 42@EnableConfigurationProperties({ServerProperties.class}) 43//三个启动配置类,支持三种服务器 44//EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class 45@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class}) 46public class ServletWebServerFactoryAutoConfiguration { 47 public ServletWebServerFactoryAutoConfiguration() { 48 } 49 50 @Bean 51 public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { 52 return new ServletWebServerFactoryCustomizer(serverProperties); 53 } 54 55 @Configuration 56 @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class}) 57 @ConditionalOnMissingBean( 58 value = {ServletWebServerFactory.class}, 59 search = SearchStrategy.CURRENT 60 ) 61 public static class EmbeddedTomcat { 62 public EmbeddedTomcat() { 63 } 64 65 @Bean 66 public TomcatServletWebServerFactory tomcatServletWebServerFactory() { 67 return new TomcatServletWebServerFactory(); 68 } 69 } 70 71 public WebServer getWebServer(ServletContextInitializer... initializers) { 72 //创建我们的tomcat服务器 73 Tomcat tomcat = new Tomcat(); 74 File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat"); 75 tomcat.setBaseDir(baseDir.getAbsolutePath()); 76 Connector connector = new Connector(this.protocol); 77 tomcat.getService().addConnector(connector); 78 this.customizeConnector(connector); 79 tomcat.setConnector(connector); 80 tomcat.getHost().setAutoDeploy(false); 81 this.configureEngine(tomcat.getEngine()); 82 Iterator var5 = this.additionalTomcatConnectors.iterator(); 83 84 while(var5.hasNext()) { 85 Connector additionalConnector = (Connector)var5.next(); 86 tomcat.getService().addConnector(additionalConnector); 87 } 88 89 this.prepareContext(tomcat.getHost(), initializers); 90 return this.getTomcatWebServer(tomcat); 91 }

DispatcherServletAutoConfiguration

WebMvcProperties

1@ConfigurationProperties( 2 prefix = "spring.mvc" 3) 4public class WebMvcProperties { 5 private Format messageCodesResolverFormat; 6 private Locale locale; 7 private WebMvcProperties.LocaleResolver localeResolver; 8 private String dateFormat; 9 private boolean dispatchTraceRequest; 10 private boolean dispatchOptionsRequest; 11 private boolean ignoreDefaultModelOnRedirect; 12 private boolean throwExceptionIfNoHandlerFound; 13 private boolean logResolvedException; 14 private String staticPathPattern; 15 private final WebMvcProperties.Async async; 16 private final WebMvcProperties.Servlet servlet; 17 private final WebMvcProperties.View view; 18 private final WebMvcProperties.Contentnegotiation contentnegotiation; 19 private final WebMvcProperties.Pathmatch pathmatch; 20 21 22//加载springmvc 23@Bean( 24 name = {"dispatcherServlet"} 25 ) 26 public DispatcherServlet dispatcherServlet() { 27 DispatcherServlet dispatcherServlet = new DispatcherServlet(); 28 dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest()); 29 dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest()); 30 dispatcherServlet.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); 31 dispatcherServlet.setEnableLoggingRequestDetails(this.httpProperties.isLogRequestDetails()); 32 return dispatcherServlet; 33 }

三、SpringBoot启动流程分析

1//1.创建SpringApplication对象 2new SpringApplication(primarySources) 3//1.1获取当前启动类型原理:判断当前classpath是否有加载我们的servlet类,返回启动方式,webApplicationType分为三种启动类型:REACTIVE,NONE,SERVLET,默认SERVLET类型启动:嵌入web server服务器启动 4this.webApplicationType = WebApplicationType.deduceFromClasspath(); 5//1.2读取springboot包下的META-INF.spring.factories下的ApplicationContextInitializer装配到集合 6this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); 7//读取springboot包下的META-INF.spring.factories下的ApplicationListener装配到 8this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); 9 10 //2.调用SpringApplication run 实现启动同时返回当前容器的上下文 11(new SpringApplication(primarySources)).run(args) 12 13//3.记录springboot启动时间 14StopWatch stopWatch = new StopWatch(); 15 16//4.读取META-INF/spring.factories下的ApplicationListener装配到集合 17SpringApplicationRunListeners listeners = this.getRunListeners(args) 18 19//5.循环调用监听starting方法(监听器初始化操作,做一些回调方法) 20listeners.starting(); 21 22//6.对参数进赋值 23ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); 24//6.1读取配置文件到我们的springboot容器中 25listeners.environmentPrepared((ConfigurableEnvironment)environment) 26//6.1.1 27this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); 28//6.1.2 29this.multicastEvent(event, this.resolveDefaultEventType(event)); 30//6.1.3 31this.invokeListener(listener, event); 32//6.1.4 33this.doInvokeListener(listener, event); 34//6.1.5 35listener.onApplicationEvent(event);

1this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event); 2 3postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());

1this.addPropertySources(environment, application.getResourceLoader()); 2 3//7.读取到配置文件内容,放入springboot容器中 4protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { 5 RandomValuePropertySource.addToEnvironment(environment); 6 (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load(); 7 } 8 9this.load((ConfigFileApplicationListener.Profile)null, this::getNegativeProfileFilter, this.addToLoaded(MutablePropertySources::addFirst, true)); 10 11names.forEach((name) -> { this.load(location, name, profile, filterFactory, consumer);}); 12 13this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer); 14 15locations.addAll(this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, "classpath:/,classpath:/config/,file:./,file:./config/")); 16 17//8.打印banner图 18Banner printedBanner = this.printBanner(environment); 19 20//9.创建SpringBoot上下文AnnotationConfigServletWebServerApplicationContext 21context = this.createApplicationContext(); 22case SERVLET:contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); 23 24 this.refreshContext(context); 25 ((AbstractApplicationContext)applicationContext).refresh(); 26//10.走spring的刷新方法 27 public void refresh() throws BeansException, IllegalStateException { 28 synchronized(this.startupShutdownMonitor) { 29 this.prepareRefresh(); 30 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); 31 this.prepareBeanFactory(beanFactory); 32 33 try { 34 this.postProcessBeanFactory(beanFactory); 35 this.invokeBeanFactoryPostProcessors(beanFactory); 36 this.registerBeanPostProcessors(beanFactory); 37 this.initMessageSource(); 38 this.initApplicationEventMulticaster(); 39 this.onRefresh(); 40 this.registerListeners(); 41 this.finishBeanFactoryInitialization(beanFactory); 42 this.finishRefresh(); 43 } catch (BeansException var9) { 44 if (this.logger.isWarnEnabled()) { 45 this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); 46 } 47 48 this.destroyBeans(); 49 this.cancelRefresh(var9); 50 throw var9; 51 } finally { 52 this.resetCommonCaches(); 53 } 54 55 } 56 }

//11.开始创建web server服务器

//12.加载springmvc

1//13.空方法回调 2this.afterRefresh(context, applicationArguments); 3 4//14.开始使用广播和回调机制通知监听器SpringBoot容器启动成功 5listeners.started(context); 6 7//15.开始使用广播和回调机制开始运行项目 8listeners.running(context); 9 10//16.返回当前上下文 11return context;
点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Spring5.0源码深度解析之理解Configuration注解

!(https://gss1.bdstatic.com/vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign0c730b84bd19ebc4c078719fba1da8c1/37d12f2eb9389b503a80d4b38b35e5dde6116ed7.jpg)

Spring5.0源码深度解析之Spring核心注解

!(https://gss1.bdstatic.com/vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign0c730b84bd19ebc4c078719fba1da8c1/37d12f2eb9389b503a80d4b38b35e5dde6116ed7.jpg)

Spring5.0源码深度解析之SpringBean的Aop的使用

!(https://gss1.bdstatic.com/vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign0c730b84bd19ebc4c078719fba1da8c1/37d12f2eb9389b503a80d4b38b35e5dde6116ed7.jpg)

Spring5.0源码深度解析之SpringBean的Aop源码分析

!(https://gss1.bdstatic.com/vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign0c730b84bd19ebc4c078719fba1da8c1/37d12f2eb9389b503a80d4b38b35e5dde6116ed7.jpg)SpringAop源码分析

Spring5.0源码深度解析之SpringBean声明事务底层实现原理

!(https://gss1.bdstatic.com/vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign0c730b84bd19ebc4c078719fba1da8c1/37d12f2eb9389b503a80d4b38b35e5dde6116ed7.jpg)