springBoot從入門到源碼分析

 先分享一個springBoot搭建學習項目,和springboot多數據源項目的傳送門:https://github.com/1057234721/springBoot

 

1.  SpringBoot快速入門

該項目分爲幾個模塊:css

1,集成了mybatis。html

2,事務支持前端

3,全局異常處理java

4,靜態資源訪問。git

靜態資源:js, css, html, 圖片,音視頻等程序員

靜態資源路徑:是指系統能夠直接訪問的路徑,且路徑下的全部文件都可被用戶直接讀取。github

Spring Boot默認提供靜態資源目錄位置需置於classpath下,目錄名需符合以下規則:web

/staticredis

/publicspring

/resources

/META-INF/resources

resources目錄下面創建static文件夾,在文件夾裏面任意放張圖片。

命名爲:enjoy.jpg

 

在地址欄上輸入localhost:8080/enjoy.jpg,能夠看到圖片

5,jsp集成

 通常來講springboot不建議直接使用jsp頁面,但不排除有些公司的項目依然使用jsp作前端界面。

springboot內置的tomcat並無集成對jsp的支持,也沒有對EL表達式的支持,所以要使用jsp應該先把相關的依賴集成進來

pom文件裏面新增

      <!--JavaServer Pages Standard Tag LibraryJSP標準標籤庫-->

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>jstl</artifactId>

        </dependency>

        <!--內置tocatJsp支持的依賴,用於編譯Jsp-->

        <dependency>

            <groupId>org.apache.tomcat.embed</groupId>

            <artifactId>tomcat-embed-jasper</artifactId>

        </dependency>

因爲要springmvc解析jsp,要配置試圖解析器,在applicaiton.properties 裏面新增

spring.mvc.view.prefix=/WEB-INF/jsp/

spring.mvc.view.suffix=.jsp

resources裏面新建WEB-INF文件夾,在裏面放一個index.jsp頁面 

最後新建一個controller,注意這裏的註解是@Controller,千萬不能用@RestController

在瀏覽器上輸入:localhost:8080/jsp/hi,能夠看到JSP頁面。

6, 模板引擎

SpringBoot 推薦使用模板引擎來渲染html,若是你不是歷史遺留項目,必定不要使用JSP,經常使用的模板引擎不少,有freemark,thymeleaf等,其實都大同小異

其中springboot 強烈推薦的是用thymeleaf

pom文件種添加thymeleaf的支持,而且刪除JSP的支持

  <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-thymeleaf</artifactId>

        </dependency>

 

        <!--<!–JavaServer Pages Standard Tag LibraryJSP標準標籤庫–>-->

        <!--<dependency>-->

            <!--<groupId>javax.servlet</groupId>-->

            <!--<artifactId>jstl</artifactId>-->

        <!--</dependency>-->

 

        <!--<!–內置tocatJsp支持的依賴,用於編譯Jsp–>-->

        <!--<dependency>-->

            <!--<groupId>org.apache.tomcat.embed</groupId>-->

            <!--<artifactId>tomcat-embed-jasper</artifactId>-->

        <!--</dependency>-->

刪除application.properties文件裏面視圖解析器內容

#spring.mvc.view.prefix=/WEB-INF/jsp/

#spring.mvc.view.suffix=.jsp

Springboot默認的模板配置路徑爲:src/main/resources/templates

resources目錄裏面新建一個templates目錄,在目錄裏面新建testThymeleaf.html文件

在瀏覽器上輸入:localhost:8080/tpl/testThymeleaf,能夠看到頁面。

7,集成swagger2構建api文檔

Swagger2 的做用

l隨項目自動生成強大RESTful API文檔,減小工做量

lAPI文檔與代碼整合在一塊兒,便於同步更新API說明

 頁面測試功能來調試每一個RESTful API

訪問:http://localhost:8080/swagger-ui.html

8,集成日誌

java有許多的日誌組件,好比 log4j,log4j2,logback還有java自生提供的Java Util Logging,其實在springboot中對這些組件都提供了支持,log4jlog4j2logback都提供相應的組件支持。

 Logback

springboot中默認使用的日誌工具是logback,不過在說起具體的日誌工具以前要提一個名詞,這個名詞就是slf4j(Simple Logging Facade For Java)

百度百科解釋https://baike.baidu.com/item/slf4j/6408868

slf4j不是具體的日誌解決方案它有點相似於jdbc,使用了門面模式,是一個針對各種日誌的抽象實現,既然是抽象的日誌實現,在springboot中確定不須要額外導入。

注意:spring-boot-starter中就提供了對spring-boot-starter-logging的依賴

在spring-boot-starter-logging中能夠看到以及集成了slf4j與具體實現logback的默認支持

日誌級別:

 

修改controller 把日誌的輸出改爲logger.debug("這個一個hello日誌");這個時候重啓,再調用,發現後臺並不會有任何輸出,這緣由是日誌級別在做祟

默認狀況下,Spring Boot 配置的是INFO 日誌級別,也就是會輸出INFO級別以上的日誌(ERROR, WARN, INFO)若是須要 Debug 級別的日誌。

src/main/resources/application.properties 中配置。debug=true 此外,配置 logging.level.* 來具體輸出哪些包的日誌級別。

例如

logging.level.root=INFO

logging.level.org.springframework.web=DEBUG

logging.level.cn.enjoy.controller=DEBUG

 

 日誌文件

通常狀況下,springboot日誌只會輸出到控制檯,並不會寫入到日誌文件,可是,在一些正式環境的應用中,咱們須要經過在 application.properites 文件中配置 logging.file 文件名稱和 logging.path 文件路徑,將日誌輸出到日誌文件中

logging.path = /var/tmp

logging.file = xxx.log

logging.level.root = info

注意:

若是隻配置 logging.path,在 /var/tmp文件夾生成一個日誌文件爲 spring.log。若是隻配置 logging.file,會在項目的當前路徑下生成一個 xxx.log 日誌文件

 

 log4j2

spring-boot-dependencies POMs中搜索spring-boot-starter-log4j2

發現Spring bootPom中本身提供了這個依賴,因而咱們加入以下jar依賴:

修改pom.xml文件

 <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

            <exclusions>

                <exclusion>

                    <groupId>org.springframework.boot</groupId>

                    <artifactId>spring-boot-starter-logging</artifactId>

                </exclusion>

            </exclusions>

        </dependency>

        <dependency> 

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-log4j2</artifactId>

        </dependency>

注意: 因爲默認使用logback在擴展log4j2以前先要把logback移除

 日誌使用跟上面logback同樣。

使用AOP統一日誌處理

爲了防止在工做中常常在代碼中加入大量的日誌處理代碼,在實際項目開發中,通常使用AOP統一完成日誌處理工做。

9,springBoot熱加載部署

 

熱部署不會用在生產環境,但對於程序員開發的效率,仍是有必定幫助的,所謂的熱部署,就是在應用程序在不中止的狀況下,實現新的部署

spring-boot-devtools 是一個爲開發者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去。原理是在發現代碼有更改以後,從新啓動應用,可是速度比手動中止後再啓動還要更快,更快指的不是節省出來的手工操做的時間。

其深層原理是使用了兩個ClassLoader,一個Classloader加載那些不會改變的類(第三方Jar包),另外一個ClassLoader加載會更改的類,稱爲  restart ClassLoader  

,這樣在有代碼更改的時候,原來的restart ClassLoader 被丟棄,從新建立一個restart ClassLoader,因爲須要加載的類相比較少,因此實現了較快的重啓時間

修改pom文件,增長

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-devtools</artifactId>

</dependency>

修改properties文件

若是使用的  Thymeleaf  模板,那麼請直接在application.properties中添加

spring.thymeleaf.cache=false

若是使用的 FreeMarker 模板,那麼請直接在application.properties中添加

spring.freemarker.cache=false

idea中使用

若是你是使用eclipse,請忽略,但若是你是使用IDEA,因爲idea 沒有保存修改的,也就是說在idea中並不會由於你ctrl+s 就從新編譯代碼。

那麼就須要額外的配置

pom文件中,增長編譯插件,讓代碼有變更的時候也編譯

<build>

    <plugins>

        <plugin>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-maven-plugin</artifactId>

            <configuration>

                <!-- 若是不設置fork,那麼不會restart,devtools熱部署不會起做用-->

                <fork>true</fork>

            </configuration>

        </plugin>

    </plugins>

</build>

一、手動:修改完代碼,按快捷鍵Ctrl+F9,手動構建項目,或者只修改單個類文件的話,按Ctrl+Shift+F9,從新編譯該類文件,便可觸發重啓服務。

二、自動

        1File -> Settings -> Compiler,勾選 Build Project automatically

         2)按快捷鍵Ctrl+Shift+Alt+/,選擇1.Registry...

 

         3)勾選 compiler.automake.allow.when.app.running 便可

 

這個時候修改JAVA文件或者模板文件都自動會生效

 

10,編譯,打包

 

 快速入門進行到這裏,其實已經差很少了,能應對絕大多數開發常見,接下來就是導包部署。

 

pom文件中新增

 

<build>

 

        <plugins>

 

            <plugin>

 

                <groupId>org.apache.maven.plugins</groupId>

 

                <artifactId>maven-compiler-plugin</artifactId>

 

                <configuration>

 

                    <source>1.8</source>

 

                    <target>1.8</target>

 

                </configuration>

 

            </plugin>

 

            <plugin>

 

                <groupId>org.springframework.boot</groupId>

 

                <artifactId>spring-boot-maven-plugin</artifactId>

 

                <configuration>

 

                    <!-- 若是不設置fork,那麼不會restart,devtools熱部署不會起做用-->

 

                    <fork>true</fork>

 

                </configuration>

 

                <executions>

 

                    <execution>

 

                        <goals>

 

                            <goal>repackage</goal>

 

                        </goals>

 

                    </execution>

 

                </executions>

 

            </plugin>

 

        </plugins>

 

    </build>

 

使用mvn clean  package 打包

 

java –jar 運行

 

 

 

11, war部署

若是並不但願使用內置的tomcat,但願部署到其餘tomcat服務器,那麼就須要使用war包部署了。

修改pom文件,打包方式改爲war

修改在pom文件,剔除內置tomcat的支持,不然會和外面的tomcat衝突

 <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-tomcat</artifactId>

            <!--打包的時候能夠不用包進去,別的設施會提供。事實上該依賴理論上能夠參與編譯,測試,運行等週期。

                至關於compile,可是打包階段作了exclude操做-->

            <scope>provided</scope>

        </dependency>

修改啓動類,使其繼承

@SpringBootApplication

@MapperScan("cn.enjoy.dao")

public class App  extends SpringBootServletInitializer  {

    public static void main(String[] args) throws Exception {

        SpringApplication.run(App.class, args);

    }

    @Override

    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {

        return builder.sources(App.class);

    }

}

使用mvn clean  package 打包

war包拷貝到tomcat webapps

 

12,集成redis

13,集成RabbitMq

14,Actuator監控管理

 

Actuatorspring boot的一個附加功能,可幫助你在應用程序生產環境時監視和管理應用程序。可使用HTTP的各類請求來監管,審計,收集應用的運行狀況.特別對於微服務管理十分有意義

缺點:沒有可視化界面(Spring cloud 還會用到這功能,就能夠看到界面了)

修改pom文件,添加依賴

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

修改application.properties文件,啓動監控端點

# 加載全部的端點/默認只加載了 info / health

management.endpoints.web.exposure.include=*

# 描述信息

info.blog-url=http://xiangxueketang.cn

info.author=enjoy

info.version=@project.version@

從新啓動,在地址欄輸入

http://localhost:8080/actuator/info

Actuator訪問路徑

經過actuator/+端點名就能夠獲取相應的信息。

 

路徑

做用

/actuator/beans

顯示應用程序中全部Spring bean的完整列表。

/actuator/configprops

顯示全部配置信息。

/actuator/env

陳列全部的環境變量。

/actuator/mappings

顯示全部@RequestMappingurl整理列表。

/actuator/health

顯示應用程序運行情況信息 up表示成功 down失敗

/actuator/info

查看自定義應用信息

15,多數據源與jta+atomikos分佈式事務

2. SpringBoot啓動流程分析

建立SpringApplication

public static ConfigurableApplicationContext run(Class<?>[] primarySources,

String[] args) {

return new SpringApplication(primarySources).run(args);

}

 

其實SpringBoot啓動就着兩個步驟,先建立ConfigurableApplicationContext ,而後再調用Run方法。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {

this.resourceLoader = resourceLoader;

Assert.notNull(primarySources, "PrimarySources must not be null");

//保存主類

this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

//判斷當前是什麼類型項目

this.webApplicationType = WebApplicationType.deduceFromClasspath();

//從類路徑下找到META-INF/spring.factories配置的全部ApplicationContextInitializer

setInitializers((Collection) getSpringFactoriesInstances(

ApplicationContextInitializer.class));

//從類路徑下找到META-INF/spring.factories配置的全部ApplicationListener

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

this.mainApplicationClass = deduceMainApplicationClass();

}

可見着一步很是簡單,只是把一些相關的類都加載了而已,並沒執行。

 Run方法

真的重要是run方法

 

public ConfigurableApplicationContext run(String... args) {

StopWatch stopWatch = new StopWatch();

stopWatch.start();

ConfigurableApplicationContext context = null;

Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

configureHeadlessProperty();

//從類路徑下METAINF/spring.factories,取得SpringApplicationRunListeners

SpringApplicationRunListeners listeners = getRunListeners(args);

//回調全部的獲取SpringApplicationRunListener.starting()方法

listeners.starting();

try {

    //封裝命令行參數

ApplicationArguments applicationArguments = new DefaultApplicationArguments(

args);

    //準備環境

ConfigurableEnvironment environment = prepareEnvironment(listeners,

applicationArguments);

configureIgnoreBeanInfo(environment);

            //創回調SpringApplicationRunListener.environmentPrepared()

//表示環境準備完成

 

//打印Banner

Banner printedBanner = printBanner(environment);

            //根據環境建立context

context = createApplicationContext();

    //錯誤的異常報表

exceptionReporters = getSpringFactoriesInstances(

SpringBootExceptionReporter.class,

new Class[] { ConfigurableApplicationContext.class }, context);

     //準備上下文環境;

//environment保存到ioc中;

//applyInitializers()調用全部的ApplicationContextInitializerinitialize方法

//調用全部的SpringApplicationRunListenercontextPrepared()

prepareContext(context, environment, listeners, applicationArguments,

printedBanner);

//SpringApplicationRunListenercontextLoaded

//刷新容器

//掃描,建立,加載全部組件;

refreshContext(context);

afterRefresh(context, applicationArguments);

stopWatch.stop();

if (this.logStartupInfo) {

new StartupInfoLogger(this.mainApplicationClass)

.logStarted(getApplicationLog(), stopWatch);

}

//全部的SpringApplicationRunListener回調started方法

listeners.started(context);

//獲取全部的ApplicationRunnerCommandLineRunner進行調用

callRunners(context, applicationArguments);

}

catch (Throwable ex) {

handleRunFailure(context, ex, exceptionReporters, listeners);

throw new IllegalStateException(ex);

}

 

try {

//全部的SpringApplicationRunListenerrunning()

listeners.running(context);

}

catch (Throwable ex) {

handleRunFailure(context, ex, exceptionReporters, null);

throw new IllegalStateException(ex);

}

return context;

}

相關文章
相關標籤/搜索