第一章:SpringBoot基礎(chǔ)入門
1.1:Spring與SpinrBoot
-
Spring
能做什么-
Spring
的能力 -
Spring
的生態(tài)網(wǎng)址:
https://spring.io/projects/spring-boot
覆蓋了:
Web
開發(fā)、數(shù)據(jù)訪問、安全控制、分布式、消息服務(wù)、移動開發(fā)、批處理等。 -
Spring5
重大升級-
響應(yīng)式編程
-
內(nèi)部源碼設(shè)計
基于
Java8
的一些新特性。
-
-
-
為什么用
SpringBoot
?
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run"。
能快速創(chuàng)建出生產(chǎn)級別的Spring
應(yīng)用。-
SpringBoot
的優(yōu)點-
Create stand-alone Spring applications
:創(chuàng)建獨立的Spring
應(yīng)用。 -
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
:內(nèi)嵌Web
服務(wù)器。 -
Provide opinionated 'starter' dependencies to simplify your build configuration
:自動starter
依賴,簡單構(gòu)建配置 -
Automatically configure Spring and 3rd party libraries whenever possible
:自動配置Spring
以及第三方功能。 -
Provide production-ready features such as metrics, health checks, and externalized configuration
:提供生產(chǎn)級別的監(jiān)控、健康檢查以及外部化配置。 -
Absolutely no code generation and no requirement for XML configuration
:無代碼生成、無需編寫XML
。
SpringBoot
是整合Spring
技術(shù)棧的一站式框架,SpringBoot
是簡化Spring
技術(shù)棧的快速開發(fā)腳手架。 -
-
SpringBoot
的缺點- 迭代快,需要時刻關(guān)注變化。
- 封裝太深,內(nèi)部原理復(fù)雜,不容易精通。
-
-
時代背景
-
微服務(wù)
?
James Lewis and Martin Fowler (2014)
提出微服務(wù)完整概念。https://martinfowler.com/microservices/
? 微服務(wù)是一種架構(gòu)風(fēng)格。一個應(yīng)用拆分為一組小型服務(wù)。每個服務(wù)運行在自己的進(jìn)程內(nèi),也就是可獨立部署和升級。服務(wù)之間使用輕量級
HTTP
交互。服務(wù)圍繞業(yè)務(wù)功能拆,可以由全自動部署機制獨立部署,去中心化,服務(wù)自治。服務(wù)可以使用不同的語言、不同的存儲技術(shù)。 -
分布式
-
分布式的困難
遠(yuǎn)程調(diào)用、服務(wù)發(fā)現(xiàn)、負(fù)載均衡、服務(wù)容錯、配置管理、服務(wù)監(jiān)控、鏈路追蹤、日志管理、任務(wù)調(diào)度。
-
分布式的解決
SpringBoot + SpringCloud
-
-
-
如何學(xué)習(xí)
SpringBoot
-
官網(wǎng)文檔架構(gòu)
查看版本新特性:
https://github.com/spring-projects/spring-boot/wiki#release-notes
-
1.2:SpringBoot2入門
需求:瀏覽器發(fā)送/hello
請求,響應(yīng)Hello, Spring Boot 2
。
-
創(chuàng)建
maven
工程在
IDEA
創(chuàng)建一個新的工程boot_helloworld_01
。 -
引入依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
-
創(chuàng)建主程序
package com.wang; // 主程序類。@SpringBootApplication:這是一個SpringBoot應(yīng)用 @SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
-
編寫業(yè)務(wù)
package com.wang.controller; @RestController public class HelloController { @RequestMapping("/hello") public String handle01() { return "Hello, Spring Boot 2!"; } }
-
測試
直接運行
mian
方法,瀏覽器訪問http://localhost:8080/hello
-
修改配置
在
resources
文件夾下創(chuàng)建application.properties
文件server.port=8888
修改了上面配置,重新啟動項目,
http://localhost:8080/hello
訪問成功。 -
簡化部署
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
重新打成一個
jar
包在cmd
窗口下也能運行。
1.3:了解自動配置原理
-
SpringBoot
特點-
依賴管理
-
父項目做依賴管理
幾乎聲明了所有開發(fā)中常用的依賴的版本號,自動版本仲裁機制。
<!-- 依賴管理,自己工程引入的依賴 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> <!-- 它的父項目 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.4.RELEASE</version> </parent>
-
開發(fā)導(dǎo)入
starter
場景啟動器-
見到很多
spring-boot-starter-*
:*
就是某種場景。 -
只要引入
starter
,這個場景的所有常規(guī)需要的依賴我們都自動引入。 -
SpringBoot
所有支持的場景:https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
-
見到
*-spring-boot-starter
:第三方為我們提供的簡化開發(fā)的場景啟動器。 -
所有場景啟動器最底層的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
-
-
無需關(guān)注版本號,自動版本仲裁
- 引入依賴默認(rèn)都可以不寫版本。
- 引入非版本仲裁的
jar
,要寫版本號。
-
可以修改默認(rèn)版本
查看
spring-boot-dependencies
里面規(guī)定當(dāng)前依賴的版本用的key
。<!-- 舉例:修改mysql的版本依賴 --> <properties> <mysql.version>5.1.43</mysql.version> </properties>
-
-
自動配置
-
自動配好
Tomcat
-
引入
Tomcat
依賴<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
-
配置
Tomcat
-
-
自動配置好
SpringMVC
- 引入
SpringMVC
全套組件。 - 自動配好
SpringmVC
常用組件(功能)。
- 引入
-
自動配好
Web
常見功能-
SpringBoot
幫我們配置好了所有Web
開發(fā)的場景。
-
-
默認(rèn)的包結(jié)構(gòu)
-
主程序所在包及其下面的所有子包里面的組件都會被默認(rèn)掃描出來。
-
無序以前的包掃描配置。
-
想要改變掃描路徑:
@SpringBootApplication(scanBasePackages = "com")
或者@ComponentScan("com.wang")
指定掃描路徑@SpringBootApplication(scanBasePackages = "com.wang") // 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.wang")
-
-
各種配置擁有默認(rèn)值
- 默認(rèn)配置最終都是映射到某個類上。
- 配置文件的值最終會綁定在每個類上,這個類會在容器中創(chuàng)建對象。
-
按需加載所有自動配置項
- 非常多的
starter
。 - 引入了哪些場景這個場景的自動配置才會開啟。
-
SpringBoot
所有的自動配置功能都在spring-boot-autoconfigure
包里面。
- 非常多的
-
-
-
容器功能
-
添加組件
先創(chuàng)建兩個實體類:
User
和Pet
package com.wang.bean; // 用戶 public class User { private String name; private Integer age; private Pet pet; // 省略空參、全參構(gòu)造、get/set方法、toString方法 }
package com.wang.bean; // 寵物 public class Pet { private String name; // 省略空參、全參構(gòu)造、get/set方法、toString方法 }
-
@Configuration
Full
模式與Lite
模式:- 配置類組件之間無依賴關(guān)系用
Lite
模式加速容器啟動過程,減少判斷。 - 配置類組件之間有依賴關(guān)系,方法會被調(diào)用得到之前單實例組件,用
Full
模式。
// Configuration使用示例 package com.wang.config; // 配置類里面使用@Bean標(biāo)注在方法給容器注冊組件,默認(rèn)也是單實例的。 // 配置類本身也是組件 // proxyBeanMethods = false:代理bean的方法 // Full(proxyBeanMethods = true): 【保證每個@Bean方法被調(diào)用多少次返回的組件都是單實例的】 // Lite(proxyBeanMethods = false): 【每個@Bean方法被調(diào)用多少次返回的組件都是新創(chuàng)建的】 // 組件依賴必須使用Full模式默認(rèn)。其他默認(rèn)是否Lite模式 // 告訴SpringBoot這一個配置類 == 配置文件 @Configuration(proxyBeanMethods = false) public class MyConfig { // 給容器中添加組件。以方法名作為組件的id。返回類型就是組件類型。返回的值,就是組件在容器中的實例 @Bean public User user01() { User zhangsan = new User("zhangsan", 18); // User組件依賴了Pet組件 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom") public Pet tomcatPet() { return new Pet("tomcat"); } }
// Configuration測試代碼 package com.wang; @SpringBootApplication public class MainApplication { public static void main(String[] args) { // 1. 返回我們IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 2. 查看容器里面的組件 String[] names = run.getBeanDefinitionNames(); for (String name: names) { System.out.println(name); } // 3.從容器中獲取組件 Pet tom01 = run.getBean("tom", Pet.class); Pet tom02 = run.getBean("tom", Pet.class); System.out.println("組件:" + (tom01 == tom02)); MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); // 4. 組件是否單例 User user1 = bean.user01(); User user2 = bean.user01(); System.out.println(user1 == user2); User user01 = run.getBean("user01", User.class); Pet tom = run.getBean("tom", Pet.class); System.out.println("用戶的寵物: " + (user01.getPet() == tom)); } }
- 配置類組件之間無依賴關(guān)系用
-
@Import()
@Import({User.class, DBHelper.class})
給容器中自動創(chuàng)建出這兩個類型的組件、默認(rèn)組件的名字就是全類名。 -
@Conditional
條件裝配:滿足
Conditional
指定的條件,則進(jìn)行組件注入。// 條件轉(zhuǎn)配示例 package com.wang.config; @Configuration // 容器中存在tom組件時,才給類中的bean進(jìn)行組件注入 @ConditionalOnBean(name = "tom") public class MyConfig { @Bean public User user01() { User zhangsan = new User("zhangsan", 18); zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom22") public Pet tomcatPet() { return new Pet("tomcat"); } }
// 測試條件裝配 package com.wang; @SpringBootApplication() public class MainApplication { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); boolean tom = run.containsBean("tom"); System.out.println("容器中Tom組件:" + tom); boolean user01 = run.containsBean("user01"); System.out.println("容器中user01組件:" + user01); boolean tom22 = run.containsBean("tom22"); System.out.println("容器中tom22組件:" + tom22); } }
-
-
原生配置文件引入
-
@ImportResource
<!--創(chuàng)建beans.xml配置文件--> <bean id="haha" class="com.wang.bean.User"> <property name="name" value="zhangsan"></property> <property name="age" value="18"></property> </bean> <bean id="hehe" class="com.wang.bean.Pet"> <property name="name" value="tomcat"></property> </bean>
package com.wang.config; // 添加@ImportResource注解 @ImportResource("classpath:beans.xml") public class MyConfig { .... }
// 測試IOC容器是否存在haha和hehe組件 package com.wang; @SpringBootApplication public class MainApplication { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); boolean haha = run.containsBean("haha"); System.out.println("haha: :" + haha); boolean hehe = run.containsBean("hehe"); System.out.println("hehe::" + hehe); } }
-
-
配置綁定
如何使用
Java
讀取到properties
文件中的內(nèi)容,并且把它封裝到JavaBean
中,以供隨時使用:# application.properties文件中 mycar.brand=BYD mycar.price=100000
-
@ConfigurationProperties
package com.wang.bean; // 只有在容器中的組件,才會擁有SpringBoot提供的強大功能 @Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; private Integer price; // 省略get/set方法、toString方法 }
-
@EnableConfigurationProperties
+@ConfigurationProperties
package com.wang.bean; @ConfigurationProperties(prefix = "mycar") public class Car { ..... }
package com.wang.config; @Configuration // 1.開啟Car配置綁定功能 // 2.把這個Car這個組件自動注冊到容器中 @EnableConfigurationProperties(Car.class) public class MyConfig { ... }
-
-
-
自動配置原理入門
-
引導(dǎo)加載類自動配置
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ... }
-
@SpringBootConfiguration
// 代表當(dāng)前是一個配置類 @Configuration public @interface SpringBootConfiguration {}
-
@ComponentScan
// 指定掃描那些注解 @Repeatable(ComponentScans.class) public @interface ComponentScan { .... }
-
@EnableAutoConfiguration
@AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
-
@AutoConfigurationPackage
// 利用Registrar給容器中導(dǎo)入一系列組件 // 將指定的一個包下的所有組件導(dǎo)入進(jìn)來,MainApplication主程序所在的包下 @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { .... }
package org.springframework.boot.autoconfigure; public abstract class AutoConfigurationPackages { ...... /** * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing * configuration. */ static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } } ..... }
-
@Import(AutoConfigurationImportSelector.class)
// 1.利用getAutoConfigurationEntry(annotationMetadata)給容器中批量導(dǎo)入一些組件 // 2.調(diào)用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes) // 獲取到所有需要導(dǎo)入到容器中的配置類 package org.springframework.boot.autoconfigure; public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { ...... @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } ....... }
// 接上面的類 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
// 3.利用工廠加載Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) // 得到所有的組件 // 4.從META-INF/spring.factories位置來加載一個文件。 // 默認(rèn)掃描我們當(dāng)前系統(tǒng)里面所有META-INF/spring.factories位置的文件。 // spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面有META-INF/spring.factories package org.springframework.core.io.support; public final class SpringFactoriesLoader { .... // 此方法的返回值 public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } .... }
-
-
-
按需開啟自動配置項
# 文件里面寫死了springBoot啟動就要給容器加載的所有配置類 .... # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ .... # 雖然我們127個場景的所有自動配置啟動的時候默認(rèn)全部加載。XxxAutoConfiguration # 按照條件裝配規(guī)則(@Conditional),最終會按需配置。
-
總結(jié)
// 隨便點開spring-boot-autoconfigure-2.3.4.RELEASE.jar包下XxxAutoConfiguration文件看是否配置了此組件 @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(ServerProperties.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(CharacterEncodingFilter.class) @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { .... }
-
SpringBoot
先加載所有的自動配置類XxxAutoConfiguration
。 - 每個自動配置類按照條件進(jìn)行生效,默認(rèn)都會綁定配置文件指定的值。
XxxProperties
里面拿。XxxProperties
和配置文件進(jìn)行了綁定。 - 生效的配置類就會給容器中裝配很多組件。
- 只要容器中有這些組件,就相當(dāng)于這些功能就有了。
- 定制化配置。
- 用戶直接自己
@Bean
替換底層的組件。 - 用戶去看這個組件是獲取的配置文件什么值就去修改。
- 用戶直接自己
XxxAutoConfiguration
——> 加載組件 ——>XxxProperties
里面拿值 ——>application.properties
修改配置文章來源:http://www.zghlxwxcb.cn/news/detail-659779.html -
-
最佳實踐文章來源地址http://www.zghlxwxcb.cn/news/detail-659779.html
- 引入場景依賴
- 查看自動配置了哪些(選做):配置文件中
debug=true
開啟自動配置報告?!?code>Negative(不生效)、Positive
(生效)】 - 是否需要修改:參照文檔修改配置項
- 自動加入或者替換組件:
@Bean、@Component....
- 自定義器
XxxCustomizer
-
到了這里,關(guān)于第一章:SpringBoot基礎(chǔ)入門的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!