一、幫助開發者快速整合第三方框架(原理Maven依賴封裝)java
二、內嵌服務器(原理Java語言建立服務器)react
三、徹底註解形式替代XML(原理包裝Spring體系註解)spring-boot-starter-web 整合Spring,SpringMVCweb
SpringCloud的RPC遠程調用依賴SpringMVC編寫接口(Http+json)spring
SpringCloud是微服務一站式解決方案,基於SpringBoot之上搭建起來的數據庫
@EnableAutoConfiguration:啓動SpringMVC,啓動時,掃包範圍當前包下json
@ComponentScan:啓動時掃包範圍tomcat
@Configuration:標識當前類爲配置類,結合@Bean注入beanspringboot
@SpringBootApplication:整合前面三個註解,掃包範圍當前同級包及子包服務器
1.分包名(推薦使用)mvc
2.註解形式:
@EnableTransactionManager註解默認開啓
多數據源分佈式事務問題產生在同一個項目中,有多個不一樣的數據庫鏈接( jta+automic )兩階段提交協議。將數據源統一交給全局xa事務管理
@ControllerAdvice:標識爲異常切面類
@ExceptionHandler(XXX.class):攔截異常(異常類型.class)
本地開發,測試環境,預生產環境,生產環境...
application.yml:指定讀取的環境:
spring:
profiles:
active: dev #默認爲開發環境
一、自定義starter
@Configuration:等同於xml配置,結合@Bean使用
自定義starter
1.引入autoconfiguration依賴:自動注入
2.META-INF/spring.factories:配置EnableAutoConfiguration=自定義configuration
3.引入process依賴,編寫配置文件有提示
4.打入maven倉庫
首先是項目啓動類:
public static void main(String[] args) { SpringApplication.run(SsgSearchApplication.class, args); }
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對象過程:new SpringApplication(primarySources)
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 = new HashSet(); this.isCustomEnvironment = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //程序進入這裏,選擇啓動方式 this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
二:this.webApplicationType = WebApplicationType.deduceFromClasspath();
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)) { //1.使用響應式web啓動 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)) { //2.不會內嵌web服務器,最終經過外部tomcat服務器運行 return NONE; } } //程序分支走到這裏 //3.應用程序基於servlet應用程序,而且嵌入web server服務器 return SERVLET; } }
//將spring上下文相關類注入到spring容器中 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//將spring監聽相關類注入到spring容器中 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
//獲取啓動的class private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace(); StackTraceElement[] var2 = stackTrace; int var3 = stackTrace.length; for(int var4 = 0; var4 < var3; ++var4) { StackTraceElement stackTraceElement = var2[var4]; if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException var6) { } return null; }
return (new SpringApplication(primarySources)).run(args);
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); //記錄啓動開啓時間 stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); //打印控制檯輸出的banner圖 Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); //記錄啓動結束時間 stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
/** * 應用啓動入口 */ @SpringBootApplication
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@EnableAutoConfiguration
//選擇器方式注入到咱們的IOC容器 @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //這裏拿到配置類109個,最終選擇性註冊到IOC容器中去 //META-INF/spring.factories下的EnableAutoConfiguration下的109個類,若是引入了,就會加載第三方配置的啓動類 //加載DispatcherServletAutoConfiguration //加載ServletWebServerFactoryAutoConfiguration List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }
ServletWebServerFactoryAutoConfiguration
@Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); }
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) { this.serverProperties = serverProperties; }
@ConfigurationProperties( prefix = "server", ignoreUnknownFields = true ) public class ServerProperties { private Integer port; private InetAddress address; @NestedConfigurationProperty private final ErrorProperties error = new ErrorProperties(); private Boolean useForwardHeaders; private String serverHeader; private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L); private Duration connectionTimeout; @NestedConfigurationProperty private Ssl ssl; @NestedConfigurationProperty private final Compression compression = new Compression(); @NestedConfigurationProperty private final Http2 http2 = new Http2(); private final ServerProperties.Servlet servlet = new ServerProperties.Servlet(); private final ServerProperties.Tomcat tomcat = new ServerProperties.Tomcat(); private final ServerProperties.Jetty jetty = new ServerProperties.Jetty(); private final ServerProperties.Undertow undertow = new ServerProperties.Undertow();
@Configuration @AutoConfigureOrder(-2147483648) @ConditionalOnClass({ServletRequest.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @EnableConfigurationProperties({ServerProperties.class}) //三個啓動配置類,支持三種服務器 //EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class}) public class ServletWebServerFactoryAutoConfiguration { public ServletWebServerFactoryAutoConfiguration() { } @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); }
@Configuration @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class}) @ConditionalOnMissingBean( value = {ServletWebServerFactory.class}, search = SearchStrategy.CURRENT ) public static class EmbeddedTomcat { public EmbeddedTomcat() { } @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory() { return new TomcatServletWebServerFactory(); } }
public WebServer getWebServer(ServletContextInitializer... initializers) { //建立咱們的tomcat服務器 Tomcat tomcat = new Tomcat(); File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); this.customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); this.configureEngine(tomcat.getEngine()); Iterator var5 = this.additionalTomcatConnectors.iterator(); while(var5.hasNext()) { Connector additionalConnector = (Connector)var5.next(); tomcat.getService().addConnector(additionalConnector); } this.prepareContext(tomcat.getHost(), initializers); return this.getTomcatWebServer(tomcat); }
DispatcherServletAutoConfiguration
WebMvcProperties
@ConfigurationProperties( prefix = "spring.mvc" ) public class WebMvcProperties { private Format messageCodesResolverFormat; private Locale locale; private WebMvcProperties.LocaleResolver localeResolver; private String dateFormat; private boolean dispatchTraceRequest; private boolean dispatchOptionsRequest; private boolean ignoreDefaultModelOnRedirect; private boolean throwExceptionIfNoHandlerFound; private boolean logResolvedException; private String staticPathPattern; private final WebMvcProperties.Async async; private final WebMvcProperties.Servlet servlet; private final WebMvcProperties.View view; private final WebMvcProperties.Contentnegotiation contentnegotiation; private final WebMvcProperties.Pathmatch pathmatch;
//加載springmvc @Bean( name = {"dispatcherServlet"} ) public DispatcherServlet dispatcherServlet() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setEnableLoggingRequestDetails(this.httpProperties.isLogRequestDetails()); return dispatcherServlet; }
//1.建立SpringApplication對象 new SpringApplication(primarySources) //1.1獲取當前啓動類型原理:判斷當前classpath是否有加載咱們的servlet類,返回啓動方式,webApplicationType分爲三種啓動類型:REACTIVE,NONE,SERVLET,默認SERVLET類型啓動:嵌入web server服務器啓動 this.webApplicationType = WebApplicationType.deduceFromClasspath(); //1.2讀取springboot包下的META-INF.spring.factories下的ApplicationContextInitializer裝配到集合 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //讀取springboot包下的META-INF.spring.factories下的ApplicationListener裝配到 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//2.調用SpringApplication run 實現啓動同時返回當前容器的上下文 (new SpringApplication(primarySources)).run(args)
//3.記錄springboot啓動時間 StopWatch stopWatch = new StopWatch();
//4.讀取META-INF/spring.factories下的ApplicationListener裝配到集合 SpringApplicationRunListeners listeners = this.getRunListeners(args)
//5.循環調用監聽starting方法(監聽器初始化操做,作一些回調方法) listeners.starting();
//6.對參數進賦值 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); //6.1讀取配置文件到咱們的springboot容器中 listeners.environmentPrepared((ConfigurableEnvironment)environment) //6.1.1 this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); //6.1.2 this.multicastEvent(event, this.resolveDefaultEventType(event)); //6.1.3 this.invokeListener(listener, event); //6.1.4 this.doInvokeListener(listener, event); //6.1.5 listener.onApplicationEvent(event);
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
this.addPropertySources(environment, application.getResourceLoader());
//7.讀取到配置文件內容,放入springboot容器中 protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { RandomValuePropertySource.addToEnvironment(environment); (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load(); }
this.load((ConfigFileApplicationListener.Profile)null, this::getNegativeProfileFilter, this.addToLoaded(MutablePropertySources::addFirst, true));
names.forEach((name) -> { this.load(location, name, profile, filterFactory, consumer);});
this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
locations.addAll(this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, "classpath:/,classpath:/config/,file:./,file:./config/"));
//8.打印banner圖 Banner printedBanner = this.printBanner(environment);
//9.建立SpringBoot上下文AnnotationConfigServletWebServerApplicationContext context = this.createApplicationContext(); case SERVLET:contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
this.refreshContext(context); ((AbstractApplicationContext)applicationContext).refresh(); //10.走spring的刷新方法 public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
//11.開始建立web server服務器
//12.加載springmvc
//13.空方法回調 this.afterRefresh(context, applicationArguments);
//14.開始使用廣播和回調機制通知監聽器SpringBoot容器啓動成功 listeners.started(context);
//15.開始使用廣播和回調機制開始運行項目 listeners.running(context);
//16.返回當前上下文 return context;