javascript
SpringBoot学习笔记~狂神
什么是SpringBoot
回顧Spring
Spring是一個(gè)開(kāi)源框架,2003 年興起的一個(gè)輕量級(jí)的Java 開(kāi)發(fā)框架,作者:Rod Johnson 。
Spring是為了解決企業(yè)級(jí)應(yīng)用開(kāi)發(fā)的復(fù)雜性而創(chuàng)建的,簡(jiǎn)化開(kāi)發(fā)。
什么 SpringBoot
學(xué)過(guò)javaweb的同學(xué)就知道,開(kāi)發(fā)一個(gè)web應(yīng)用,從最初開(kāi)始接觸Servlet結(jié)合Tomcat, 跑出一個(gè)Hello Wolrld程序,是要經(jīng)歷特別多的步驟;后來(lái)就用了框架Struts,再后來(lái)是SpringMVC,到了現(xiàn)在的SpringBoot,過(guò)一兩年又會(huì)有其他web框架出現(xiàn);你們有經(jīng)歷過(guò)框架不斷的演進(jìn),然后自己開(kāi)發(fā)項(xiàng)目所有的技術(shù)也在不斷的變化、改造嗎?建議都可以去經(jīng)歷一遍;
言歸正傳,什么是SpringBoot呢,就是一個(gè)javaweb的開(kāi)發(fā)框架,和SpringMVC類(lèi)似,對(duì)比其他javaweb框架的好處,官方說(shuō)是簡(jiǎn)化開(kāi)發(fā),約定大于配置, you can “just run”,能迅速的開(kāi)發(fā)web應(yīng)用,幾行代碼開(kāi)發(fā)一個(gè)http接口。
所有的技術(shù)框架的發(fā)展似乎都遵循了一條主線規(guī)律:從一個(gè)復(fù)雜應(yīng)用場(chǎng)景 衍生 一種規(guī)范框架,人們只需要進(jìn)行各種配置而不需要自己去實(shí)現(xiàn)它,這時(shí)候強(qiáng)大的配置功能成了優(yōu)點(diǎn);發(fā)展到一定程度之后,人們根據(jù)實(shí)際生產(chǎn)應(yīng)用情況,選取其中實(shí)用功能和設(shè)計(jì)精華,重構(gòu)出一些輕量級(jí)的框架;之后為了提高開(kāi)發(fā)效率,嫌棄原先的各類(lèi)配置過(guò)于麻煩,于是開(kāi)始提倡“約定大于配置”,進(jìn)而衍生出一些一站式的解決方案。
是的這就是Java企業(yè)級(jí)應(yīng)用->J2EE->spring->springboot的過(guò)程。
隨著 Spring 不斷的發(fā)展,涉及的領(lǐng)域越來(lái)越多,項(xiàng)目整合開(kāi)發(fā)需要配合各種各樣的文件,慢慢變得不那么易用簡(jiǎn)單,違背了最初的理念,甚至人稱配置地獄。Spring Boot 正是在這樣的一個(gè)背景下被抽象出來(lái)的開(kāi)發(fā)框架,目的為了讓大家更容易的使用 Spring 、更容易的集成各種常用的中間件、開(kāi)源軟件;
Spring Boot 基于 Spring 開(kāi)發(fā),Spirng Boot 本身并不提供 Spring 框架的核心特性以及擴(kuò)展功能,只是用于快速、敏捷地開(kāi)發(fā)新一代基于 Spring 框架的應(yīng)用程序。也就是說(shuō),它并不是用來(lái)替代 Spring 的解決方案,而是和 Spring 框架緊密結(jié)合用于提升 Spring 開(kāi)發(fā)者體驗(yàn)的工具。Spring Boot 以約定大于配置的核心思想,默認(rèn)幫我們進(jìn)行了很多設(shè)置,多數(shù) Spring Boot 應(yīng)用只需要很少的 Spring 配置。同時(shí)它集成了大量常用的第三方庫(kù)配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 應(yīng)用中這些第三方庫(kù)幾乎可以零配置的開(kāi)箱即用。
簡(jiǎn)單來(lái)說(shuō)就是SpringBoot其實(shí)不是什么新的框架,它默認(rèn)配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架 。
Spring Boot 出生名門(mén),從一開(kāi)始就站在一個(gè)比較高的起點(diǎn),又經(jīng)過(guò)這幾年的發(fā)展,生態(tài)足夠完善,Spring Boot 已經(jīng)當(dāng)之無(wú)愧成為 Java 領(lǐng)域最熱門(mén)的技術(shù)。
Spring Boot的主要優(yōu)點(diǎn):
- 為所有Spring開(kāi)發(fā)者更快的入門(mén)
- 開(kāi)箱即用,提供各種默認(rèn)配置來(lái)簡(jiǎn)化項(xiàng)目配置
- 內(nèi)嵌式容器簡(jiǎn)化Web項(xiàng)目
- 沒(méi)有冗余代碼生成和XML配置的要求
微服務(wù)
什么是微服務(wù)
微服務(wù)也是架構(gòu),把service拆分成小模塊放在不同的電腦上,就比如springMVC中每個(gè)controller都分布在一臺(tái)電腦上,然后只提供接口,然后形成了網(wǎng)狀。
微服務(wù)是一種架構(gòu)風(fēng)格,它要求我們?cè)陂_(kāi)發(fā)一個(gè)應(yīng)用的時(shí)倏,這個(gè)應(yīng)用必須構(gòu)建成一系列小服務(wù)的組合;可以通過(guò)http的方式進(jìn)行互通。要說(shuō)微服務(wù)架構(gòu),先得說(shuō)說(shuō)過(guò)去我們的單體應(yīng)用架構(gòu)。
單體應(yīng)用架構(gòu)
? 所謂單體應(yīng)用架構(gòu) (all in one)是指,我們將一個(gè)應(yīng)用的中的所有應(yīng)用服務(wù)都封裝在一個(gè)應(yīng)用中。
? 無(wú)論是ERP、CRM或是其他什么系統(tǒng),你都把數(shù)據(jù)庫(kù)訪問(wèn),web訪問(wèn),等等各個(gè)功能放到一個(gè)war包內(nèi)。
- 這樣做的好處是,易于開(kāi)發(fā)和測(cè)試;也十分方便部署;當(dāng)需要擴(kuò)展時(shí),只需要將war復(fù)制多份,然后放到多個(gè)服務(wù)器上,再做個(gè)負(fù)載均衡就可以了。
- 單體應(yīng)用架構(gòu)的缺點(diǎn)是,哪怕我要修改一個(gè)非常小的地方,我都需要停掉整個(gè)服務(wù),重新打包、部署這個(gè)應(yīng)用war包。特別是對(duì)于一個(gè)大型應(yīng)用,我們不可能吧所有內(nèi)容都放在一個(gè)應(yīng)用里面,我們?nèi)绾尉S護(hù)、如何分工合作都是問(wèn)題。
微服務(wù)架構(gòu)
all in one的架構(gòu)方式,我們把所有的功能單元放在一個(gè)應(yīng)用里面。然后我們把整個(gè)應(yīng)用部署到服務(wù)器上。如果負(fù)載能力不行,我們將整個(gè)應(yīng)用進(jìn)行水平復(fù)制,進(jìn)行擴(kuò)展,然后在負(fù)載均衡。
所謂微服務(wù)架構(gòu),就是打破之前all in one的架構(gòu)方式,把每個(gè)功能元素獨(dú)立出來(lái)。把獨(dú)立出來(lái)的功能元素的動(dòng)態(tài)組合,需要的功能元素才去拿來(lái)組合,需要多一些時(shí)可以整合多個(gè)功能元素。所以微服務(wù)架構(gòu)是對(duì)功能元素進(jìn)行復(fù)制,而沒(méi)有對(duì)整個(gè)應(yīng)用進(jìn)行復(fù)制。
這樣做的好處是:
Martin Flower于2014年3月25日寫(xiě)的《Microservices》,詳細(xì)的闡述了什么是微服務(wù)。
原文地址: http://martinfowler.com/articles/microservices.html
翻譯:https://www.cnblogs.com/liuning8023/p/4493156.html
如何構(gòu)建一個(gè)微服務(wù)
? 一個(gè)大型系統(tǒng)的微服務(wù)架構(gòu),就像一個(gè)復(fù)雜交織的神經(jīng)網(wǎng)絡(luò),每一個(gè)神經(jīng)元就是一個(gè)功能元素,它們各自完成自己的功能,然后通過(guò)http相互請(qǐng)求調(diào)用。比如一個(gè)電商系統(tǒng),查緩存、連數(shù)據(jù)庫(kù)、瀏覽頁(yè)面、結(jié)賬、支付等服務(wù)都是一個(gè)個(gè)獨(dú)立的功能服務(wù),都被微化了,它們作為一個(gè)個(gè)微服務(wù)共同構(gòu)建了一個(gè)龐大的系統(tǒng)。如果修改其中的一個(gè)功能,只需要更新升級(jí)其中一個(gè)功能服務(wù)單元即可。
? 但是這種龐大的系統(tǒng)架構(gòu)給部署和運(yùn)維帶來(lái)很大的難度。于是,spring為我們帶來(lái)了構(gòu)建大型分布式微服務(wù)的全套、全程產(chǎn)品:
- 構(gòu)建一個(gè)個(gè)功能獨(dú)立的微服務(wù)應(yīng)用單元,可以使用springboot,可以幫我們快速構(gòu)建一個(gè)應(yīng)用;
- 大型分布式網(wǎng)絡(luò)服務(wù)的調(diào)用,這部分由spring cloud來(lái)完成,實(shí)現(xiàn)分布式;
- 在分布式中間,進(jìn)行流式數(shù)據(jù)計(jì)算、批處理,我們有spring cloud data flow。
- spring為我們想清楚了整個(gè)從開(kāi)始構(gòu)建應(yīng)用到大型分布式應(yīng)用全流程方案。
第一個(gè)SpringBoot程序
官方:提供了一個(gè)快速生成的網(wǎng)站!IDEA集成了這個(gè)網(wǎng)站。
**項(xiàng)目創(chuàng)建方式一:**使用Spring Initializr 的 Web頁(yè)面創(chuàng)建項(xiàng)目
1、打開(kāi) https://start.spring.io/
2、填寫(xiě)項(xiàng)目信息
3、點(diǎn)擊”Generate Project“按鈕生成項(xiàng)目;下載此項(xiàng)目
4、解壓項(xiàng)目包,并用IDEA以Maven項(xiàng)目導(dǎo)入,一路下一步即可,直到項(xiàng)目導(dǎo)入完畢。
5、如果是第一次使用,可能速度會(huì)比較慢,包比較多、需要耐心等待一切就緒。
**項(xiàng)目創(chuàng)建方式二:**使用 IDEA 直接創(chuàng)建項(xiàng)目
1、創(chuàng)建一個(gè)新項(xiàng)目
2、選擇spring initalizr , 可以看到默認(rèn)就是去官網(wǎng)的快速構(gòu)建工具那里實(shí)現(xiàn)
3、填寫(xiě)項(xiàng)目信息
4、選擇初始化的組件(初學(xué)勾選 Web 即可)
如果不勾選 在pom.xml里面加入以下代碼也可以
<!--web依賴: tomcat,dispatcherServlet,xml--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency>5、填寫(xiě)項(xiàng)目路徑
6、等待項(xiàng)目構(gòu)建成功
- 項(xiàng)目元數(shù)據(jù)信息:創(chuàng)建時(shí)候輸入的Project Metadata部分,也就是Maven項(xiàng)目的基本元素,包括: groupld、 artifactld、version、name、description等
- parent:繼承 spring-boot-starter-parent的依賴管理,控制版本與打包等內(nèi)容
- dependencies:項(xiàng)目具體依賴,這里包含了spring-boot-starter-web用于實(shí)現(xiàn)HTTP接口(該依賴中包含了Spring MVC),官網(wǎng)對(duì)它的描述是:使用Spring MVC構(gòu)建Web(包括RESTful)應(yīng)用程序的入門(mén)者,使用Tomcat作為默認(rèn)嵌入式容器。; spring-boot-starter-test用于編寫(xiě)單元測(cè)試的依賴包。更多功能模塊的使用我們將在后面逐步展開(kāi)。
- build:構(gòu)建配置部分。默認(rèn)使用了spring-boot-maven-plug in,配合spring-boot-starter-parent就可以把Spring Boot應(yīng)用打包成JAR來(lái)直接運(yùn)行。
打包
如果遇到以上錯(cuò)誤,可以配置打包時(shí) 跳過(guò)項(xiàng)目運(yùn)行測(cè)試用例
<!--在工作中,很多情況下我們打包是不想執(zhí)行測(cè)試用例的可能是測(cè)試用例不完事,或是測(cè)試用例會(huì)影響數(shù)據(jù)庫(kù)數(shù)據(jù)跳過(guò)測(cè)試用例執(zhí)--> <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><!--跳過(guò)項(xiàng)目運(yùn)行測(cè)試用例--><skipTests>true</skipTests></configuration> </plugin>如果打包成功,則會(huì)在target目錄下生成一個(gè) jar 包
運(yùn)行jar包 java -jar jar包名字
彩蛋
如何更改啟動(dòng)時(shí)顯示的字符拼成的字母,SpringBoot呢?也就是 banner 圖案;
只需一步:到項(xiàng)目下的 resources 目錄下新建一個(gè)banner.txt 即可。
圖案可以到:https://www.bootschool.net/ascii 這個(gè)網(wǎng)站生成,然后拷貝到文件中即可!
原理初探
父依賴
自動(dòng)配置
pom.xml
其中它主要是依賴一個(gè)父項(xiàng)目,主要是管理項(xiàng)目的資源過(guò)濾及插件!
parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --> </parent>點(diǎn)進(jìn)去,發(fā)現(xiàn)還有一個(gè)父依賴
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.5.RELEASE</version><relativePath>../../spring-boot-dependencies</relativePath> </parent>這里才是真正管理SpringBoot應(yīng)用里面所有依賴版本的地方,SpringBoot的版本控制中心;
以后我們導(dǎo)入依賴默認(rèn)是不需要寫(xiě)版本;但是如果導(dǎo)入的包沒(méi)有在依賴中管理著就需要手動(dòng)配置版本了;
啟動(dòng)器
啟動(dòng)器 spring-boot-starte - xxx
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency>啟動(dòng)器就是Springboot 的啟動(dòng)場(chǎng)景
SpringBoot將所有的功能場(chǎng)景都抽取出來(lái),做成一個(gè)個(gè)的starter (啟動(dòng)器),只需要在項(xiàng)目中引入這些starter即可,所有相關(guān)的依賴都會(huì)導(dǎo)入進(jìn)來(lái) , 我們要用什么功能就導(dǎo)入什么樣的場(chǎng)景啟動(dòng)器即可 ;我們未來(lái)也可以自己自定義 starter;
啟動(dòng)器模塊是一個(gè) 空 jar 文件,僅提供輔助性依賴管理,這些依賴可能用于自動(dòng)裝配或者其他類(lèi)庫(kù);
命名歸約:
官方命名:
- 前綴:spring-boot-starter-xxx
- 比如:spring-boot-starter-web…
自定義命名:
- xxx-spring-boot-starter
- 比如:mybatis-spring-boot-starter
編寫(xiě)啟動(dòng)器
1、在IDEA中新建一個(gè)空項(xiàng)目 spring-boot-starter-diy
2、新建一個(gè)普通Maven模塊:kuang-spring-boot-starter
3、新建一個(gè)Springboot模塊:kuang-spring-boot-starter-autoconfigure
4、點(diǎn)擊apply即可,基本結(jié)構(gòu)
5、在我們的 starter 中 導(dǎo)入 autoconfigure 的依賴!
<!-- 啟動(dòng)器 --> <dependencies><!-- 引入自動(dòng)配置模塊 --><dependency><groupId>com.kuang</groupId><artifactId>kuang-spring-boot-starter-autoconfigure</artifactId><version>0.0.1-SNAPSHOT</version></dependency> </dependencies>6、將 autoconfigure 項(xiàng)目下多余的文件都刪掉,Pom中只留下一個(gè) starter,這是所有的啟動(dòng)器基本配置!
7、我們編寫(xiě)一個(gè)自己的服務(wù)
package com.kuang;public class HelloService {HelloProperties helloProperties;public HelloProperties getHelloProperties() {return helloProperties;}public void setHelloProperties(HelloProperties helloProperties) {this.helloProperties = helloProperties;}public String sayHello(String name){return helloProperties.getPrefix() + name + helloProperties.getSuffix();}}8、編寫(xiě)HelloProperties 配置類(lèi)
package com.kuang;import org.springframework.boot.context.properties.ConfigurationProperties;// 前綴 kuang.hello @ConfigurationProperties(prefix = "kuang.hello") public class HelloProperties {private String prefix;private String suffix;public String getPrefix() {return prefix;}public void setPrefix(String prefix) {this.prefix = prefix;}public String getSuffix() {return suffix;}public void setSuffix(String suffix) {this.suffix = suffix;} }9、編寫(xiě)我們的自動(dòng)配置類(lèi)并注入bean,測(cè)試
package com.kuang;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration @ConditionalOnWebApplication //web應(yīng)用生效 @EnableConfigurationProperties(HelloProperties.class) public class HelloServiceAutoConfiguration {@AutowiredHelloProperties helloProperties;@Beanpublic HelloService helloService(){HelloService service = new HelloService();service.setHelloProperties(helloProperties);return service;}}10、在resources編寫(xiě)一個(gè)自己的 META-INF\spring.factories
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.kuang.HelloServiceAutoConfiguration11、編寫(xiě)完成后,可以安裝到maven倉(cāng)庫(kù)中!
新建項(xiàng)目測(cè)試
1、新建一個(gè)SpringBoot 項(xiàng)目
2、導(dǎo)入我們自己寫(xiě)的啟動(dòng)器
<dependency><groupId>com.kuang</groupId><artifactId>kuang-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version> </dependency>3、編寫(xiě)一個(gè) HelloController 進(jìn)行測(cè)試我們自己的寫(xiě)的接口!
package com.kuang.controller;@RestController public class HelloController {@AutowiredHelloService helloService;@RequestMapping("/hello")public String hello(){return helloService.sayHello("zxc");}}4、編寫(xiě)配置文件 application.properties
kuang.hello.prefix="ppp" kuang.hello.suffix="sss"5、啟動(dòng)項(xiàng)目進(jìn)行測(cè)試,結(jié)果成功 !
主程序
// @SpringBootApplication 標(biāo)注這個(gè)類(lèi)是一個(gè)springboot的應(yīng)用 啟動(dòng)類(lèi)下的所有資源被導(dǎo)入 @SpringBootApplication public class Springboot01HelloworldApplication {public static void main(String[] args) {//將spring引應(yīng)用啟動(dòng)SpringApplication.run(Springboot01HelloworldApplication.class, args);} }-
注解
- @SpringBootConfiguration springboot的配置@Configuration spring配置類(lèi)@Component 說(shuō)明這也是一個(gè)spring的組件@EnableAutoConfiguration 自動(dòng)配置@AutoConfigurationPackage 自動(dòng)配置包@Import(AutoConfigurationPackages.Registrar.class) 自動(dòng)配置包注冊(cè)@Import(AutoConfigurationImportSelector.class) 自動(dòng)導(dǎo)入選擇List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); 獲取所有的配置
獲取候選的配置
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;}ETA-INF/spring.factories: 自動(dòng)配置的核心文件
- @SpringBootConfiguration springboot的配置@Configuration spring配置類(lèi)@Component 說(shuō)明這也是一個(gè)spring的組件@EnableAutoConfiguration 自動(dòng)配置@AutoConfigurationPackage 自動(dòng)配置包@Import(AutoConfigurationPackages.Registrar.class) 自動(dòng)配置包注冊(cè)@Import(AutoConfigurationImportSelector.class) 自動(dòng)導(dǎo)入選擇List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); 獲取所有的配置
結(jié)論
為什么這么多的配置有的沒(méi)有生效,需要導(dǎo)入對(duì)應(yīng)的start才能有用
@ConditionalOnXXX 核心注解 如果這里面的條件都滿足,才會(huì)生效
springboot所有自動(dòng)配置都是在啟動(dòng)的時(shí)候掃描并加載:spring.factories所有的自動(dòng)配置類(lèi)都在這里面,但是不一定生效,要判斷條件是否成立,只要導(dǎo)入了對(duì)應(yīng)的start,就有對(duì)應(yīng)的啟動(dòng)器了,有了啟動(dòng)器,我們自動(dòng)裝配就會(huì)生效,然后就配置成功!
SpringBoot在啟動(dòng)的時(shí)候從類(lèi)路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的值
將這些值作為自動(dòng)配置類(lèi)導(dǎo)入容器 , 自動(dòng)配置類(lèi)就生效 , 幫我們進(jìn)行自動(dòng)配置工作;
整個(gè)J2EE的整體解決方案和自動(dòng)配置都在springboot-autoconfigure的jar包中;
它會(huì)給容器中導(dǎo)入非常多的自動(dòng)配置類(lèi) (xxxAutoConfiguration), 就是給容器中導(dǎo)入這個(gè)場(chǎng)景需要的所有組件 , 并配置好這些組件 ;
容器中也會(huì)存在非常多的xxxAutoConfiguration的文件(@Bean),就是這些類(lèi)給容器中導(dǎo)入了這個(gè)場(chǎng)景需要的所有組件;并自動(dòng)配置,@Configuration , JavaConfig !
有了自動(dòng)配置類(lèi) , 免去了我們手動(dòng)編寫(xiě)配置注入功能組件等的工作;
SpringApplication
這個(gè)類(lèi)主要做了以下四件事情
1、推斷應(yīng)用的類(lèi)型是普通的項(xiàng)目還是Web項(xiàng)目
2、查找并加載所有可用初始化器 , 設(shè)置到initializers屬性中
3、找出所有的應(yīng)用程序監(jiān)聽(tīng)器,設(shè)置到listeners屬性中
4、推斷并設(shè)置main方法的定義類(lèi),找到運(yùn)行的主類(lèi)
SpringBoot Config
配置文件
SpringBoot使用一個(gè)全局的配置文件 , 配置文件名稱是固定的
-
application.properties
-
- 語(yǔ)法結(jié)構(gòu) :key=value
-
application.yml
-
- 語(yǔ)法結(jié)構(gòu) :key:空格value
- 語(yǔ)法結(jié)構(gòu) :key:空格value
對(duì)空格要求嚴(yán)格,注意空格
可以注入到配置類(lèi)中
**配置文件的作用 :**修改SpringBoot自動(dòng)配置的默認(rèn)值,因?yàn)镾pringBoot在底層都給我們自動(dòng)配置好了;
比如我們可以在配置文件中修改Tomcat 默認(rèn)啟動(dòng)的端口號(hào)!測(cè)試一下!
yaml可以直接給實(shí)體類(lèi)賦值
實(shí)體類(lèi):
/* @ConfigurationProperties作用: 將配置文件中配置的每一個(gè)屬性的值,映射到這個(gè)組件中; 告訴SpringBoot將本類(lèi)中的所有屬性和配置文件中相關(guān)的配置進(jìn)行綁定 參數(shù) prefix = “person” : 將配置文件中的person下面的所有屬性一一對(duì)應(yīng) *///再配置一個(gè)person2,然后將 @ConfigurationProperties(prefix = "person2") 指向我們的person2; @ConfigurationProperties(prefix = "person")@Component //注冊(cè)bean導(dǎo)入依賴
<!-- 導(dǎo)入配置文件處理器,配置文件進(jìn)行綁定就會(huì)有提示,需要重啟 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional> </dependency>1、將配置文件的key 值 和 屬性的值設(shè)置為不一樣,則結(jié)果輸出為null,注入失敗
2、在配置一個(gè)person2,然后將 @ConfigurationProperties(prefix = “person2”) 指向我們的person2;
yaml
配置文件還可以編寫(xiě)占位符生成隨機(jī)數(shù)
person:name: qinjiang${random.uuid} # 隨機(jī)uuidage: ${random.int} # 隨機(jī)inthappy: falsebirth: 2000/01/01maps: {k1: v1,k2: v2}lists:- code- girl- musicdog:name: ${person.hello:other}_旺財(cái) //EL表達(dá)式 如果前面的存在就用前面的 不存在則用后面的age: 1加載指定的配置文件
properties配置文件在寫(xiě)中文的時(shí)候,會(huì)有亂碼 , 我們需要去IDEA中設(shè)置編碼格式為UTF-8;
settings–>FileEncodings 中配置;
person.properties
name=世杰實(shí)體類(lèi)
@PropertySource(value = "classpath:person.properties") @Component //注冊(cè)bean public class Person {@Value("${name}")private String name;...... }對(duì)比小結(jié)
@Value這個(gè)使用起來(lái)并不友好!我們需要為每個(gè)屬性單獨(dú)注解賦值,比較麻煩;我們來(lái)看個(gè)功能對(duì)比圖
1、@ConfigurationProperties只需要寫(xiě)一次即可 , @Value則需要每個(gè)字段都添加
2、松散綁定:這個(gè)什么意思呢? 比如我的yml中寫(xiě)的last-name,這個(gè)和lastName是一樣的, - 后面跟著的字母默認(rèn)是大寫(xiě)的。這就是松散綁定。可以測(cè)試一下
3、JSR303數(shù)據(jù)校驗(yàn) , 這個(gè)就是我們可以在字段是增加一層過(guò)濾器驗(yàn)證 , 可以保證數(shù)據(jù)的合法性
4、復(fù)雜類(lèi)型封裝,yml中可以封裝對(duì)象 , 使用value就不支持
結(jié)論:
配置yml和配置properties都可以獲取到值 , 強(qiáng)烈推薦 yml;
如果我們?cè)谀硞€(gè)業(yè)務(wù)中,只需要獲取配置文件中的某個(gè)值,可以使用一下 @value;
如果說(shuō),我們專門(mén)編寫(xiě)了一個(gè)JavaBean來(lái)和配置文件進(jìn)行一一映射,就直接@configurationProperties,不要猶豫!
JSR303數(shù)據(jù)校驗(yàn)
報(bào)紅
<!--@Email注解報(bào)紅 是因?yàn)樾掳姹拘枰獀alidation啟動(dòng)器 新的springBoot版本得導(dǎo)入spring-boot-starter-validation依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>注解
@NotNull(message="名字不能為空") private String userName; @Max(value=120,message="年齡最大不能查過(guò)120") private int age; @Email(message="郵箱格式錯(cuò)誤") private String email;空檢查 @Null 驗(yàn)證對(duì)象是否為null @NotNull 驗(yàn)證對(duì)象是否不為null, 無(wú)法查檢長(zhǎng)度為0的字符串 @NotBlank 檢查約束字符串是不是Null還有被Trim的長(zhǎng)度是否大于0,只對(duì)字符串,且會(huì)去掉前后空格. @NotEmpty 檢查約束元素是否為NULL或者是EMPTY.Booelan檢查 @AssertTrue 驗(yàn)證 Boolean 對(duì)象是否為 true @AssertFalse 驗(yàn)證 Boolean 對(duì)象是否為 false 長(zhǎng)度檢查 @Size(min=, max=) 驗(yàn)證對(duì)象(Array,Collection,Map,String)長(zhǎng)度是否在給定的范圍之內(nèi) @Length(min=, max=) string is between min and max included.日期檢查 @Past 驗(yàn)證 Date 和 Calendar 對(duì)象是否在當(dāng)前時(shí)間之前 @Future 驗(yàn)證 Date 和 Calendar 對(duì)象是否在當(dāng)前時(shí)間之后 @Pattern 驗(yàn)證 String 對(duì)象是否符合正則表達(dá)式的規(guī)則 正則表達(dá)式.......等等 除此以外,我們還可以自定義一些數(shù)據(jù)校驗(yàn)規(guī)則環(huán)境配置位置和優(yōu)先級(jí)
優(yōu)先級(jí)由高到低
多環(huán)境切換
properties如何切換
application.properties
# springboot的多環(huán)境配置,可以選擇激活哪一個(gè)配置文件 spring.profiles.active = test #-后面的 # 使用application-test.properties配置文件application-dev.properties
application-test.properties
yaml
server:port: 8081 spring:profiles:active: dev--- server:port: 8082 spring:profiles: dev --- server:port: 8083 spring:profiles: test分析自動(dòng)配置原理
我們以**HttpEncodingAutoConfiguration(Http編碼自動(dòng)配置)**為例解釋自動(dòng)配置原理;
//表示這是一個(gè)配置類(lèi),和以前編寫(xiě)的配置文件一樣,也可以給容器中添加組件; @Configuration //啟動(dòng)指定類(lèi)的ConfigurationProperties功能;//進(jìn)入這個(gè)HttpProperties查看,將配置文件中對(duì)應(yīng)的值和HttpProperties綁定起來(lái);//并把HttpProperties加入到ioc容器中 @EnableConfigurationProperties({HttpProperties.class}) //Spring底層@Conditional注解//根據(jù)不同的條件判斷,如果滿足指定的條件,整個(gè)配置類(lèi)里面的配置就會(huì)生效;//這里的意思就是判斷當(dāng)前應(yīng)用是否是web應(yīng)用,如果是,當(dāng)前配置類(lèi)生效 @ConditionalOnWebApplication(type = Type.SERVLET )//判斷當(dāng)前項(xiàng)目有沒(méi)有這個(gè)類(lèi)CharacterEncodingFilter;SpringMVC中進(jìn)行亂碼解決的過(guò)濾器; @ConditionalOnClass({CharacterEncodingFilter.class})//判斷配置文件中是否存在某個(gè)配置:spring.http.encoding.enabled;//如果不存在,判斷也是成立的//即使我們配置文件中不配置pring.http.encoding.enabled=true,也是默認(rèn)生效的; @ConditionalOnProperty(prefix = "spring.http.encoding",value = {"enabled"},matchIfMissing = true )public class HttpEncodingAutoConfiguration {//他已經(jīng)和SpringBoot的配置文件映射了private final Encoding properties;//只有一個(gè)有參構(gòu)造器的情況下,參數(shù)的值就會(huì)從容器中拿public HttpEncodingAutoConfiguration(HttpProperties properties) {this.properties = properties.getEncoding();}//給容器中添加一個(gè)組件,這個(gè)組件的某些值需要從properties中獲取@Bean@ConditionalOnMissingBean //判斷容器沒(méi)有這個(gè)組件?public CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));return filter;}//。。。。。。。 }一句話總結(jié) :根據(jù)當(dāng)前不同的條件判斷,決定這個(gè)配置類(lèi)是否生效!
- 一但這個(gè)配置類(lèi)生效;這個(gè)配置類(lèi)就會(huì)給容器中添加各種組件;
- 這些組件的屬性是從對(duì)應(yīng)的properties類(lèi)中獲取的,這些類(lèi)里面的每一個(gè)屬性又是和配置文件綁定的;
- 所有在配置文件中能配置的屬性都是在xxxxProperties類(lèi)中封裝著;
- 配置文件能配置什么就可以參照某個(gè)功能對(duì)應(yīng)的這個(gè)屬性類(lèi)
我們?nèi)ヅ渲梦募锩嬖囋嚽熬Y,看提示!
這就是自動(dòng)裝配的原理!
精髓
1、SpringBoot啟動(dòng)會(huì)加載大量的自動(dòng)配置類(lèi)
2、我們看我們需要的功能有沒(méi)有在SpringBoot默認(rèn)寫(xiě)好的自動(dòng)配置類(lèi)當(dāng)中;
3、我們?cè)賮?lái)看這個(gè)自動(dòng)配置類(lèi)中到底配置了哪些組件;(只要我們要用的組件存在在其中,我們就不需要再手動(dòng)配置了)
4、給容器中自動(dòng)配置類(lèi)添加組件的時(shí)候,會(huì)從properties類(lèi)中獲取某些屬性。我們只需要在配置文件中指定這些屬性的值即可;
**xxxxAutoConfigurartion:自動(dòng)配置類(lèi);**給容器中添加組件
xxxxProperties:封裝配置文件中相關(guān)屬性;和我們的配置文件綁定 就可以在自己的配置文件中配置了
了解:@Conditional
了解完自動(dòng)裝配的原理后,我們來(lái)關(guān)注一個(gè)細(xì)節(jié)問(wèn)題,自動(dòng)配置類(lèi)必須在一定的條件下才能生效;
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置配里面的所有內(nèi)容才生效;
那么多的自動(dòng)配置類(lèi),必須在一定的條件下才能生效;也就是說(shuō),我們加載了這么多的配置類(lèi),但不是所有的都生效了。
我們?cè)趺粗滥男┳詣?dòng)配置類(lèi)生效?
我們可以通過(guò)啟用 debug=true屬性;來(lái)讓控制臺(tái)打印自動(dòng)配置報(bào)告,這樣我們就可以很方便的知道哪些自動(dòng)配置類(lèi)生效;
#開(kāi)啟springboot的調(diào)試類(lèi) debug=truePositive matches:(自動(dòng)配置類(lèi)啟用的:正匹配)
Negative matches:(沒(méi)有啟動(dòng),沒(méi)有匹配成功的自動(dòng)配置類(lèi):負(fù)匹配)
Unconditional classes: (沒(méi)有條件的類(lèi))
【演示:查看輸出的日志】
掌握吸收理解原理,即可以不變應(yīng)萬(wàn)變!
SpringBoot Web開(kāi)發(fā)
靜態(tài)資源
可以獲取靜態(tài)資源的地方 按照優(yōu)先級(jí)順序排序
獲取方式:webjars 里面通過(guò)pom導(dǎo)入maven包
只需輸入http://localhost:8080/webjars/jquery/4.1.3/jquery.js
總結(jié):
1.在springboot,我們可以使用以下方式處理靜態(tài)資源
? public,static,/**,resources `localhost:8080/ ``
自定義靜態(tài)資源路徑
我們也可以自己通過(guò)配置文件來(lái)指定一下,哪些文件夾是需要我們放靜態(tài)資源文件的,在application.properties中配置;
spring.mvc.static-path-pattern=/hello/,classpath:/kuang/一旦自己定義了靜態(tài)文件夾的路徑,原來(lái)的自動(dòng)配置就都會(huì)失效了!
首頁(yè)如何定制
靜態(tài)資源文件夾說(shuō)完后,我們繼續(xù)向下看源碼!可以看到一個(gè)歡迎頁(yè)的映射,就是我們的首頁(yè)!
@Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,FormattingConversionService mvcConversionService,ResourceUrlProvider mvcResourceUrlProvider) {WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), // getWelcomePage 獲得歡迎頁(yè)this.mvcProperties.getStaticPathPattern());welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));return welcomePageHandlerMapping; }點(diǎn)進(jìn)去繼續(xù)看
private Optional<Resource> getWelcomePage() {String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());// ::是java8 中新引入的運(yùn)算符// Class::function的時(shí)候function是屬于Class的,應(yīng)該是靜態(tài)方法。// this::function的funtion是屬于這個(gè)對(duì)象的。// 簡(jiǎn)而言之,就是一種語(yǔ)法糖而已,是一種簡(jiǎn)寫(xiě)return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst(); } // 歡迎頁(yè)就是一個(gè)location下的的 index.html 而已 private Resource getIndexHtml(String location) {return this.resourceLoader.getResource(location + "index.html"); }歡迎頁(yè),靜態(tài)資源文件夾下的所有 index.html 頁(yè)面;被 /** 映射。
比如我訪問(wèn) http://localhost:8080/ ,就會(huì)找靜態(tài)資源文件夾下的 index.html
新建一個(gè) index.html ,在我們上面的3個(gè)目錄中任意一個(gè);然后訪問(wèn)測(cè)試 http://localhost:8080/ 看結(jié)果!
低版本有,高版本沒(méi)有了 2.1.7有 2.2.0就沒(méi)有了
與其他靜態(tài)資源一樣,Spring Boot在配置的靜態(tài)內(nèi)容位置中查找 favicon.ico。如果存在這樣的文件,它將自動(dòng)用作應(yīng)用程序的favicon。
1、關(guān)閉SpringBoot默認(rèn)圖標(biāo)
#關(guān)閉默認(rèn)圖標(biāo) spring.mvc.favicon.enabled=false2、自己放一個(gè)圖標(biāo)在靜態(tài)資源目錄下,我放在 public 目錄下
3、清除瀏覽器緩存!刷新網(wǎng)頁(yè),發(fā)現(xiàn)圖標(biāo)已經(jīng)變成自己的了!
Thymeleaf模板引擎
模板引擎
前端交給我們的頁(yè)面,是html頁(yè)面。如果是我們以前開(kāi)發(fā),我們需要把他們轉(zhuǎn)成jsp頁(yè)面,jsp好處就是當(dāng)我們查出一些數(shù)據(jù)轉(zhuǎn)發(fā)到JSP頁(yè)面以后,我們可以用jsp輕松實(shí)現(xiàn)數(shù)據(jù)的顯示,及交互等。jsp支持非常強(qiáng)大的功能,包括能寫(xiě)Java代碼,但是呢,我們現(xiàn)在的這種情況,SpringBoot這個(gè)項(xiàng)目首先是以jar的方式,不是war,像第二,我們用的還是嵌入式的Tomcat,所以呢,他現(xiàn)在默認(rèn)是不支持jsp的。
那不支持jsp,如果我們直接用純靜態(tài)頁(yè)面的方式,那給我們開(kāi)發(fā)會(huì)帶來(lái)非常大的麻煩,那怎么辦呢,SpringBoot推薦你可以來(lái)使用模板引擎。
那么這模板引擎,我們其實(shí)大家聽(tīng)到很多,其實(shí)jsp就是一個(gè)模板引擎,還有以用的比較多的freemarker,包括SpringBoot給我們推薦的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他們的思想都是一樣的,什么樣一個(gè)思想呢我們來(lái)看一下這張圖。
模板引擎的作用就是我們來(lái)寫(xiě)一個(gè)頁(yè)面模板,比如有些值呢,是動(dòng)態(tài)的,我們寫(xiě)一些表達(dá)式。而這些值,從哪來(lái)呢,就是我們?cè)诤笈_(tái)封裝一些數(shù)據(jù)。然后把這個(gè)模板和這個(gè)數(shù)據(jù)交給我們模板引擎,模板引擎按照我們這個(gè)數(shù)據(jù)幫你把這表達(dá)式解析、填充到我們指定的位置,然后把這個(gè)數(shù)據(jù)最終生成一個(gè)我們想要的內(nèi)容給我們寫(xiě)出去,這就是我們這個(gè)模板引擎,不管是jsp還是其他模板引擎,都是這個(gè)思想。只不過(guò)呢,就是說(shuō)不同模板引擎之間,他們可能這個(gè)語(yǔ)法有點(diǎn)不一樣。其他的我就不介紹了,我主要來(lái)介紹一下SpringBoot給我們推薦的Thymeleaf模板引擎,這模板引擎呢,是一個(gè)高級(jí)語(yǔ)言的模板引擎,他的這個(gè)語(yǔ)法更簡(jiǎn)單。而且呢,功能更強(qiáng)大。
我們呢,就來(lái)看一下這個(gè)模板引擎,那既然要看這個(gè)模板引擎。首先,我們來(lái)看SpringBoot里邊怎么用。
引入Thymeleaf
怎么引入呢,對(duì)于springboot來(lái)說(shuō),什么事情不都是一個(gè)start的事情嘛,我們?nèi)ピ陧?xiàng)目中引入一下。給大家三個(gè)網(wǎng)址:
Thymeleaf 官網(wǎng):https://www.thymeleaf.org/
Thymeleaf 在Github 的主頁(yè):https://github.com/thymeleaf/thymeleaf
Spring官方文檔:找到我們對(duì)應(yīng)的版本
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
找到對(duì)應(yīng)的pom依賴:可以適當(dāng)點(diǎn)進(jìn)源碼看下本來(lái)的包!
<!--thymeleaf--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-java8time</artifactId></dependency>Maven會(huì)自動(dòng)下載jar包,我們可以去看下下載的東西;
分析Thymeleaf
首先得按照SpringBoot的自動(dòng)配置原理看一下我們這個(gè)Thymeleaf的自動(dòng)配置規(guī)則,在按照那個(gè)規(guī)則,我們進(jìn)行使用。
我們?nèi)フ乙幌耇hymeleaf的自動(dòng)配置類(lèi):ThymeleafProperties
@ConfigurationProperties(prefix = "spring.thymeleaf" ) public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING;public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";private boolean checkTemplate = true;private boolean checkTemplateLocation = true;private String prefix = "classpath:/templates/";private String suffix = ".html";private String mode = "HTML";private Charset encoding; }我們可以在其中看到默認(rèn)的前綴和后綴!
我們只需要把我們的html頁(yè)面放在類(lèi)路徑下的templates下,thymeleaf就可以幫我們自動(dòng)渲染了。
使用thymeleaf什么都不需要配置,只需要將他放在指定的文件夾下即可!
測(cè)試
1、編寫(xiě)一個(gè)TestController
@Controller public class TestController {@RequestMapping("/t1")public String test1(){//classpath:/templates/test.htmlreturn "test";}}2、編寫(xiě)一個(gè)測(cè)試頁(yè)面 test.html 放在 templates 目錄下
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h1>測(cè)試頁(yè)面</h1></body> </html>3、啟動(dòng)項(xiàng)目請(qǐng)求測(cè)試
Thymeleaf語(yǔ)法
學(xué)習(xí)語(yǔ)法,還是參考官網(wǎng)文檔最為準(zhǔn)確,我們找到對(duì)應(yīng)的版本看一下;
Thymeleaf 官網(wǎng):https://www.thymeleaf.org/ , 簡(jiǎn)單看一下官網(wǎng)!我們?nèi)ハ螺dThymeleaf的官方文檔!
我們做個(gè)最簡(jiǎn)單的練習(xí) :我們需要查出一些數(shù)據(jù),在頁(yè)面中展示
1、修改測(cè)試請(qǐng)求,增加數(shù)據(jù)傳輸;
@RequestMapping("/t1") public String test1(Model model){//存入數(shù)據(jù)model.addAttribute("msg","Hello,Thymeleaf");//classpath:/templates/test.htmlreturn "test"; }2、我們要使用thymeleaf,需要在html文件中導(dǎo)入命名空間的約束,方便提示。
我們可以去官方文檔的#3中看一下命名空間拿來(lái)過(guò)來(lái):
xmlns:th="http://www.thymeleaf.org"3、我們?nèi)ゾ帉?xiě)下前端頁(yè)面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>狂神說(shuō)</title> </head> <body> <h1>測(cè)試頁(yè)面</h1><!--th:text就是將div中的內(nèi)容設(shè)置為它指定的值,和之前學(xué)習(xí)的Vue一樣--> <div th:text="${msg}"></div> </body> </html>4、啟動(dòng)測(cè)試!
認(rèn)真學(xué)習(xí)語(yǔ)法
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-04DJdgBA-1621008881187)(SpringBoot.assets/image-20201217210034131.png)]
能寫(xiě)哪些表達(dá)式
Simple expressions:(表達(dá)式語(yǔ)法) Variable Expressions: ${...}:獲取變量值;OGNL;1)、獲取對(duì)象的屬性、調(diào)用方法2)、使用內(nèi)置的基本對(duì)象:#18#ctx : the context object.#vars: the context variables.#locale : the context locale.#request : (only in Web Contexts) the HttpServletRequest object.#response : (only in Web Contexts) the HttpServletResponse object.#session : (only in Web Contexts) the HttpSession object.#servletContext : (only in Web Contexts) the ServletContext object.3)、內(nèi)置的一些工具對(duì)象:#execInfo : information about the template being processed.#uris : methods for escaping parts of URLs/URIs#conversions : methods for executing the configured conversion service (if any).#dates : methods for java.util.Date objects: formatting, component extraction, etc.#calendars : analogous to #dates , but for java.util.Calendar objects.#numbers : methods for formatting numeric objects.#strings : methods for String objects: contains, startsWith, prepending/appending, etc.#objects : methods for objects in general.#bools : methods for boolean evaluation.#arrays : methods for arrays.#lists : methods for lists.#sets : methods for sets.#maps : methods for maps.#aggregates : methods for creating aggregates on arrays or collections. ==================================================================================Selection Variable Expressions: *{...}:選擇表達(dá)式:和${}在功能上是一樣;Message Expressions: #{...}:獲取國(guó)際化內(nèi)容Link URL Expressions: @{...}:定義URL;Fragment Expressions: ~{...}:片段引用表達(dá)式Literals(字面量)Text literals: 'one text' , 'Another one!' ,…Number literals: 0 , 34 , 3.0 , 12.3 ,…Boolean literals: true , falseNull literal: nullLiteral tokens: one , sometext , main ,…Text operations:(文本操作)String concatenation: +Literal substitutions: |The name is ${name}|Arithmetic operations:(數(shù)學(xué)運(yùn)算)Binary operators: + , - , * , / , %Minus sign (unary operator): -Boolean operations:(布爾運(yùn)算)Binary operators: and , orBoolean negation (unary operator): ! , notComparisons and equality:(比較運(yùn)算)Comparators: > , < , >= , <= ( gt , lt , ge , le )Equality operators: == , != ( eq , ne )Conditional operators:條件運(yùn)算(三元運(yùn)算符)If-then: (if) ? (then)If-then-else: (if) ? (then) : (else)Default: (value) ?: (defaultvalue)Special tokens:No-Operation: _SpringMVC配置
官網(wǎng)閱讀
在進(jìn)行項(xiàng)目編寫(xiě)前,我們還需要知道一個(gè)東西,就是SpringBoot對(duì)我們的SpringMVC還做了哪些配置,包括如何擴(kuò)展,如何定制。
只有把這些都搞清楚了,我們?cè)谥笫褂貌艜?huì)更加得心應(yīng)手。途徑一:源碼分析,途徑二:官方文檔!
地址 :https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration
Spring MVC Auto-configuration // Spring Boot為Spring MVC提供了自動(dòng)配置,它可以很好地與大多數(shù)應(yīng)用程序一起工作。 Spring Boot provides auto-configuration for Spring MVC that works well with most applications. // 自動(dòng)配置在Spring默認(rèn)設(shè)置的基礎(chǔ)上添加了以下功能: The auto-configuration adds the following features on top of Spring’s defaults: // 包含視圖解析器 Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans. // 支持靜態(tài)資源文件夾的路徑,以及webjars Support for serving static resources, including support for WebJars // 自動(dòng)注冊(cè)了Converter: // 轉(zhuǎn)換器,這就是我們網(wǎng)頁(yè)提交數(shù)據(jù)到后臺(tái)自動(dòng)封裝成為對(duì)象的東西,比如把"1"字符串自動(dòng)轉(zhuǎn)換為int類(lèi)型 // Formatter:【格式化器,比如頁(yè)面給我們了一個(gè)2019-8-10,它會(huì)給我們自動(dòng)格式化為Date對(duì)象】 Automatic registration of Converter, GenericConverter, and Formatter beans. // HttpMessageConverters // SpringMVC用來(lái)轉(zhuǎn)換Http請(qǐng)求和響應(yīng)的的,比如我們要把一個(gè)User對(duì)象轉(zhuǎn)換為JSON字符串,可以去看官網(wǎng)文檔解釋; Support for HttpMessageConverters (covered later in this document). // 定義錯(cuò)誤代碼生成規(guī)則的 Automatic registration of MessageCodesResolver (covered later in this document). // 首頁(yè)定制 Static index.html support. // 圖標(biāo)定制 Custom Favicon support (covered later in this document). // 初始化數(shù)據(jù)綁定器:幫我們把請(qǐng)求數(shù)據(jù)綁定到JavaBean中! Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document)./* 如果您希望保留Spring Boot MVC功能,并且希望添加其他MVC配置(攔截器、格式化程序、視圖控制器和其他功能),則可以添加自己 的@configuration類(lèi),類(lèi)型為webmvcconfiguer,但不添加@EnableWebMvc。如果希望提供 RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定義 實(shí)例,則可以聲明WebMVCregistrationAdapter實(shí)例來(lái)提供此類(lèi)組件。 */ If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.// 如果您想完全控制Spring MVC,可以添加自己的@Configuration,并用@EnableWebMvc進(jìn)行注釋。 If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.ContentNegotiatingViewResolver 內(nèi)容協(xié)商視圖解析器
自動(dòng)配置了ViewResolver,就是我們之前學(xué)習(xí)的SpringMVC的視圖解析器;
即根據(jù)方法的返回值取得視圖對(duì)象(View),然后由視圖對(duì)象決定如何渲染(轉(zhuǎn)發(fā),重定向)。
我們?nèi)タ纯催@里的源碼:我們找到 WebMvcAutoConfiguration , 然后搜索ContentNegotiatingViewResolver。找到如下方法!
@Bean @ConditionalOnBean(ViewResolver.class) @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class) public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));// ContentNegotiatingViewResolver使用所有其他視圖解析器來(lái)定位視圖,因此它應(yīng)該具有較高的優(yōu)先級(jí)resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);return resolver; }點(diǎn)進(jìn)這類(lèi)看看!找到對(duì)應(yīng)的解析視圖的代碼;
getCandidateViews中看到他是把所有的視圖解析器拿來(lái),進(jìn)行while循環(huán),挨個(gè)解析!
Iterator var5 = this.viewResolvers.iterator();得出結(jié)論:ContentNegotiatingViewResolver 這個(gè)視圖解析器就是用來(lái)組合所有的視圖解析器的
我們?cè)偃パ芯肯滤慕M合邏輯,看到有個(gè)屬性viewResolvers,看看它是在哪里進(jìn)行賦值的!
protected void initServletContext(ServletContext servletContext) {// 這里它是從beanFactory工具中獲取容器中的所有視圖解析器// ViewRescolver.class 把所有的視圖解析器來(lái)組合的Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();ViewResolver viewResolver;if (this.viewResolvers == null) {this.viewResolvers = new ArrayList(matchingBeans.size());}// ............... }既然它是在容器中去找視圖解析器,我們是否可以猜想,我們就可以去實(shí)現(xiàn)一個(gè)視圖解析器了呢?
我們可以自己給容器中去添加一個(gè)視圖解析器;這個(gè)類(lèi)就會(huì)幫我們自動(dòng)的將它組合進(jìn)來(lái);我們?nèi)?shí)現(xiàn)一下
1、我們?cè)谖覀兊闹鞒绦蛑腥?xiě)一個(gè)視圖解析器來(lái)試試;
@Bean //放到bean中 public ViewResolver myViewResolver(){return new MyViewResolver(); }//我們寫(xiě)一個(gè)靜態(tài)內(nèi)部類(lèi),視圖解析器就需要實(shí)現(xiàn)ViewResolver接口 private static class MyViewResolver implements ViewResolver{@Overridepublic View resolveViewName(String s, Locale locale) throws Exception {return null;} }2、怎么看我們自己寫(xiě)的視圖解析器有沒(méi)有起作用呢?
我們給 DispatcherServlet 中的 doDispatch方法 加個(gè)斷點(diǎn)進(jìn)行調(diào)試一下,因?yàn)樗械恼?qǐng)求都會(huì)走到這個(gè)方法中
3、我們啟動(dòng)我們的項(xiàng)目,然后隨便訪問(wèn)一個(gè)頁(yè)面,看一下Debug信息;
找到this
找到視圖解析器,我們看到我們自己定義的就在這里了;
所以說(shuō),我們?nèi)绻胍褂米约憾ㄖ苹臇|西,我們只需要給容器中添加這個(gè)組件就好了!剩下的事情SpringBoot就會(huì)幫我們做了!
修改SpringBoot的默認(rèn)配置
這么多的自動(dòng)配置,原理都是一樣的,通過(guò)這個(gè)WebMVC的自動(dòng)配置原理分析,我們要學(xué)會(huì)一種學(xué)習(xí)方式,通過(guò)源碼探究,得出結(jié)論;這個(gè)結(jié)論一定是屬于自己的,而且一通百通。
SpringBoot的底層,大量用到了這些設(shè)計(jì)細(xì)節(jié)思想,所以,沒(méi)事需要多閱讀源碼!得出結(jié)論;
SpringBoot在自動(dòng)配置很多組件的時(shí)候,先看容器中有沒(méi)有用戶自己配置的(如果用戶自己配置@bean),如果有就用用戶配置的,如果沒(méi)有就用自動(dòng)配置的;
如果有些組件可以存在多個(gè),比如我們的視圖解析器,就將用戶配置的和自己默認(rèn)的組合起來(lái)!
擴(kuò)展使用SpringMVC 官方文檔如下:
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
我們要做的就是編寫(xiě)一個(gè)@Configuration注解類(lèi),并且類(lèi)型要為WebMvcConfigurer,還不能標(biāo)注@EnableWebMvc注解;我們?nèi)プ约簩?xiě)一個(gè);我們新建一個(gè)包叫config,寫(xiě)一個(gè)類(lèi)MyMvcConfig;
//應(yīng)為類(lèi)型要求為WebMvcConfigurer,所以我們實(shí)現(xiàn)其接口 //可以使用自定義類(lèi)擴(kuò)展MVC的功能 @Configuration public class MyMvcConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {// 瀏覽器發(fā)送/test , 就會(huì)跳轉(zhuǎn)到test頁(yè)面;registry.addViewController("/test").setViewName("test");} }確實(shí)也跳轉(zhuǎn)過(guò)來(lái)了!所以說(shuō),我們要擴(kuò)展SpringMVC,官方就推薦我們這么去使用,既保SpringBoot留所有的自動(dòng)配置,也能用我們擴(kuò)展的配置!
我們可以去分析一下原理:
1、WebMvcAutoConfiguration 是 SpringMVC的自動(dòng)配置類(lèi),里面有一個(gè)類(lèi)WebMvcAutoConfigurationAdapter
2、這個(gè)類(lèi)上有一個(gè)注解,在做其他自動(dòng)配置時(shí)會(huì)導(dǎo)入:@Import(EnableWebMvcConfiguration.class)
3、我們點(diǎn)進(jìn)EnableWebMvcConfiguration這個(gè)類(lèi)看一下,它繼承了一個(gè)父類(lèi):DelegatingWebMvcConfiguration
這個(gè)父類(lèi)中有這樣一段代碼:
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();// 從容器中獲取所有的webmvcConfigurer@Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);}} }4、我們可以在這個(gè)類(lèi)中去尋找一個(gè)我們剛才設(shè)置的viewController當(dāng)做參考,發(fā)現(xiàn)它調(diào)用了一個(gè)
protected void addViewControllers(ViewControllerRegistry registry) {this.configurers.addViewControllers(registry); }5、我們點(diǎn)進(jìn)去看一下
public void addViewControllers(ViewControllerRegistry registry) {Iterator var2 = this.delegates.iterator();while(var2.hasNext()) {// 將所有的WebMvcConfigurer相關(guān)配置來(lái)一起調(diào)用!包括我們自己配置的和Spring給我們配置的WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();delegate.addViewControllers(registry);}}所以得出結(jié)論:所有的WebMvcConfiguration都會(huì)被作用,不止Spring自己的配置類(lèi),我們自己的配置類(lèi)當(dāng)然也會(huì)被調(diào)用;
全面接管SpringMVC
官方文檔:
If you want to take complete control of Spring MVCyou can add your own @Configuration annotated with @EnableWebMvc.全面接管即:SpringBoot對(duì)SpringMVC的自動(dòng)配置不需要了,所有都是我們自己去配置!
只需在我們的配置類(lèi)中要加一個(gè)@EnableWebMvc。
我們看下如果我們?nèi)娼庸芰薙pringMVC了,我們之前SpringBoot給我們配置的靜態(tài)資源映射一定會(huì)無(wú)效,我們可以去測(cè)試一下;
不加注解之前,訪問(wèn)首頁(yè):
給配置類(lèi)加上注解:@EnableWebMvc
我們發(fā)現(xiàn)所有的SpringMVC自動(dòng)配置都失效了!回歸到了最初的樣子;
當(dāng)然,我們開(kāi)發(fā)中,不推薦使用全面接管SpringMVC
思考問(wèn)題?為什么加了一個(gè)注解,自動(dòng)配置就失效了!我們看下源碼:
1、這里發(fā)現(xiàn)它是導(dǎo)入了一個(gè)類(lèi),我們可以繼續(xù)進(jìn)去看
@Import({DelegatingWebMvcConfiguration.class}) public @interface EnableWebMvc { }2、它繼承了一個(gè)父類(lèi) WebMvcConfigurationSupport
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {// ...... } @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) // 這個(gè)注解的意思就是:容器中沒(méi)有這個(gè)組件的時(shí)候,這個(gè)自動(dòng)配置類(lèi)才生效 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {}總結(jié)一句話:@EnableWebMvc將WebMvcConfigurationSupport組件導(dǎo)入進(jìn)來(lái)了;
而導(dǎo)入的WebMvcConfigurationSupport只是SpringMVC最基本的功能!
在springboot中,有非常多的xxxx Configuration幫助我們進(jìn)行擴(kuò)展配置,只要看見(jiàn)了這個(gè)東西,我們就要注意了!
Springboot項(xiàng)目
首頁(yè)
首頁(yè)配置,所有的頁(yè)面靜態(tài)資源都需要被Thymeleaf接管 @{} href src等等
國(guó)際化
2020版本idea可視化配置有問(wèn)題
返不回去的話點(diǎn)上面的index 再點(diǎn)下面的text就可以返回了
在Spring中有一個(gè)國(guó)際化的Locale (區(qū)域信息對(duì)象);里面有一個(gè)叫做LocaleResolver (獲取區(qū)域信息對(duì)象)的解析器!
我們?nèi)ノ覀僿ebmvc自動(dòng)配置文件,尋找一下!看到SpringBoot默認(rèn)配置:
@Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = "spring.mvc", name = "locale") public LocaleResolver localeResolver() {// 容器中沒(méi)有就自己配,有的話就用用戶配置的if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {return new FixedLocaleResolver(this.mvcProperties.getLocale());}// 接收頭國(guó)際化分解AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();localeResolver.setDefaultLocale(this.mvcProperties.getLocale());return localeResolver; }AcceptHeaderLocaleResolver 這個(gè)類(lèi)中有一個(gè)方法
public Locale resolveLocale(HttpServletRequest request) {Locale defaultLocale = this.getDefaultLocale();// 默認(rèn)的就是根據(jù)請(qǐng)求頭帶來(lái)的區(qū)域信息獲取Locale進(jìn)行國(guó)際化if (defaultLocale != null && request.getHeader("Accept-Language") == null) {return defaultLocale;} else {Locale requestLocale = request.getLocale();List<Locale> supportedLocales = this.getSupportedLocales();if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);if (supportedLocale != null) {return supportedLocale;} else {return defaultLocale != null ? defaultLocale : requestLocale;}} else {return requestLocale;}} }分析之后可以自己寫(xiě)一個(gè)
整個(gè)過(guò)程
自動(dòng)配置會(huì)根據(jù)我們的環(huán)境來(lái)更改語(yǔ)言,比較高級(jí) 使用#{}來(lái)取值 如下圖
攔截器
LoginHandleInterceptor.java
public class LoginHandleInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//登錄成功之后,應(yīng)該有用戶的sessionObject loginUsername = request.getSession().getAttribute("loginUsername");if (loginUsername==null){//沒(méi)有登錄request.setAttribute("msg","沒(méi)有權(quán)限,請(qǐng)先登錄");request.getRequestDispatcher("/index.html").forward(request,response);return false;}else {return true;}} }在MyMvcConfig中配置 注意過(guò)濾靜態(tài)資源
@Override public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginHandleInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login","/css/**","/js/**","/img/**"); }頁(yè)面公共部分抽取
th:fragment="sidebar" 定義抽取部分的名字引用頁(yè)面部分的時(shí)候要用~{頁(yè)面名::頁(yè)面部分名} 注意路徑要正確完整
<div th:insert="~{dashboard::sidebar} "></div>提取公共界面 傳參高亮
<div th:replace="~{common/commons::sidebar(active='main.html')}"></div>獲取參數(shù) 判斷 賦值不一樣的class
<a th:class="${active=='main.html'?'nav-link active':'nav-link'}" th:href="@{/dashboard}"></a>thymeleaf模板中insert/include/replace三種引用fragment方式的區(qū)別
insert: 把整個(gè)fragment(包括fragment的節(jié)點(diǎn)tag)插入到當(dāng)前節(jié)點(diǎn)內(nèi)部,
replace:用fragment(包括fragment的節(jié)點(diǎn)tag)替換掉當(dāng)前節(jié)點(diǎn)
include:把fragment的內(nèi)容(不包括fragment的節(jié)點(diǎn))插入到當(dāng)前節(jié)點(diǎn)內(nèi)容
CRUD
注意參數(shù)傳遞,取值,放值等問(wèn)題。
404
在template文件夾下面新建一個(gè)error文件夾 把錯(cuò)誤界面放進(jìn)去就可以自動(dòng)找到了
把對(duì)應(yīng)的錯(cuò)誤界面放進(jìn)去就可以了
如何寫(xiě)網(wǎng)站
1.前端搞定:頁(yè)面長(zhǎng)什么樣子:數(shù)據(jù)
2.設(shè)計(jì)教據(jù)庫(kù)(數(shù)據(jù)庫(kù)設(shè)計(jì)難點(diǎn)!
3.前端讓他能夠自動(dòng)運(yùn)行,獨(dú)立化工程
4.數(shù)據(jù)接口如何對(duì)接: json,對(duì)象all in one !
5.前后端聯(lián)調(diào)測(cè)試!
數(shù)據(jù)庫(kù) Druid
spring Data簡(jiǎn)介
對(duì)于數(shù)據(jù)訪問(wèn)層,無(wú)論是 SQL(關(guān)系型數(shù)據(jù)庫(kù)) 還是 NOSQL(非關(guān)系型數(shù)據(jù)庫(kù)),Spring Boot 底層都是采用 Spring Data 的方式進(jìn)行統(tǒng)一處理。
Spring Boot 底層都是采用 Spring Data 的方式進(jìn)行統(tǒng)一處理各種數(shù)據(jù)庫(kù),Spring Data 也是 Spring 中與 Spring Boot、Spring Cloud 等齊名的知名項(xiàng)目。
Sping Data 官網(wǎng):https://spring.io/projects/spring-data
數(shù)據(jù)庫(kù)相關(guān)的啟動(dòng)器 :可以參考官方文檔:
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
JDBCTemplate
1、有了數(shù)據(jù)源(com.zaxxer.hikari.HikariDataSource),然后可以拿到數(shù)據(jù)庫(kù)連接(java.sql.Connection),有了連接,就可以使用原生的 JDBC 語(yǔ)句來(lái)操作數(shù)據(jù)庫(kù);
2、即使不使用第三方第數(shù)據(jù)庫(kù)操作框架,如 MyBatis等,Spring 本身也對(duì)原生的JDBC 做了輕量級(jí)的封裝,即JdbcTemplate。
3、數(shù)據(jù)庫(kù)操作的所有 CRUD 方法都在 JdbcTemplate 中。
4、Spring Boot 不僅提供了默認(rèn)的數(shù)據(jù)源,同時(shí)默認(rèn)已經(jīng)配置好了 JdbcTemplate 放在了容器中,程序員只需自己注入即可使用
5、JdbcTemplate 的自動(dòng)配置是依賴 org.springframework.boot.autoconfigure.jdbc 包下的 JdbcTemplateConfiguration 類(lèi)
JdbcTemplate主要提供以下幾類(lèi)方法:
- execute方法:可以用于執(zhí)行任何SQL語(yǔ)句,一般用于執(zhí)行DDL語(yǔ)句;
- update方法及batchUpdate方法:update方法用于執(zhí)行新增、修改、刪除等語(yǔ)句;batchUpdate方法用于執(zhí)行批處理相關(guān)語(yǔ)句;
- query方法及queryForXXX方法:用于執(zhí)行查詢相關(guān)語(yǔ)句;
- call方法:用于執(zhí)行存儲(chǔ)過(guò)程、函數(shù)相關(guān)語(yǔ)句。
Druid
簡(jiǎn)介
Java程序很大一部分要操作數(shù)據(jù)庫(kù),為了提高性能操作數(shù)據(jù)庫(kù)的時(shí)候,又不得不使用數(shù)據(jù)庫(kù)連接池。
Druid 是阿里巴巴開(kāi)源平臺(tái)上一個(gè)數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn),結(jié)合了 C3P0、DBCP 等 DB 池的優(yōu)點(diǎn),同時(shí)加入了日志監(jiān)控。
Druid 可以很好的監(jiān)控 DB 池連接和 SQL 的執(zhí)行情況,天生就是針對(duì)監(jiān)控而生的 DB 連接池。
Druid已經(jīng)在阿里巴巴部署了超過(guò)600個(gè)應(yīng)用,經(jīng)過(guò)一年多生產(chǎn)環(huán)境大規(guī)模部署的嚴(yán)苛考驗(yàn)。
Spring Boot 2.0 以上默認(rèn)使用 Hikari 數(shù)據(jù)源,可以說(shuō) Hikari 與 Driud 都是當(dāng)前 Java Web 上最優(yōu)秀的數(shù)據(jù)源,我們來(lái)重點(diǎn)介紹 Spring Boot 如何集成 Druid 數(shù)據(jù)源,如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)監(jiān)控。
Github地址:https://github.com/alibaba/druid/
com.alibaba.druid.pool.DruidDataSource 基本配置參數(shù)如下:
配置數(shù)據(jù)源
1、添加上 Druid 數(shù)據(jù)源依賴。 可以加上log4j
<!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.4</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>2、切換數(shù)據(jù)源;之前已經(jīng)說(shuō)過(guò) Spring Boot 2.0 以上默認(rèn)使用 com.zaxxer.hikari.HikariDataSource 數(shù)據(jù)源,但可以 通過(guò) spring.datasource.type 指定數(shù)據(jù)源。
spring:datasource:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource # 自定義數(shù)據(jù)源3、數(shù)據(jù)源切換之后,在測(cè)試類(lèi)中注入 DataSource,然后獲取到它,輸出一看便知是否成功切換;
4、切換成功!既然切換成功,就可以設(shè)置數(shù)據(jù)源連接初始化大小、最大連接數(shù)、等待時(shí)間、最小連接數(shù) 等設(shè)置項(xiàng);可以查看源碼
spring:datasource:username: rootpassword: 123456#?serverTimezone=UTC解決時(shí)區(qū)的報(bào)錯(cuò)url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource#Spring Boot 默認(rèn)是不注入這些屬性值的,需要自己綁定#druid 數(shù)據(jù)源專有配置initialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#配置監(jiān)控統(tǒng)計(jì)攔截的filters,stat:監(jiān)控統(tǒng)計(jì)、log4j:日志記錄、wall:防御sql注入#如果允許時(shí)報(bào)錯(cuò) java.lang.ClassNotFoundException: org.apache.log4j.Priority#則導(dǎo)入 log4j 依賴即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4jfilters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5005、導(dǎo)入log4j
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version> </dependency>6、現(xiàn)在需要程序員自己為 DruidDataSource 綁定全局配置文件中的參數(shù),再添加到容器中,而不再使用 Spring Boot 的自動(dòng)生成了;我們需要 自己添加 DruidDataSource 組件到容器中,并綁定屬性;
配置Druid數(shù)據(jù)源監(jiān)控
Druid 數(shù)據(jù)源具有監(jiān)控的功能,并提供了一個(gè) web 界面方便用戶查看,類(lèi)似安裝 路由器 時(shí),人家也提供了一個(gè)默認(rèn)的 web 頁(yè)面。
所以第一步需要設(shè)置 Druid 的后臺(tái)管理頁(yè)面,比如 登錄賬號(hào)、密碼 等;配置后臺(tái)管理;
//配置 Druid 監(jiān)控管理后臺(tái)的Servlet; //內(nèi)置 Servlet 容器時(shí)沒(méi)有web.xml文件,所以使用 Spring Boot 的注冊(cè) Servlet 方式 @Bean public ServletRegistrationBean statViewServlet() {ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");// 這些參數(shù)可以在 com.alibaba.druid.support.http.StatViewServlet // 的父類(lèi) com.alibaba.druid.support.http.ResourceServlet 中找到Map<String, String> initParams = new HashMap<>();initParams.put("loginUsername", "admin"); //后臺(tái)管理界面的登錄賬號(hào)initParams.put("loginPassword", "123456"); //后臺(tái)管理界面的登錄密碼//后臺(tái)允許誰(shuí)可以訪問(wèn)//initParams.put("allow", "localhost"):表示只有本機(jī)可以訪問(wèn)//initParams.put("allow", ""):為空或者為null時(shí),表示允許所有訪問(wèn)initParams.put("allow", "");//deny:Druid 后臺(tái)拒絕誰(shuí)訪問(wèn)//initParams.put("kuangshen", "192.168.1.20");表示禁止此ip訪問(wèn)//設(shè)置初始化參數(shù)bean.setInitParameters(initParams);return bean; }配置完畢后,我們可以選擇訪問(wèn) :http://localhost:8080/druid/login.html
整合Mybatis
Mybatis啟動(dòng)器
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.1</version> </dependency>兩種表示這是一個(gè)mybatis的mapper類(lèi)
1、在mapper接口上添加注解@Mapper
2、在啟動(dòng)類(lèi)上加@MapperScan(“要掃描的包”) 比如com.can.mapper
Mybatis整合
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.1</version> </dependency> #整合Mybatis mybatis.type-aliases-package=com.can.pojo mybatis.mapper-locations=classpath:mybatis/mapper/*.xmlSpringSecurity(安全)
-
在web開(kāi)發(fā)中,安全第一位!過(guò)濾器,攔截器也可以實(shí)現(xiàn)
功能性需求:非功能性需求
做網(wǎng)站: 安全應(yīng)該在還說(shuō)呢么時(shí)候考慮? 設(shè)計(jì)之初
- 漏洞,隱私泄露~
- 架構(gòu)一旦確定,再加安全 就不容易了
shiro、SpringSecurity: 很像~除了類(lèi)不一樣,名字不一樣;認(rèn)證,授權(quán)
認(rèn)證,授權(quán)(vip1,vip2,vip3)權(quán)限不同
簡(jiǎn)介
Spring Security是針對(duì)Spring項(xiàng)目的安全框架,也是Spring Boot底層安全模塊默認(rèn)的技術(shù)選型,他可以實(shí)現(xiàn)強(qiáng)大的Web安全控制,對(duì)于安全控制,我們僅需要引入spring-boot-starter-security模塊,進(jìn)行少量的配置,即可實(shí)現(xiàn)強(qiáng)大的安全管理!
記住幾個(gè)類(lèi):
- WebSecurityConfigurerAdapter:自定義Security策略
- AuthenticationManagerBuilder:自定義認(rèn)證策略
- @EnableWebSecurity:開(kāi)啟WebSecurity模式
Spring Security的兩個(gè)主要目標(biāo)是“認(rèn)證”和“授權(quán)”(訪問(wèn)控制)。
“認(rèn)證”(Authentication)
“授權(quán)”(Authorization)
這個(gè)概念是通用的,而不是只在Spring security中存在。
參考官網(wǎng): https://spring.io/projects/spring-security。查看我們自己項(xiàng)目中的版本,找到對(duì)應(yīng)的幫助文檔:https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle
security和thymeleaf整合
<!--security和Thymeleaf整合包--> <!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 --> <dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity5</artifactId><version>3.0.4.RELEASE</version> </dependency>thymeleaf需要導(dǎo)入的東西<dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-java8time</artifactId></dependency>主要就是一下兩句有問(wèn)題導(dǎo)致報(bào)錯(cuò) 狂神角色寫(xiě)錯(cuò)了
用戶名:<span sec:authentication="name"></span> 角色:<span sec:authentication="authorities"></span>命名空間
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">springsecurity4不支持高版本 但是彈幕好像說(shuō)支持2.3.3
springsecurity4點(diǎn)擊注銷(xiāo) 會(huì)報(bào)錯(cuò) 因?yàn)閟pringsecurity4自動(dòng)開(kāi)啟了csrf功能
但是springsecurity5不用這個(gè)操作,據(jù)說(shuō)好像是logout的時(shí)候用了post傳輸,因?yàn)槭莂標(biāo)簽,舊版沒(méi)有做處理,只能用get傳輸。因?yàn)間et是明文傳輸,容易被攻擊,所以默認(rèn)開(kāi)啟了csrf。
//防止網(wǎng)站攻擊: get post //關(guān)閉csrf功能 http.csrf().disable();使用自己的登錄界面loginPage("/toLogin")自定義登錄請(qǐng)求。 .loginProcessingUrl("/login")自定義登錄請(qǐng)求接收
需要跟登錄頁(yè)提交的地址一致。
不用定義登錄請(qǐng)求接收的話需要將登錄表單提交到toLogin。
如果加了loginProcessingUrl的話 前端傳入的 用戶名不是username和密碼不是password的話會(huì)error
但是可以自定義接收屬性
.usernameParameter("user").passwordParameter("pwd")Shiro 安全 容易被面試提問(wèn)
官網(wǎng):http://shiro.apache.org/index.html
簡(jiǎn)介:
Shiro是Apache旗下的一個(gè)開(kāi)源項(xiàng)目,它是一個(gè)非常易用的安全框架,提供了包括認(rèn)證、授權(quán)、加密、會(huì)話管理等功能,與Spring Security一樣屬基于權(quán)限的安全框架,但是與Spring Security 相比,Shiro使用了比較簡(jiǎn)單易懂易于使用的授權(quán)方式。Shiro屬于輕量級(jí)框架,相對(duì)于Spring Security簡(jiǎn)單很多,并沒(méi)有security那么復(fù)雜。
優(yōu)勢(shì)特點(diǎn)
它是一個(gè)功能強(qiáng)大、靈活的、優(yōu)秀的、開(kāi)源的安全框架。
它可以勝任身份驗(yàn)證、授權(quán)、企業(yè)會(huì)話管理和加密等工作。
它易于使用和理解,與Spring Security相比,入門(mén)門(mén)檻低。
主要功能
- 驗(yàn)證用戶身份
- 用戶訪問(wèn)權(quán)限控制
- 支持單點(diǎn)登錄(SSO)功能
- 可以響應(yīng)認(rèn)證、訪問(wèn)控制,或Session事件
- 支持提供“Remember Me”服務(wù)
框架體系
Shiro 的整體框架大致如下圖所示(圖片來(lái)自互聯(lián)網(wǎng)):
Authentication(認(rèn)證), Authorization(授權(quán)), Session Management(會(huì)話管理), Cryptography(加密)代表Shiro應(yīng)用安全的四大基石。
它們分別是:
- Authentication(認(rèn)證):用戶身份識(shí)別,通常被稱為用戶“登錄”。
- Authorization(授權(quán)):訪問(wèn)控制。比如某個(gè)用戶是否具有某個(gè)操作的使用權(quán)限。
- Session Management(會(huì)話管理):特定于用戶的會(huì)話管理,甚至在非web 應(yīng)用程序。
- Cryptography(加密):在對(duì)數(shù)據(jù)源使用加密算法加密的同時(shí),保證易于使用。
除此之外,還有其他的功能來(lái)支持和加強(qiáng)這些不同應(yīng)用環(huán)境下安全領(lǐng)域的關(guān)注點(diǎn)。
特別是對(duì)以下的功能支持:
- Web支持:Shiro 提供的 web 支持 api ,可以很輕松的保護(hù) web 應(yīng)用程序的安全。
- 緩存:緩存是 Apache Shiro 保證安全操作快速、高效的重要手段。
- 并發(fā):Apache Shiro 支持多線程應(yīng)用程序的并發(fā)特性。
- 測(cè)試:支持單元測(cè)試和集成測(cè)試,確保代碼和預(yù)想的一樣安全。
- “Run As”:這個(gè)功能允許用戶在許可的前提下假設(shè)另一個(gè)用戶的身份。
- “Remember Me”:跨 session 記錄用戶的身份,只有在強(qiáng)制需要時(shí)才需要登錄。
架構(gòu)(外部)
在概念層,Shiro 架構(gòu)包含三個(gè)主要的理念:Subject, SecurityManager 和 Realm。下面的圖展示了這些組件如何相互作用,我們將在下面依次對(duì)其進(jìn)行描述。
Shiro執(zhí)行流程圖(圖片來(lái)自互聯(lián)網(wǎng))
三個(gè)主要理念/三大對(duì)象 重點(diǎn)!!!!
- Subject:代表當(dāng)前用戶,Subject 可以是一個(gè)人,也可以是第三方服務(wù)、守護(hù)進(jìn)程帳戶、時(shí)鐘守護(hù)任務(wù)或者其它當(dāng)前和軟件交互的任何事件。
- SecurityManager:管理所有Subject,SecurityManager 是 Shiro 架構(gòu)的核心,配合內(nèi)部安全組件共同組成安全傘。
- Realms:用于進(jìn)行權(quán)限信息的驗(yàn)證,我們自己實(shí)現(xiàn)。Realm 本質(zhì)上是一個(gè)特定的安全 DAO:它封裝與數(shù)據(jù)源連接的細(xì)節(jié),得到Shiro 所需的相關(guān)的數(shù)據(jù)。在配置 Shiro 的時(shí)候,你必須指定至少一個(gè)Realm 來(lái)實(shí)現(xiàn)認(rèn)證(authentication)和/或授權(quán)(authorization)。
我們需要實(shí)現(xiàn)Realms的Authentication 和 Authorization。其中 Authentication 是用來(lái)驗(yàn)證用戶身份,Authorization 是授權(quán)訪問(wèn)控制,用于對(duì)用戶進(jìn)行的操作授權(quán),證明該用戶是否允許進(jìn)行當(dāng)前操作,如訪問(wèn)某個(gè)鏈接,某個(gè)資源文件等。
架構(gòu)(內(nèi)部)
- Subject:任何可以與應(yīng)用交互的’用戶’;
- Security Manager: 相當(dāng)于SpringMVC中的DispatcherServlet;是Shiro的心臟,所有具體的交互都通過(guò)Security Manager進(jìn)行控制,它管理者所有的Subject,且負(fù)責(zé)進(jìn)行認(rèn)證,授權(quán),會(huì)話,及緩存的管理。
- Authenticator:負(fù)責(zé)Subject認(rèn)證,是一個(gè)擴(kuò)展點(diǎn),可以自定義實(shí)現(xiàn);可以使用認(rèn)證策略(Authenticationstrategy),即什么情況下算用戶認(rèn)證通過(guò)了;
- Authorizer:授權(quán)器,即訪問(wèn)控制器,用來(lái)決定主體是否有權(quán)限進(jìn)行相應(yīng)的操作;即控制著用戶能訪問(wèn)應(yīng)用中的那些功能;
- Realm: 可以有一個(gè)或者多個(gè)的realm,可以認(rèn)為是安全實(shí)體數(shù)據(jù)源,即用于獲取安全實(shí)體的,可以用DBC實(shí)現(xiàn),也可以是內(nèi)存實(shí)現(xiàn)等等,由用戶提供;所以一般在應(yīng)用中都需要實(shí)現(xiàn)自己的realm
- SessionManager:管理Session生命周期的組件,而Shiro并不僅僅可以用在Web環(huán)境,也可以用在普通的JavaSE環(huán)境中
- CacheManager:緩存控制器,來(lái)管理如用戶,角色,權(quán)限等緩存的;因?yàn)檫@些數(shù)據(jù)基本上很少改變,放到緩存中后可以提高訪問(wèn)的性能;
- Cryptography:密碼模塊,Shiro提高了一些常見(jiàn)的加密組件用于密碼加密,解密等
spring整合shio
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.1</version> </dependency> //得到一個(gè)用戶 subject currentuser = securityutils.getsubject( ); //通過(guò)當(dāng)前用戶得到session session session = currentuser.getsession(); //判斷當(dāng)前用戶是否被認(rèn)證 currentuser.isAuthenticated (); //獲得當(dāng)前用戶的認(rèn)證 currentuser.getPrincipal (); //獲得用戶是否擁有這個(gè)角色 currentuser.hasRole("schwartz"); //獲得當(dāng)前用戶的權(quán)限 currentuser.ispermitted("lightsaber:wield"); //注銷(xiāo) currentuser.logout();和security區(qū)別
沒(méi)有自定義登錄界面 需要自己動(dòng)手寫(xiě)
整合Mybatis
加上druid
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId> </dependency><!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.4</version> </dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version> </dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.1</version> </dependency>連接上數(shù)據(jù)庫(kù)之后
mybatis.type-aliases-package=com.can.pojo mybatis.mapper-locations=classpath:mapper/*.xml整合Thymeleaf
導(dǎo)入包
<dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.0.0</version> </dependency>需要配置 shiroConfig.java
@Bean //整合ShiroDialect:用來(lái)整合shiro Thymeleaf public ShiroDialect getShiroDialect(){return new ShiroDialect(); }命名空間
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"Swagger
- 號(hào)稱世界上最流行的Api框架;
- RestFul Api文檔在線自動(dòng)生成工具=>Api文檔與API定義同步更新
- 直接運(yùn)行,可以在線測(cè)試API接口;
- 支持多種語(yǔ)言: (Java,Php…)
官網(wǎng):https://swagger.io/
在項(xiàng)目中使用需要springfox
-
swagger2
-
ui
SpringBoot集成Swagger
新建一個(gè)springweb項(xiàng)目
導(dǎo)包
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version> </dependency>編寫(xiě)一個(gè)Hello
配置Swagger==>Config
@Configuration @EnableSwagger2 //開(kāi)啟Swagger2 public class SwaggerConfig { }測(cè)試運(yùn)行
訪問(wèn) : http://localhost:8080/swagger-ui.html
配置Swagger
Swagger的beansh實(shí)例Docket
//配置了Swagger的Docket實(shí)例 @Bean public Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()); }//配置Swagger信息 = apiInfo private ApiInfo apiInfo(){//作者信息Contact DEFAULT_CONTACT = new Contact("燦燦", "https://m.gmw.cn/baijia/2020-12/23/1301967099.html", "821057799@qq.com");return new ApiInfo("燦燦的SwaggerApI文檔","不想描述","1.0", "https://www.baidu.com/",DEFAULT_CONTACT,"Apache 2.0","http://www.apache.org/licenses/LICENSE-2.0",new ArrayList<VendorExtension>()); }Swagger配置掃描接口
Docket.select()
只希望在生產(chǎn)環(huán)境中使用,在發(fā)布的時(shí)候不使用
- 判斷是不是生產(chǎn)環(huán)境 flag = false
- 注入enable(flag)
在application中配置
#指定誰(shuí)激活 spring.profiles.active=dev然后config中寫(xiě)代碼
如何配置多個(gè)分組,多個(gè)Docket實(shí)例就可以,不能重名
controller
//只要接口中,返回值存在實(shí)體類(lèi),他就會(huì)被掃描到Swagger中 @PostMapping(value = "/user") public User user(){return new User(); }注釋
//給生成的文檔加注釋 //ApiModel 用在類(lèi)上 @ApiModel("用戶實(shí)體類(lèi)") public class User {//ApiModelProperty用在方法上 不是public的字段上不會(huì)在文檔中顯示 私有屬性要加set get@ApiModelProperty("用戶名")public String username;@ApiModelProperty("密碼")public String password; }總結(jié):
Swagger是一個(gè)優(yōu)秀的工具,幾乎所有的大公司都有使用它
注意:
在正式發(fā)布的時(shí)候,關(guān)閉Swagger!出于安全考慮并且節(jié)省運(yùn)行的內(nèi)存
任務(wù)
異步任務(wù)~
定時(shí)任務(wù)~
郵件任務(wù)~
異步任務(wù)
//告訴Spring這是一個(gè)異步的方法 @Async public void hello(){try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("數(shù)據(jù)正在處理...."); }在Spring主啟動(dòng)類(lèi)里面啟動(dòng)
//開(kāi)啟異步注解功能 @EnableAsync郵件任務(wù)
導(dǎo)入郵箱包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency>配置 application.properties
spring.mail.username=821057799@qq.com spring.mail.password=qwjsdodvnxlrbcaa spring.mail.host=smtp.qq.com # 開(kāi)啟加密驗(yàn)證 spring.mail.properties.mail.smtp.enable=true測(cè)試
@Test void contextLoads() {boolean html = true;String subject = "哈嘍!";String text = "<p style='color:red'>李詩(shī)雨愛(ài)張世杰</p>";ArrayList<String> pathnames = new ArrayList<>();String toBody = "1537752955@qq.com";String fromBody = "821057799@qq.com";pathnames.add("C:\\Users\\86177\\Desktop\\1.jpg");pathnames.add("C:\\Users\\86177\\Desktop\\1.jpg");try {send(html,subject,text,pathnames,toBody,fromBody);} catch (MessagingException e) {e.printStackTrace();} }@Test void contextLoads2() throws MessagingException {//一個(gè)復(fù)雜的郵件MimeMessage mimeMessage = mailSender.createMimeMessage();//組裝MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);helper.setSubject("雨寶寶你好呀");helper.setText("<p style='color:red'>詩(shī)雨你好呀</p>",true);//附件helper.addAttachment("1.jpg",new File("C:\\Users\\86177\\Desktop\\1.jpg"));helper.addAttachment("2.jpg",new File("C:\\Users\\86177\\Desktop\\1.jpg"));helper.setTo("1537752955@qq.com");helper.setFrom("821057799@qq.com");mailSender.send(mimeMessage); }/**** @param html 是否開(kāi)啟html編碼* @param subject 主題* @param text 文本* @param pathnames 路徑名* @param toBody 發(fā)送給誰(shuí)* @param fromBody 來(lái)自誰(shuí)* @throws MessagingException*/ public void send(Boolean html,String subject,String text,ArrayList<String> pathnames,String toBody,String fromBody) throws MessagingException {//一個(gè)復(fù)雜的郵件MimeMessage mimeMessage = mailSender.createMimeMessage();//組裝MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);helper.setSubject(subject);helper.setText(text,html);String uuid = UUID.randomUUID().toString() + "";// substring() 方法用于提取字符串中介于兩個(gè)指定下標(biāo)之間的字符。String filename;for (String pathname : pathnames) {//附件filename = uuid + pathname.substring(pathname.lastIndexOf('\\')+1);helper.addAttachment(filename,new File(pathname));}helper.setTo(toBody);helper.setFrom(fromBody);mailSender.send(mimeMessage); }定時(shí)任務(wù)
核心
TaskScheduler 任務(wù)調(diào)度者 TaskExecutor 人去執(zhí)行者//核心啟動(dòng)類(lèi)上啟動(dòng) 開(kāi)啟定時(shí)功能的注解 @EnableScheduling@Scheduled //什么時(shí)候執(zhí)行Cron表達(dá)式 //較難測(cè)試
@Service public class ScheduledService {//在一個(gè)特定的時(shí)間執(zhí)行這個(gè)方法~ Timer//cron 表達(dá)式/*30 15 10 * * ? 每天的10點(diǎn)15分30秒執(zhí)行一次30 0/5 10,18 * * ? 每天10點(diǎn)和18點(diǎn) 每隔五分鐘執(zhí)行一次*///秒 分 時(shí) 日 月 周幾@Scheduled(cron = "30 15 10 * * ?")public void hello(){System.out.println("hello,你被執(zhí)行了!");} }分布式Dubbo + Zookeeper + SpringBoot
什么是分布式系統(tǒng)
在《分布式系統(tǒng)原理與范型》一書(shū)中有如下定義:“分布式系統(tǒng)是若干獨(dú)立計(jì)算機(jī)的集合,這些計(jì)算機(jī)對(duì)于用戶來(lái)說(shuō)就像單個(gè)相關(guān)系統(tǒng)”;
分布式系統(tǒng)是由一組通過(guò)網(wǎng)絡(luò)進(jìn)行通信、為了完成共同的任務(wù)而協(xié)調(diào)工作的計(jì)算機(jī)節(jié)點(diǎn)組成的系統(tǒng)。分布式系統(tǒng)的出現(xiàn)是為了用廉價(jià)的、普通的機(jī)器完成單個(gè)計(jì)算機(jī)無(wú)法完成的計(jì)算、存儲(chǔ)任務(wù)。其目的是利用更多的機(jī)器,處理更多的數(shù)據(jù)。
分布式系統(tǒng)(distributed system)是建立在網(wǎng)絡(luò)之上的軟件系統(tǒng)。
首先需要明確的是,只有當(dāng)單個(gè)節(jié)點(diǎn)的處理能力無(wú)法滿足日益增長(zhǎng)的計(jì)算、存儲(chǔ)任務(wù)的時(shí)候,且硬件的提升(加內(nèi)存、加磁盤(pán)、使用更好的CPU)高昂到得不償失的時(shí)候,應(yīng)用程序也不能進(jìn)一步優(yōu)化的時(shí)候,我們才需要考慮分布式系統(tǒng)。因?yàn)?#xff0c;分布式系統(tǒng)要解決的問(wèn)題本身就是和單機(jī)系統(tǒng)一樣的,而由于分布式系統(tǒng)多節(jié)點(diǎn)、通過(guò)網(wǎng)絡(luò)通信的拓?fù)浣Y(jié)構(gòu),會(huì)引入很多單機(jī)系統(tǒng)沒(méi)有的問(wèn)題,為了解決這些問(wèn)題又會(huì)引入更多的機(jī)制、協(xié)議,帶來(lái)更多的問(wèn)題。。。
RPC
RPC【Remote Procedure Call】是指遠(yuǎn)程過(guò)程調(diào)用,是一種進(jìn)程間通信方式,他是一種技術(shù)的思想,而不是規(guī)范。它允許程序調(diào)用另一個(gè)地址空間(通常是共享網(wǎng)絡(luò)的另一臺(tái)機(jī)器上)的過(guò)程或函數(shù),而不用程序員顯式編碼這個(gè)遠(yuǎn)程調(diào)用的細(xì)節(jié)。即程序員無(wú)論是調(diào)用本地的還是遠(yuǎn)程的函數(shù),本質(zhì)上編寫(xiě)的調(diào)用代碼基本相同。
也就是說(shuō)兩臺(tái)服務(wù)器A,B,一個(gè)應(yīng)用部署在A服務(wù)器上,想要調(diào)用B服務(wù)器上應(yīng)用提供的函數(shù)/方法,由于不在一個(gè)內(nèi)存空間,不能直接調(diào)用,需要通過(guò)網(wǎng)絡(luò)來(lái)表達(dá)調(diào)用的語(yǔ)義和傳達(dá)調(diào)用的數(shù)據(jù)。為什么要用RPC呢?就是無(wú)法在一個(gè)進(jìn)程內(nèi),甚至一個(gè)計(jì)算機(jī)內(nèi)通過(guò)本地調(diào)用的方式完成的需求,比如不同的系統(tǒng)間的通訊,甚至不同的組織間的通訊,由于計(jì)算能力需要橫向擴(kuò)展,需要在多臺(tái)機(jī)器組成的集群上部署應(yīng)用。RPC就是要像調(diào)用本地的函數(shù)一樣去調(diào)遠(yuǎn)程函數(shù);
推薦閱讀文章:https://www.jianshu.com/p/2accc2840a1b
Dubbo
什么是dubbo?
Apache Dubbo |?d?b??| 是一款高性能、輕量級(jí)的開(kāi)源Java RPC框架,它提供了三大核心能力:面向接口的遠(yuǎn)程方法調(diào)用,智能容錯(cuò)和負(fù)載均衡,以及服務(wù)自動(dòng)注冊(cè)和發(fā)現(xiàn)。
dubbo官網(wǎng)
1.了解Dubbo的特性
2.查看官方文檔
服務(wù)提供者(Provider):暴露服務(wù)的服務(wù)提供方,服務(wù)提供者在啟動(dòng)時(shí),向注冊(cè)中心注冊(cè)自己提供的服務(wù)。
服務(wù)消費(fèi)者(Consumer):調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方,服務(wù)消費(fèi)者在啟動(dòng)時(shí),向注冊(cè)中心訂閱自己所需的服務(wù),服務(wù)消費(fèi)者,從提供者地址列表中,基于軟負(fù)載均衡算法,選一臺(tái)提供者進(jìn)行調(diào)用,如果調(diào)用失敗,再選另一臺(tái)調(diào)用。
注冊(cè)中心(Registry):注冊(cè)中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更,注冊(cè)中心將基于長(zhǎng)連接推送變更數(shù)據(jù)給消費(fèi)者
監(jiān)控中心(Monitor):服務(wù)消費(fèi)者和提供者,在內(nèi)存中累計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間,定時(shí)每分鐘發(fā)送一次統(tǒng)計(jì)數(shù)據(jù)到監(jiān)控中心
調(diào)用關(guān)系說(shuō)明
Zookeeper
下載地址:http://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/
最新版下載地址:http://mirror.bit.edu.cn/apache/zookeeper/stable/
3.5以后的版本要下載帶有bin標(biāo)識(shí)的zookeeper
運(yùn)行/bin/zkServer.cmd ,初次運(yùn)行會(huì)報(bào)錯(cuò),沒(méi)有zoo.cfg配置文件;
可能遇到問(wèn)題:閃退 !
解決方案:編輯zkServer.cmd文件末尾添加pause 。這樣運(yùn)行出錯(cuò)就不會(huì)退出,會(huì)提示錯(cuò)誤信息,方便找到原因。
修改zoo.cfg配置文件
將conf文件夾下面的zoo_sample.cfg復(fù)制一份改名為zoo.cfg即可。
注意幾個(gè)重要位置:
dataDir=./ 臨時(shí)數(shù)據(jù)存儲(chǔ)的目錄(可寫(xiě)相對(duì)路徑)
clientPort=2181 zookeeper的端口號(hào)
修改完成后再次啟動(dòng)zookeeper
使用zkCli.cmd測(cè)試
ls /:列出zookeeper根下保存的所有節(jié)點(diǎn)
[zk: 127.0.0.1:2181(CONNECTED) 4] ls / [zookeeper]create –e /kuangshen 123:創(chuàng)建一個(gè)kuangshen節(jié)點(diǎn),值為123
get /kuangshen:獲取/kuangshen節(jié)點(diǎn)的值
我們?cè)賮?lái)查看一下節(jié)點(diǎn)
下載dubbo-admin
dubbo本身并不是一個(gè)服務(wù)軟件。它其實(shí)就是一個(gè)jar包,能夠幫你的java程序連接到zookeeper,并利用zookeeper消費(fèi)、提供服務(wù)。
但是為了讓用戶更好的管理監(jiān)控眾多的dubbo服務(wù),官方提供了一個(gè)可視化的監(jiān)控程序dubbo-admin,不過(guò)這個(gè)監(jiān)控即使不裝也不影響使用。
我們這里來(lái)安裝一下:
1、下載dubbo-admin
地址 :https://github.com/apache/dubbo-admin/tree/master
2、解壓進(jìn)入目錄
修改 dubbo-admin\src\main\resources \application.properties 指定zookeeper地址
server.port=7001 spring.velocity.cache=false spring.velocity.charset=UTF-8 spring.velocity.layout-url=/templates/default.vm spring.messages.fallback-to-system-locale=false spring.messages.basename=i18n/message spring.root.password=root spring.guest.password=guestdubbo.registry.address=zookeeper://127.0.0.1:21813、在項(xiàng)目目錄下打包dubbo-admin
mvn clean package -Dmaven.test.skip=true第一次打包的過(guò)程有點(diǎn)慢,需要耐心等待!直到成功!
4、執(zhí)行 dubbo-admin\target 下的dubbo-admin-0.0.1-SNAPSHOT.jar
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar【注意:zookeeper的服務(wù)一定要打開(kāi)!】
執(zhí)行完畢,我們?nèi)ピL問(wèn)一下 http://localhost:7001/ , 這時(shí)候我們需要輸入登錄賬戶和密碼,我們都是默認(rèn)的root-root;
登錄成功后,查看界面
總結(jié)
zookeeper: 注冊(cè)中心 必須要
dubbo-admin:是一個(gè)監(jiān)控管理后臺(tái)~查看我們注冊(cè)了那些服務(wù),那些服務(wù)被消費(fèi)了
Dubbo:jar包
測(cè)試
服務(wù)提供者
1、將服務(wù)提供者注冊(cè)到注冊(cè)中心,我們需要整合Dubbo和zookeeper,所以需要導(dǎo)包
我們從dubbo官網(wǎng)進(jìn)入github,看下方的幫助文檔,找到dubbo-springboot,找到依賴包****
<!-- Dubbo Spring Boot Starter --> <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.3</version> </dependency>zookeeper的包我們?nèi)aven倉(cāng)庫(kù)下載,zkclient;
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient --> <dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version> </dependency>【新版的坑】zookeeper及其依賴包,解決日志沖突,還需要剔除日志依賴;
<!-- 引入zookeeper --> <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.12.0</version> </dependency> <dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.12.0</version> </dependency> <dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.14</version><!--排除這個(gè)slf4j-log4j12--><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions> </dependency>2、在springboot配置文件中配置dubbo相關(guān)屬性!
#當(dāng)前應(yīng)用名字 dubbo.application.name=provider-server #注冊(cè)中心地址 dubbo.registry.address=zookeeper://172.30.72.23:2181 #掃描指定包下服務(wù) dubbo.scan.base-packages=com.kuang.provider.service3、在service的實(shí)現(xiàn)類(lèi)中配置服務(wù)注解,發(fā)布服務(wù)!注意導(dǎo)包問(wèn)題
//Zookeeper:服務(wù)注冊(cè)與發(fā)現(xiàn)@Service //dubbo.config.annotation 注意導(dǎo)的包 要是dubbo的 // 在項(xiàng)目一啟動(dòng)就自動(dòng)注冊(cè)到Zookeeper的注冊(cè)中心 @Component // 使用了dubbo后盡量使用這個(gè) 不使用上面的 // 因?yàn)楹蛃pring的注解一樣 容易導(dǎo)錯(cuò)包 public class TicketServiceImpl implements TicketService{@Overridepublic String getTicket() {return "《狂神說(shuō)JAVA》";} }啟動(dòng)Zookeeper 同時(shí)也可以啟動(dòng)監(jiān)控界面 duubo-admin 界面有緩存 刷新較慢 但是控制臺(tái)實(shí)時(shí)刷新 注意不要關(guān)掉控制臺(tái)
服務(wù)消費(fèi)者
1、導(dǎo)入依賴,和之前的依賴一樣;
<!--dubbo--> <!-- Dubbo Spring Boot Starter --> <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.3</version> </dependency> <!--zookeeper--> <!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient --> <dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version> </dependency> <!-- 引入zookeeper --> <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.12.0</version> </dependency> <dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.12.0</version> </dependency> <dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.14</version><!--排除這個(gè)slf4j-log4j12--><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions> </dependency>2、配置參數(shù)
#當(dāng)前應(yīng)用名字 dubbo.application.name=consumer-server #注冊(cè)中心地址 dubbo.registry.address=zookeeper://172.30.72.23:21813、本來(lái)正常步驟是需要將服務(wù)提供者的接口打包,然后用pom文件導(dǎo)入,我們這里使用簡(jiǎn)單的方式,直接將服務(wù)的接口拿過(guò)來(lái),路徑必須保證正確,即和服務(wù)提供者相同;
聊聊
分布式架構(gòu)會(huì)遇到的四個(gè)核心問(wèn)題?
1.這么多服務(wù),客戶端該如何去訪問(wèn)?
2.這么多服務(wù),服務(wù)之間如何進(jìn)行通信?
3.這么多服務(wù),如何治理呢?
4.服務(wù)掛了,怎么辦?
解決方案:
springcloud,是一套生態(tài),就是來(lái)解決以上分布式架構(gòu)的4個(gè)問(wèn)題
想使用springcloud,必須要掌握springBoot,因?yàn)閟pringcloud是基于springBoot;
Spring cloud NetFlix,出來(lái)了一套解決方案,一站式解決方案,用可以直接拿。
? Api網(wǎng)關(guān),zuul組件
? Feign–>HttpClient–>HTTP的通信方式,同步并阻塞
? 服務(wù)注冊(cè)與發(fā)現(xiàn),Eureka
? 熔斷機(jī)制,Hystrix
? 2018年年底,NetFlix宣布無(wú)限期停止維護(hù)。生態(tài)不再維護(hù),就會(huì)脫節(jié)。
Apache Dubbo Zookeeper,第二套解決方案
? API: 沒(méi)有! 要么找第三方組件,要么自己實(shí)現(xiàn)
? Dubbo是一個(gè)高性能的基于Java實(shí)現(xiàn)的RPC通訊框架!
? 服務(wù)注冊(cè)與發(fā)現(xiàn),Zookeeper:動(dòng)物園管理者(Hadoop,Hive)
? 熔斷機(jī)制:沒(méi)有,借助了Hystrix。
?
? 所以 不完善,Dubbo3.0
SpringCloud Alibaba 一站式解決方案
目前,又提出了一種方案:
? 服務(wù)網(wǎng)格:下一代微服務(wù)標(biāo)準(zhǔn),Server Mesh
? 代表解決方案:istio(未來(lái))
萬(wàn)變不離其宗,一通百通!
為什么要解決這些問(wèn)題,網(wǎng)絡(luò)不可靠。加載器
總結(jié)
以上是生活随笔為你收集整理的SpringBoot学习笔记~狂神的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 蓝桥杯-回形取数
- 下一篇: Reactor 3快速上手——响应式Sp