1、Spring Boot 入門
一、Spring Boot 簡介
簡化Spring應用開發的一個框架;
整個Spring技術棧的一個大整合;
J2EE開發的一站式解決方案;
二、微服務
2014,martin fowler
微服務:架構風格(服務微化)
一個應用應該是一組小型服務;能夠經過HTTP的方式進行互通;
單體應用:ALL IN ONE
微服務:每個功能元素最終都是一個可獨立替換和獨立升級的軟件單元;
詳細參照微服務文檔
三、環境準備
http://www.gulixueyuan.com/ 穀粒學院
環境約束
–jdk1.8:Spring Boot 推薦jdk1.7及以上;java version "1.8.0_112"
–maven3.x:maven 3.3以上版本;Apache Maven 3.3.9
–IntelliJIDEA2017:IntelliJ IDEA 2017.2.2 x6四、STS
–SpringBoot 1.5.9.RELEASE:1.5.9;
統一環境;
一、MAVEN設置;
給maven 的settings.xml配置文件的profiles標籤添加
二、IDEA設置
整合maven進來;
<profile>
<id>jdk‐1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
1
2
3
4
5
6
7
8
9
10
11
12
四、Spring Boot HelloWorld
一個功能:
瀏覽器發送hello請求,服務器接受請求並處理,響應Hello World字符串;
一、建立一個maven工程;(jar)
二、導入spring boot相關的依賴
三、編寫一個主程序;啓動Spring Boot應用
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
四、編寫相關的Controller、Service
五、運行主程序測試
六、簡化部署
將這個應用打成jar包,直接使用java -jar的命令進行執行;
五、Hello World探究
一、POM文件
一、父項目
/**
* @SpringBootApplication 來標註一個主程序類,說明這是一個Spring Boot應用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring應用啓動起來
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "Hello World!";
}
}
<!‐‐ 這個插件,能夠將應用打包成一個可執行的jar包;‐‐>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐maven‐plugin</artifactId>
</plugin>
</plugins>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
Spring Boot的版本仲裁中心;
之後咱們導入依賴默認是不須要寫版本;(沒有在dependencies裏面管理的依賴天然須要聲明版本號)
二、啓動器
spring-boot-starter-web:
spring-boot-starter:spring-boot場景啓動器;幫咱們導入了web模塊正常運行所依賴的組件;
Spring Boot將全部的功能場景都抽取出來,作成一個個的starters(啓動器),只須要在項目裏面引入這些starter
相關場景的全部依賴都會導入進來。要用什麼功能就導入什麼場景的啓動器
二、主程序類,主入口類
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
他的父項目是
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring‐boot‐dependencies</relativePath>
</parent>
他來真正管理Spring Boot應用裏面的全部依賴版本;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
/**
* @SpringBootApplication 來標註一個主程序類,說明這是一個Spring Boot應用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring應用啓動起來
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication: Spring Boot應用標註在某個類上說明這個類是SpringBoot的主配置類,SpringBoot
就應該運行這個類的main方法來啓動SpringBoot應用;
@SpringBootConfiguration:Spring Boot的配置類;
標註在某個類上,表示這是一個Spring Boot的配置類;
@Configuration:配置類上來標註這個註解;
配置類 ----- 配置文件;配置類也是容器中的一個組件;@Component
@EnableAutoConfiguration:開啓自動配置功能;
之前咱們須要配置的東西,Spring Boot幫咱們自動配置;@EnableAutoConfiguration告訴SpringBoot開啓自
動配置功能;這樣自動配置才能生效;
@AutoConfigurationPackage:自動配置包
@Import(AutoConfigurationPackages.Registrar.class):
Spring的底層註解@Import,給容器中導入一個組件;導入的組件由
AutoConfigurationPackages.Registrar.class;
將主配置類(@SpringBootApplication標註的類)的所在包及下面全部子包裏面的全部組件掃描到Spring容器;
@Import(EnableAutoConfigurationImportSelector.class);
給容器中導入組件?
EnableAutoConfigurationImportSelector:導入哪些組件的選擇器;
將全部須要導入的組件以全類名的方式返回;這些組件就會被添加到容器中;
會給容器中導入很是多的自動配置類(xxxAutoConfiguration);就是給容器中導入這個場景須要的全部組件,
並配置好這些組件;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
1
2
3
4
5
6
7
8
9
10
1
2
3
有了自動配置類,免去了咱們手動編寫配置注入功能組件等的工做;
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);
Spring Boot在啓動的時候從類路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的值,將
這些值做爲自動配置類導入到容器中,自動配置類就生效,幫咱們進行自動配置工做;之前咱們須要本身配置的東
西,自動配置類都幫咱們;
J2EE的總體整合解決方案和自動配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar;
Spring註解版(穀粒學院)
六、使用Spring Initializer快速建立Spring Boot項目
一、IDEA:使用 Spring Initializer快速建立項目
IDE都支持使用Spring的項目建立嚮導快速建立一個Spring Boot項目;
選擇咱們須要的模塊;嚮導會聯網建立Spring Boot項目;
默認生成的Spring Boot項目;
主程序已經生成好了,咱們只須要咱們本身的邏輯
resources文件夾中目錄結構
static:保存全部的靜態資源; js css images;
templates:保存全部的模板頁面;(Spring Boot默認jar包使用嵌入式的Tomcat,默認不支持JSP頁
面);可使用模板引擎(freemarker、thymeleaf);
application.properties:Spring Boot應用的配置文件;能夠修改一些默認設置;
二、STS使用 Spring Starter Project快速建立項目
2、配置文件
一、配置文件
SpringBoot使用一個全局的配置文件,配置文件名是固定的;
•application.properties
•application.yml
配置文件的做用:修改SpringBoot自動配置的默認值;SpringBoot在底層都給咱們自動配置好;
YAML(YAML Ain't Markup Language)
YAML A Markup Language:是一個標記語言
YAML isn't Markup Language:不是一個標記語言;
標記語言:
之前的配置文件;大多都使用的是 xxxx.xml文件;
YAML:以數據爲中心,比json、xml等更適合作配置文件;
YAML:配置例子
XML:
二、YAML語法:
一、基本語法
k:(空格)v:表示一對鍵值對(空格必須有);
以空格的縮進來控制層級關係;只要是左對齊的一列數據,都是同一個層級的
server:
port: 8081
<server>
<port>8081</port>
</server>
1
2
1
2
3
屬性和值也是大小寫敏感;
二、值的寫法
字面量:普通的值(數字,字符串,布爾)
k: v:字面直接來寫;
字符串默認不用加上單引號或者雙引號;
"":雙引號;不會轉義字符串裏面的特殊字符;特殊字符會做爲自己想表示的意思
name: "zhangsan \n lisi":輸出;zhangsan 換行 lisi
'':單引號;會轉義特殊字符,特殊字符最終只是一個普通的字符串數據
name: ‘zhangsan \n lisi’:輸出;zhangsan \n lisi
對象、Map(屬性和值)(鍵值對):
k: v:在下一行來寫對象的屬性和值的關係;注意縮進
對象仍是k: v的方式
行內寫法:
數組(List、Set):
用- 值表示數組中的一個元素
行內寫法
server:
port: 8081
path: /hello
friends:
lastName: zhangsan
age: 20
friends: {lastName: zhangsan,age: 18}
pets:
‐ cat
‐ dog
‐ pig
1
2
3
1
2
3
1
1
2
3
4
三、配置文件值注入
配置文件
javaBean:
咱們能夠導入配置文件處理器,之後編寫配置就有提示了
pets: [cat,dog,pig]
person:
lastName: hello
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: 12}
lists:
‐ lisi
‐ zhaoliu
dog:
name: 小狗
age: 12
/**
* 將配置文件中配置的每個屬性的值,映射到這個組件中
* @ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定;
* prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射
*
* 只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能;
*
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
1
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ConfigurationProperties @Value
功能批量注入配置文件中的屬性一個個指定
鬆散綁定(鬆散語法) 支持不支持
SpEL 不支持支持
JSR303數據校驗支持不支持
複雜類型封裝支持不支持
一、properties配置文件在idea中默認utf-8可能會亂碼
調整
二、@Value獲取值和@ConfigurationProperties獲取值比較
配置文件yml仍是properties他們都能獲取到值;
<!‐‐導入配置文件處理器,配置文件進行綁定就會有提示‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>
1
2
3
4
5
6
若是說,咱們只是在某個業務邏輯中須要獲取一下配置文件中的某項值,使用@Value;
若是說,咱們專門編寫了一個javaBean來和配置文件進行映射,咱們就直接使用@ConfigurationProperties;
三、配置文件注入值數據校驗
四、@PropertySource&@ImportResource&@Bean
@PropertySource:加載指定的配置文件;
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}從環境變量、配置文件中獲取值/#
{SpEL}"></property>
* <bean/>
*/
//lastName必須是郵箱格式
@Email
//@Value("${person.last‐name}")
private String lastName;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
/**
* 將配置文件中配置的每個屬性的值,映射到這個組件中
* @ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定;
* prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射
*
* 只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能;
* @ConfigurationProperties(prefix = "person")默認從全局配置文件中獲取值;
*
*/
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
//@Validated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
2
3
4
5
6
7
8
9
10
11
12
13
@ImportResource:導入Spring的配置文件,讓配置文件裏面的內容生效;
Spring Boot裏面沒有Spring的配置文件,咱們本身編寫的配置文件,也不能自動識別;
想讓Spring的配置文件生效,加載進來;@ImportResource標註在一個配置類上
不來編寫Spring的配置文件
SpringBoot推薦給容器中添加組件的方式;推薦使用全註解的方式
一、配置類@Configuration------>Spring配置文件
二、使用@Bean給容器中添加組件
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}從環境變量、配置文件中獲取值/#
{SpEL}"></property>
* <bean/>
*/
//lastName必須是郵箱格式
// @Email
//@Value("${person.last‐name}")
private String lastName;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
@ImportResource(locations = {"classpath:beans.xml"})
導入Spring的配置文件讓其生效
<?xml version="1.0" encoding="UTF‐8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring‐beans.xsd">
<bean id="helloService" class="com.atguigu.springboot.service.HelloService"></bean>
</beans>
/**
* @Configuration:指明當前類是一個配置類;就是來替代以前的Spring配置文件
*
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
1
2
3
4
5
6
7
8
1
2
3
四、配置文件佔位符
一、隨機數
二、佔位符獲取以前配置的值,若是沒有能夠是用:指定默認值
五、Profile
一、多Profile文件
咱們在主配置文件編寫的時候,文件名能夠是 application-{profile}.properties/yml
默認使用application.properties的配置;
二、yml支持多文檔塊方式
* 在配置文件中用<bean><bean/>標籤添加組件
*
*/
@Configuration
public class MyAppConfig {
//將方法的返回值添加到容器中;容器中這個組件默認的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("配置類@Bean給容器中添加組件了...");
return new HelloService();
}
}
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
person.last‐name=張三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
1
2
3
4
5
6
7
8
9
三、激活指定profile
一、在配置文件中指定 spring.profiles.active=dev
二、命令行:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
能夠直接在測試的時候,配置傳入命令行參數
三、虛擬機參數;
-Dspring.profiles.active=dev
六、配置文件加載位置
springboot 啓動會掃描如下位置的application.properties或者application.yml文件做爲Spring boot的默認配置文
件
–file:./config/
–file:./
–classpath:/config/
–classpath:/
優先級由高到底,高優先級的配置會覆蓋低優先級的配置;
server:
port: 8081
spring:
profiles:
active: prod
‐‐‐
server:
port: 8083
spring:
profiles: dev
‐‐‐
server:
port: 8084
spring:
profiles: prod #指定屬於哪一個環境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SpringBoot會從這四個位置所有加載主配置文件;互補配置;
咱們還能夠經過spring.config.location來改變默認的配置文件位置
項目打包好之後,咱們可使用命令行參數的形式,啓動項目的時候來指定配置文件的新位置;指定配置文件和默
認加載的這些配置文件共同起做用造成互補配置;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
七、外部配置加載順序
SpringBoot也能夠從如下位置加載配置; 優先級從高到低;高優先級的配置覆蓋低優先級的配置,全部的配置會
造成互補配置
1.命令行參數
全部的配置均可以在命令行上進行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
多個配置用空格分開; --配置項=值
2.來自java:comp/env的JNDI屬性
3.Java系統屬性(System.getProperties())
4.操做系統環境變量
5.RandomValuePropertySource配置的random.*屬性值
由jar包外向jar包內進行尋找;
優先加載帶profile
6.jar包外部的application-{profile}.properties或application.yml(帶spring.profile)配置文件
7.jar包內部的application-{profile}.properties或application.yml(帶spring.profile)配置文件
再來加載不帶profile
8.jar包外部的application.properties或application.yml(不帶spring.profile)配置文件
9.jar包內部的application.properties或application.yml(不帶spring.profile)配置文件
10.@Configuration註解類上的@PropertySource
11.經過SpringApplication.setDefaultProperties指定的默認屬性
全部支持的配置加載來源;
參考官方文檔
八、自動配置原理
八、自動配置原理
配置文件到底能寫什麼?怎麼寫?自動配置原理;
配置文件能配置的屬性參照
一、自動配置原理:
1)、SpringBoot啓動的時候加載主配置類,開啓了自動配置功能 @EnableAutoConfiguration
2)、@EnableAutoConfiguration 做用:
利用EnableAutoConfigurationImportSelector給容器中導入一些組件?
能夠查看selectImports()方法的內容;
List configurations = getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置
將 類路徑下 META-INF/spring.factories 裏面配置的全部EnableAutoConfiguration的值加入到了容器中;
SpringFactoriesLoader.loadFactoryNames()
掃描全部jar包類路徑下 META‐INF/spring.factories
把掃描到的這些文件的內容包裝成properties對象
從properties中獲取到EnableAutoConfiguration.class類(類名)對應的值,而後把他們添加在容器
中
# 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,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,
\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration
,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration
,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration
1
2
3
4
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfi
guration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,
\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
每個這樣的 xxxAutoConfiguration類都是容器中的一個組件,都加入到容器中;用他們來作自動配置;
3)、每個自動配置類進行自動配置功能;
4)、以HttpEncodingAutoConfiguration(Http編碼自動配置)爲例解釋自動配置原理;
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
@Configuration //表示這是一個配置類,之前編寫的配置文件同樣,也能夠給容器中添加組件
@EnableConfigurationProperties(HttpEncodingProperties.class) //啓動指定類的
ConfigurationProperties功能;將配置文件中對應的值和HttpEncodingProperties綁定起來;並把
HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication //Spring底層@Conditional註解(Spring註解版),根據不一樣的條件,若是
知足指定的條件,整個配置類裏面的配置就會生效; 判斷當前應用是不是web應用,若是是,當前配置類生效
@ConditionalOnClass(CharacterEncodingFilter.class) //判斷當前項目有沒有這個類
CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing =
true) //判斷配置文件中是否存在某個配置 spring.http.encoding.enabled;若是不存在,判斷也是成立的
//即便咱們配置文件中不配置pring.http.encoding.enabled=true,也是默認生效的;
public class HttpEncodingAutoConfiguration {
//他已經和SpringBoot的配置文件映射了
private final HttpEncodingProperties properties;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
1
2
3
4
5
6
7
8
9
10
11
12
13
根據當前不一樣的條件判斷,決定這個配置類是否生效?
一但這個配置類生效;這個配置類就會給容器中添加各類組件;這些組件的屬性是從對應的properties類中獲取
的,這些類裏面的每個屬性又是和配置文件綁定的;
5)、全部在配置文件中能配置的屬性都是在xxxxProperties類中封裝者‘;配置文件能配置什麼就能夠參照某個功
能對應的這個屬性類
精髓:
1)、SpringBoot啓動會加載大量的自動配置類
2)、咱們看咱們須要的功能有沒有SpringBoot默認寫好的自動配置類;
3)、咱們再來看這個自動配置類中到底配置了哪些組件;(只要咱們要用的組件有,咱們就不須要再來配置了)
4)、給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。咱們就能夠在配置文件中指定這
些屬性的值;
xxxxAutoConfigurartion:自動配置類;
給容器中添加組件
//只有一個有參構造器的狀況下,參數的值就會從容器中拿
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean //給容器中添加一個組件,這個組件的某些值須要從properties中獲取
@ConditionalOnMissingBean(CharacterEncodingFilter.class) //判斷容器沒有這個組件?
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
@ConfigurationProperties(prefix = "spring.http.encoding") //從配置文件中獲取指定的值和bean的屬
性進行綁定
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF‐8");
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
@Conditional擴展註解做用(判斷是否知足當前指定條件)
@ConditionalOnJava 系統的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 知足SpEL表達式指定
@ConditionalOnClass 系統中有指定的類
@ConditionalOnMissingClass 系統中沒有指定的類
@ConditionalOnSingleCandidate 容器中只有一個指定的Bean,或者這個Bean是首選Bean
@ConditionalOnProperty 系統中指定的屬性是否有指定的值
@ConditionalOnResource 類路徑下是否存在指定資源文件
@ConditionalOnWebApplication 當前是web環境
@ConditionalOnNotWebApplication 當前不是web環境
@ConditionalOnJndi JNDI存在指定項
xxxxProperties:封裝配置文件中相關屬性;
二、細節
一、@Conditional派生註解(Spring註解版原生的@Conditional做用)
做用:必須是@Conditional指定的條件成立,纔給容器中添加組件,配置配裏面的全部內容才生效;
自動配置類必須在必定的條件下才能生效;
咱們怎麼知道哪些自動配置類生效;
咱們能夠經過啓用 debug=true屬性;來讓控制檯打印自動配置報告,這樣咱們就能夠很方便的知道哪些自動配置
類生效;
=========================
AUTO‐CONFIGURATION REPORT
=========================
Positive matches:(自動配置類啓用的)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
DispatcherServletAutoConfiguration matched:
1
2
3
4
5
6
7
8
9
3、日誌
一、日誌框架
小張;開發一個大型系統;
一、System.out.println("");將關鍵數據打印在控制檯;去掉?寫在一個文件?
二、框架來記錄系統的一些運行時信息;日誌框架 ; zhanglogging.jar;
三、高大上的幾個功能?異步模式?自動歸檔?xxxx? zhanglogging-good.jar?
四、將之前框架卸下來?換上新的框架,從新修改以前相關的API;zhanglogging-prefect.jar;
五、JDBC---數據庫驅動;
寫了一個統一的接口層;日誌門面(日誌的一個抽象層);logging-abstract.jar;
給項目中導入具體的日誌實現就好了;咱們以前的日誌框架都是實現的抽象層;
市面上的日誌框架;
JUL、JCL、Jboss-logging、logback、log4j、log4j二、slf4j....
‐ @ConditionalOnClass found required class
'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find
unwanted class (OnClassCondition)
‐ @ConditionalOnWebApplication (required) found StandardServletEnvironment
(OnWebApplicationCondition)
Negative matches:(沒有啓動,沒有匹配成功的自動配置類)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
ActiveMQAutoConfiguration:
Did not match:
‐ @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory',
'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
‐ @ConditionalOnClass did not find required classes
'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
日誌門面 (日誌的抽象層) 日誌實現
JCL(Jakarta Commons Logging) SLF4j(Simple Logging
Facade for Java) jboss-logging
Log4j JUL(java.util.logging)
Log4j2 Logback
左邊選一個門面(抽象層)、右邊來選一個實現;
日誌門面: SLF4J;
日誌實現:Logback;
SpringBoot:底層是Spring框架,Spring框架默認是用JCL;‘
SpringBoot選用 SLF4j和logback;
二、SLF4j使用
一、如何在系統中使用SLF4j https://www.slf4j.org
之後開發的時候,日誌記錄方法的調用,不該該來直接調用日誌的實現類,而是調用日誌抽象層裏面的方法;
給系統裏面導入slf4j的jar和 logback的實現jar
圖示;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
1
2
3
4
5
6
7
8
9
每個日誌的實現框架都有本身的配置文件。使用slf4j之後,配置文件仍是作成日誌實現框架本身自己的配置文
件;
二、遺留問題
a(slf4j+logback): Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、xxxx
統一日誌記錄,即便是別的框架和我一塊兒統一使用slf4j進行輸出?
如何讓系統中全部的日誌都統一到slf4j;
一、將系統中其餘日誌框架先排除出去;
二、用中間包來替換原有的日誌框架;
三、咱們導入slf4j其餘的實現
三、SpringBoot日誌關係
SpringBoot使用它來作日誌功能;
底層依賴關係
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>
1
2
3
4
1
2
3
4
總結:
1)、SpringBoot底層也是使用slf4j+logback的方式進行日誌記錄
2)、SpringBoot也把其餘的日誌都替換成了slf4j;
3)、中間替換包?
4)、若是咱們要引入其餘框架?必定要把這個框架的默認日誌依賴移除掉?
Spring框架用的是commons-logging;
@SuppressWarnings("rawtypes")
public abstract class LogFactory {
static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J =
"http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";
static LogFactory logFactory = new SLF4JLogFactory();
1
2
3
4
5
6
SpringBoot能自動適配全部的日誌,並且底層使用slf4j+logback的方式記錄日誌,引入其餘框架的時候,只須要
把這個框架依賴的日誌框架排除掉便可;
四、日誌使用;
一、默認配置
SpringBoot默認幫咱們配置好了日誌;
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring‐core</artifactId>
<exclusions>
<exclusion>
<groupId>commons‐logging</groupId>
<artifactId>commons‐logging</artifactId>
</exclusion>
</exclusions>
</dependency>
//記錄器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
//System.out.println();
//日誌的級別;
//由低到高 trace<debug<info<warn<error
//能夠調整輸出的日誌級別;日誌就只會在這個級別以之後的高級別生效
logger.trace("這是trace日誌...");
logger.debug("這是debug日誌...");
//SpringBoot默認給咱們使用的是info級別的,沒有指定級別的就用SpringBoot默認規定的級別;root
級別
logger.info("這是info日誌...");
logger.warn("這是warn日誌...");
logger.error("這是error日誌...");
}
日誌輸出格式:
%d表示日期時間,
%thread表示線程名,
%‐5level:級別從左顯示5個字符寬度
%logger{50} 表示logger名字最長50個字符,不然按照句點分割。
%msg:日誌消息,
%n是換行符
‐‐>
%d{yyyy‐MM‐dd HH:mm:ss.SSS} [%thread] %‐5level %logger{50} ‐ %msg%n
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
logging.file logging.path Example Description
(none) (none) 只在控制檯輸出
指定文件名(none) my.log 輸出日誌到my.log文件
(none) 指定目錄/var/log 輸出到指定目錄的 spring.log 文件中
Logging System Customization
Logback
logback-spring.xml , logback-spring.groovy , logback.xml or
logback.groovy
Log4j2 log4j2-spring.xml or log4j2.xml
JDK (Java Util
Logging)
logging.properties
SpringBoot修改日誌的默認配置
二、指定配置
給類路徑下放上每一個日誌框架本身的配置文件便可;SpringBoot就不使用他默認配置的了
logback.xml:直接就被日誌框架識別了;
logback-spring.xml:日誌框架就不直接加載日誌的配置項,由SpringBoot解析日誌配置,可使用SpringBoot
的高級Profile功能
logging.level.com.atguigu=trace
#logging.path=
# 不指定路徑在當前項目下生成springboot.log日誌
# 能夠指定完整的路徑;
#logging.file=G:/springboot.log
# 在當前磁盤的根路徑下建立spring文件夾和裏面的log文件夾;使用 spring.log 做爲默認文件
logging.path=/spring/log
# 在控制檯輸出的日誌的格式
logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n
# 指定文件中日誌輸出的格式
logging.pattern.file=%d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如:
若是使用logback.xml做爲日誌配置文件,還要使用profile功能,會有如下錯誤
no applicable action for [springProfile]
五、切換日誌框架
能夠按照slf4j的日誌適配圖,進行相關的切換;
slf4j+log4j的方式;
<springProfile name="staging">
<!‐‐ configuration to be enabled when the "staging" profile is active ‐‐>
能夠指定某段配置只在某個環境下生效
</springProfile>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!‐‐
日誌輸出格式:
%d表示日期時間,
%thread表示線程名,
%‐5level:級別從左顯示5個字符寬度
%logger{50} 表示logger名字最長50個字符,不然按照句點分割。
%msg:日誌消息,
%n是換行符
‐‐>
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
</layout>
</appender>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback‐classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>log4j‐over‐slf4j</artifactId>
1
2
3
4
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
切換爲log4j2
4、Web開發
一、簡介
使用SpringBoot;
1)、建立SpringBoot應用,選中咱們須要的模塊;
2)、SpringBoot已經默認將這些場景配置好了,只須要在配置文件中指定少許配置就能夠運行起來
3)、本身編寫業務代碼;
自動配置原理?
這個場景SpringBoot幫咱們配置了什麼?能不能修改?能修改哪些配置?能不能擴展?xxx
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j‐log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐log4j2</artifactId>
</dependency>
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
二、SpringBoot對靜態資源的映射規則;
xxxxAutoConfiguration:幫咱們給容器中自動配置組件;
xxxxProperties:配置類來封裝配置文件的內容;
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {
//能夠設置和靜態資源有關的參數,緩存時間等
WebMvcAuotConfiguration :
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(
registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META‐INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
//靜態資源文件夾映射
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
}
//配置歡迎頁映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
//配置喜歡的圖標
@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
public static class FaviconConfiguration {
1
2
3
1
2
3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1)、全部 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找資源;
webjars:以jar包的方式引入靜態資源;
http://www.webjars.org/
localhost:8080/webjars/jquery/3.3.1/jquery.js
public static class FaviconConfiguration {
private final ResourceProperties resourceProperties;
public FaviconConfiguration(ResourceProperties resourceProperties) {
this.resourceProperties = resourceProperties;
}
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
//全部 **/favicon.ico
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new
ResourceHttpRequestHandler();
requestHandler
.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
}
}
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2)、"/**" 訪問當前項目的任何資源,都去(靜態資源的文件夾)找映射
localhost:8080/abc === 去靜態資源文件夾裏面找abc
3)、歡迎頁; 靜態資源文件夾下的全部index.html頁面;被"/**"映射;
localhost:8080/ 找index頁面
4)、全部的 **/favicon.ico 都是在靜態資源文件下找;
三、模板引擎
JSP、Velocity、Freemarker、Thymeleaf
SpringBoot推薦的Thymeleaf;
語法更簡單,功能更強大;
<!‐‐引入jquery‐webjar‐‐>在訪問的時候只須要寫webjars下面資源的名稱便可
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":當前項目的根路徑
1
2
3
4
5
6
1
2
3
4
5
一、引入thymeleaf;
二、Thymeleaf使用
只要咱們把HTML頁面放在classpath:/templates/,thymeleaf就能自動渲染;
使用:
一、導入thymeleaf的名稱空間
二、使用thymeleaf語法;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐thymeleaf</artifactId>
2.1.6
</dependency>
切換thymeleaf版本
<properties>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!‐‐ 佈局功能的支持程序 thymeleaf3主程序 layout2以上版本 ‐‐>
<!‐‐ thymeleaf2 layout1‐‐>
<thymeleaf‐layout‐dialect.version>2.2.2</thymeleaf‐layout‐dialect.version>
</properties>
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF‐8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
//
<html lang="en" xmlns:th="http://www.thymeleaf.org">
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
1
三、語法規則
1)、th:text;改變當前元素裏面的文本內容;
th:任意html屬性;來替換原生屬性的值
2)、表達式?
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF‐8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!‐‐th:text 將div裏面的文本內容設置爲 ‐‐>
<div th:text="${hello}">這是顯示歡迎信息</div>
</body>
</html>
Simple expressions:(表達式語法)
Variable Expressions: ${...}:獲取變量值;OGNL;
1)、獲取對象的屬性、調用方法
2)、使用內置的基本對象:
#ctx : the context object.
#vars: the context variables.
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
#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.
${session.foo}
3)、內置的一些工具對象:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the
same way as they would be obtained using #{…} syntax.
#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.
#ids : methods for dealing with id attributes that might be repeated (for example, as a
result of an iteration).
Selection Variable Expressions: *{...}:選擇表達式:和${}在功能上是同樣;
補充:配合 th:object="${session.user}:
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
Message Expressions: #{...}:獲取國際化內容
Link URL Expressions: @{...}:定義URL;
@{/order/process(execId=${execId},execType='FAST')}
Fragment Expressions: ~{...}:片斷引用表達式
<div th:insert="~{commons :: main}">...</div>
Literals(字面量)
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations:(文本操做)
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations:(數學運算)
Binary operators: + , ‐ , * , / , %
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
四、SpringMVC自動配置
https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developingweb-
applications
1. Spring MVC auto-configuration
Spring Boot 自動配置好了SpringMVC
如下是SpringBoot對SpringMVC的默認配置:(WebMvcAutoConfiguration)
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
自動配置了ViewResolver(視圖解析器:根據方法的返回值獲得視圖對象(View),視圖對象決定如何
渲染(轉發?重定向?))
ContentNegotiatingViewResolver:組合全部的視圖解析器的;
如何定製:咱們能夠本身給容器中添加一個視圖解析器;自動的將其組合進來;
Support for serving static resources, including support for WebJars (see below).靜態資源文件夾路
徑,webjars
Static index.html support. 靜態首頁訪問
Custom Favicon support (see below). favicon.ico
自動註冊了 of Converter , GenericConverter , Formatter beans.
Converter:轉換器; public String hello(User user):類型轉換使用Converter
Formatter 格式化器; 2017.12.17===Date;
本身添加的格式化器轉換器,咱們只須要放在容器中便可
Support for HttpMessageConverters (see below).
Minus sign (unary operator): ‐
Boolean operations:(布爾運算)
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality:(比較運算)
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators:條件運算(三元運算符)
If‐then: (if) ? (then)
If‐then‐else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens:
No‐Operation: _
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格
式化的規則
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化組件
}
57
58
59
60
61
62
63
64
65
66
67
68
69
1
2
3
4
5
HttpMessageConverter:SpringMVC用來轉換Http請求和響應的;User---Json;
HttpMessageConverters 是從容器中肯定;獲取全部的HttpMessageConverter;
本身給容器中添加HttpMessageConverter,只須要將本身的組件註冊容器中
(@Bean,@Component)
Automatic registration of MessageCodesResolver (see below).定義錯誤代碼生成規則
Automatic use of a ConfigurableWebBindingInitializer bean (see below).
咱們能夠配置一個ConfigurableWebBindingInitializer來替換默認的;(添加到容器)
org.springframework.boot.autoconfigure.web:web的全部自動場景;
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration
(interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type
WebMvcConfigurerAdapter , but without @EnableWebMvc . If you wish to provide custom instances of
RequestMappingHandlerMapping , RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver
you can declare a WebMvcRegistrationsAdapter instance providing such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with
@EnableWebMvc .
二、擴展SpringMVC
編寫一個配置類(@Configuration),是WebMvcConfigurerAdapter類型;不能標註@EnableWebMvc;
既保留了全部的自動配置,也能用咱們擴展的配置;
初始化WebDataBinder;
請求數據=====JavaBean;
<mvc:view‐controller path="/hello" view‐name="success"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>
//使用WebMvcConfigurerAdapter能夠來擴展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//瀏覽器發送 /atguigu 請求來到 success
registry.addViewController("/atguigu").setViewName("success");
}
}
1
2
1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
10
11
原理:
1)、WebMvcAutoConfiguration是SpringMVC的自動配置類
2)、在作其餘自動配置時會導入;@Import(EnableWebMvcConfiguration.class)
3)、容器中全部的WebMvcConfigurer都會一塊兒起做用;
4)、咱們的配置類也會被調用;
效果:SpringMVC的自動配置和咱們的擴展配置都會起做用;
三、全面接管SpringMVC;
SpringBoot對SpringMVC的自動配置不須要了,全部都是咱們本身配置;全部的SpringMVC的自動配置都失效了
咱們須要在配置類中添加@EnableWebMvc便可;
原理:
爲何@EnableWebMvc自動配置就失效了;
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
//從容器中獲取全部的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
//一個參考實現;將全部的WebMvcConfigurer相關配置都來一塊兒調用;
@Override
// public void addViewControllers(ViewControllerRegistry registry) {
// for (WebMvcConfigurer delegate : this.delegates) {
// delegate.addViewControllers(registry);
// }
}
}
}
//使用WebMvcConfigurerAdapter能夠來擴展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//瀏覽器發送 /atguigu 請求來到 success
registry.addViewController("/atguigu").setViewName("success");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
1)@EnableWebMvc的核心
2)、
3)、
4)、@EnableWebMvc將WebMvcConfigurationSupport組件導入進來;
5)、導入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;
五、如何修改SpringBoot的默認配置
模式:
1)、SpringBoot在自動配置不少組件的時候,先看容器中有沒有用戶本身配置的(@Bean、@Component)如
果有就用用戶配置的,若是沒有,才自動配置;若是有些組件能夠有多個(ViewResolver)將用戶配置的和本身默
認的組合起來;
2)、在SpringBoot中會有很是多的xxxConfigurer幫助咱們進行擴展配置
3)、在SpringBoot中會有不少的xxxCustomizer幫助咱們進行定製配置
六、RestfulCRUD
1)、默認訪問首頁
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//容器中沒有這個組件的時候,這個自動配置類才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
//使用WebMvcConfigurerAdapter能夠來擴展SpringMVC的功能
//@EnableWebMvc 不要接管SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
1
2
1
2
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
2)、國際化
1)、編寫國際化配置文件;
2)、使用ResourceBundleMessageSource管理國際化資源文件
3)、在頁面使用fmt:message取出國際化內容
步驟:
1)、編寫國際化配置文件,抽取頁面須要顯示的國際化消息
2)、SpringBoot自動配置好了管理國際化資源文件的組件;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//瀏覽器發送 /atguigu 請求來到 success
registry.addViewController("/atguigu").setViewName("success");
}
//全部的WebMvcConfigurerAdapter組件都會一塊兒起做用
@Bean //將組件註冊在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
return adapter;
}
}
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
3)、去頁面獲取國際化的值;
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
/**
* Comma‐separated list of basenames (essentially a fully‐qualified classpath
* location), each following the ResourceBundle convention with relaxed support for
* slash based locations. If it doesn't contain a package qualifier (such as
* "org.mypackage"), it will be resolved from the classpath root.
*/
private String basename = "messages";
//咱們的配置文件能夠直接放在類路徑下叫messages.properties;
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(this.basename)) {
//設置國際化資源文件的基礎名(去掉語言國家代碼的)
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(this.basename)));
}
if (this.encoding != null) {
messageSource.setDefaultEncoding(this.encoding.name());
}
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
messageSource.setCacheSeconds(this.cacheSeconds);
messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
return messageSource;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
效果:根據瀏覽器語言設置的信息切換了國際化;
原理:
國際化Locale(區域信息對象);LocaleResolver(獲取區域信息對象);
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http‐equiv="Content‐Type" content="text/html; charset=UTF‐8">
<meta name="viewport" content="width=device‐width, initial‐scale=1, shrink‐tofit=
no">
<meta name="description" content="">
<meta name="author" content="">
<title>Signin Template for Bootstrap</title>
<!‐‐ Bootstrap core CSS ‐‐>
<link href="asserts/css/bootstrap.min.css"
th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
<!‐‐ Custom styles for this template ‐‐>
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}"
rel="stylesheet">
</head>
<body class="text‐center">
<form class="form‐signin" action="dashboard.html">
<img class="mb‐4" th:src="@{/asserts/img/bootstrap‐solid.svg}"
src="asserts/img/bootstrap‐solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb‐3 font‐weight‐normal" th:text="#{login.tip}">Please sign
in</h1>
<label class="sr‐only" th:text="#{login.username}">Username</label>
<input type="text" class="form‐control" placeholder="Username" th:placeholder="#
{login.username}" required="" autofocus="">
<label class="sr‐only" th:text="#{login.password}">Password</label>
<input type="password" class="form‐control" placeholder="Password"
th:placeholder="#{login.password}" required="">
<div class="checkbox mb‐3">
<label>
<input type="checkbox" value="remember‐me"/> [[#{login.remember}]]
</label>
</div>
<button class="btn btn‐lg btn‐primary btn‐block" type="submit" th:text="#
{login.btn}">Sign in</button>
<p class="mt‐5 mb‐3 text‐muted">© 2017‐2018</p>
<a class="btn btn‐sm">中文</a>
<a class="btn btn‐sm">English</a>
</form>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
4)、點擊連接切換國際化
3)、登錄
開發期間模板引擎頁面修改之後,要實時生效
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
默認的就是根據請求頭帶來的區域信息獲取Locale進行國際化
/**
* 能夠在鏈接上攜帶區域信息
*/
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
String[] split = l.split("_");
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale
locale) {
}
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1)、禁用模板引擎的緩存
2)、頁面修改完成之後ctrl+f9:從新編譯;
登錄錯誤消息的顯示
4)、攔截器進行登錄檢查
攔截器
# 禁用緩存
spring.thymeleaf.cache=false
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
/**
* 登錄檢查,
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目標方法執行以前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null){
//未登錄,返回登錄頁面
request.setAttribute("msg","沒有權限請先登錄");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
//已登錄,放行請求
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object
handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
1
2
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
普通CRUD(uri來區分操做) RestfulCRUD
查詢getEmp emp---GET
添加addEmp?xxx emp---POST
修改updateEmp?id=xxx&xxx=xx emp/{id}---PUT
刪除deleteEmp?id=1 emp/{id}---DELETE
註冊攔截器
5)、CRUD-員工列表
實驗要求:
1)、RestfulCRUD:CRUD知足Rest風格;
URI: /資源名稱/資源標識 HTTP請求方式區分對資源CRUD操做
2)、實驗的請求架構;
}
//全部的WebMvcConfigurerAdapter組件都會一塊兒起做用
@Bean //將組件註冊在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
//註冊攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//靜態資源; *.css , *.js
//SpringBoot已經作好了靜態資源映射
registry.addInterceptor(new
LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login");
}
};
return adapter;
}
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
實驗功能請求URI 請求方式
查詢全部員工emps GET
查詢某個員工(來到修改頁面) emp/1 GET
來到添加頁面emp GET
添加員工emp POST
來到修改頁面(查出員工進行信息回顯) emp/1 GET
修改員工emp PUT
刪除員工emp/1 DELETE
3)、員工列表:
thymeleaf公共頁面元素抽取
三種引入公共片斷的th屬性:
th:insert:將公共片斷整個插入到聲明引入的元素中
th:replace:將聲明引入的元素替換爲公共片斷
th:include:將被引入的片斷的內容包含進這個標籤中
一、抽取公共片斷
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
二、引入公共片斷
<div th:insert="~{footer :: copy}"></div>
~{templatename::selector}:模板名::選擇器
~{templatename::fragmentname}:模板名::片斷名
三、默認效果:
insert的公共片斷在div標籤中
若是使用th:insert等屬性進行引入,能夠不用寫~{}:
行內寫法能夠加上:[[~{}]];[(~{})];
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
引入方式
<div th:insert="footer :: copy"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
引入片斷的時候傳入參數:
6)、CRUD-員工添加
添加頁面
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
效果
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
<nav class="col‐md‐2 d‐none d‐md‐block bg‐light sidebar" id="sidebar">
<div class="sidebar‐sticky">
<ul class="nav flex‐column">
<li class="nav‐item">
<a class="nav‐link active"
th:class="${activeUri=='main.html'?'nav‐link active':'nav‐link'}"
href="#" th:href="@{/main.html}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke‐width="2" strokelinecap="
round" stroke‐linejoin="round" class="feather feather‐home">
<path d="M3 9l9‐7 9 7v11a2 2 0 0 1‐2 2H5a2 2 0 0 1‐2‐2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
Dashboard <span class="sr‐only">(current)</span>
</a>
</li>
<!‐‐引入側邊欄;傳入參數‐‐>
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
<form>
<div class="form‐group">
<label>LastName</label>
<input type="text" class="form‐control" placeholder="zhangsan">
</div>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
提交的數據格式不對:生日:日期;
2017-12-12;2017/12/12;2017.12.12;
日期的格式化;SpringMVC將頁面提交的值須要轉換爲指定的類型;
2017-12-12---Date; 類型轉換,格式化;
默認日期是按照/的方式;
7)、CRUD-員工修改
修改添加二合一表單
<div class="form‐group">
<label>Email</label>
<input type="email" class="form‐control" placeholder="zhangsan@atguigu.com">
</div>
<div class="form‐group">
<label>Gender</label><br/>
<div class="form‐check form‐check‐inline">
<input class="form‐check‐input" type="radio" name="gender" value="1">
<label class="form‐check‐label">男</label>
</div>
<div class="form‐check form‐check‐inline">
<input class="form‐check‐input" type="radio" name="gender" value="0">
<label class="form‐check‐label">女</label>
</div>
</div>
<div class="form‐group">
<label>department</label>
<select class="form‐control">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form‐group">
<label>Birth</label>
<input type="text" class="form‐control" placeholder="zhangsan">
</div>
<button type="submit" class="btn btn‐primary">添加</button>
</form>
<!‐‐須要區分是員工修改仍是添加;‐‐>
<form th:action="@{/emp}" method="post">
<!‐‐發送put請求修改員工數據‐‐>
<!‐‐
一、SpringMVC中配置HiddenHttpMethodFilter;(SpringBoot自動配置好的)
二、頁面建立一個post表單
三、建立一個input項,name="_method";值就是咱們指定的請求方式
‐‐>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
8)、CRUD-員工刪除
<input type="hidden" name="_method" value="put" th:if="${emp!=null}"/>
<input type="hidden" name="id" th:if="${emp!=null}" th:value="${emp.id}">
<div class="form‐group">
<label>LastName</label>
<input name="lastName" type="text" class="form‐control" placeholder="zhangsan"
th:value="${emp!=null}?${emp.lastName}">
</div>
<div class="form‐group">
<label>Email</label>
<input name="email" type="email" class="form‐control"
placeholder="zhangsan@atguigu.com" th:value="${emp!=null}?${emp.email}">
</div>
<div class="form‐group">
<label>Gender</label><br/>
<div class="form‐check form‐check‐inline">
<input class="form‐check‐input" type="radio" name="gender" value="1"
th:checked="${emp!=null}?${emp.gender==1}">
<label class="form‐check‐label">男</label>
</div>
<div class="form‐check form‐check‐inline">
<input class="form‐check‐input" type="radio" name="gender" value="0"
th:checked="${emp!=null}?${emp.gender==0}">
<label class="form‐check‐label">女</label>
</div>
</div>
<div class="form‐group">
<label>department</label>
<!‐‐提交的是部門的id‐‐>
<select class="form‐control" name="department.id">
<option th:selected="${emp!=null}?${dept.id == emp.department.id}"
th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
</select>
</div>
<div class="form‐group">
<label>Birth</label>
<input name="birth" type="text" class="form‐control" placeholder="zhangsan"
th:value="${emp!=null}?${#dates.format(emp.birth, 'yyyy‐MM‐dd HH:mm')}">
</div>
<button type="submit" class="btn btn‐primary" th:text="${emp!=null}?'修改':'添加'">添加
</button>
</form>
<tr th:each="emp:${emps}">
<td th:text="${emp.id}"></td>
<td>[[${emp.lastName}]]</td>
<td th:text="${emp.email}"></td>
<td th:text="${emp.gender}==0?'女':'男'"></td>
<td th:text="${emp.department.departmentName}"></td>
<td th:text="${#dates.format(emp.birth, 'yyyy‐MM‐dd HH:mm')}"></td>
<td>
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
1
2
3
4
5
6
7
8
七、錯誤處理機制
1)、SpringBoot默認的錯誤處理機制
默認效果:
1)、瀏覽器,返回一個默認的錯誤頁面
瀏覽器發送請求的請求頭:
2)、若是是其餘客戶端,默認響應一個json數據
<a class="btn btn‐sm btn‐primary" th:href="@{/emp/}+${emp.id}">編輯</a>
<button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn‐sm btn‐danger
deleteBtn">刪除</button>
</td>
</tr>
<script>
$(".deleteBtn").click(function(){
//刪除當前員工的
$("#deleteEmpForm").attr("action",$(this).attr("del_uri")).submit();
return false;
});
</script>
9
10
11
12
13
14
15
16
17
18
19
20
21
原理:
能夠參照ErrorMvcAutoConfiguration;錯誤處理的自動配置;
給容器中添加了如下組件
一、DefaultErrorAttributes:
二、BasicErrorController:處理默認/error請求
幫咱們在頁面共享信息;
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, requestAttributes);
addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
addPath(errorAttributes, requestAttributes);
return errorAttributes;
}
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
@RequestMapping(produces = "text/html")//產生html類型的數據;瀏覽器發送的請求來到這個方法處理
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
//去哪一個頁面做爲錯誤頁面;包含頁面地址和頁面內容
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
@RequestMapping
@ResponseBody //產生json數據,其餘客戶端來到這個方法處理;
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
三、ErrorPageCustomizer:
四、DefaultErrorViewResolver:
步驟:
一但系統出現4xx或者5xx之類的錯誤;ErrorPageCustomizer就會生效(定製錯誤的響應規則);就會來到/error
請求;就會被BasicErrorController處理;
1)響應頁面;去哪一個頁面是由DefaultErrorViewResolver解析獲得的;
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
@Value("${error.path:/error}")
private String path = "/error"; 系統出現錯誤之後來到error請求進行處理;(web.xml註冊的錯誤頁
面規則)
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model) {
ModelAndView modelAndView = resolve(String.valueOf(status), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//默認SpringBoot能夠去找到一個頁面? error/404
String errorViewName = "error/" + viewName;
//模板引擎能夠解析這個頁面地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
.getProvider(errorViewName, this.applicationContext);
if (provider != null) {
//模板引擎可用的狀況下返回到errorViewName指定的視圖地址
return new ModelAndView(errorViewName, model);
}
//模板引擎不可用,就在靜態資源文件夾下找errorViewName對應的頁面 error/404.html
return resolveResource(errorViewName, model);
}
20
21
22
23
24
25
1
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2)、若是定製錯誤響應:
1)、如何定製錯誤的頁面;
1)、有模板引擎的狀況下;error/狀態碼; 【將錯誤頁面命名爲 錯誤狀態碼.html 放在模板引擎文件夾裏面的
error文件夾下】,發生此狀態碼的錯誤就會來到 對應的頁面;
咱們可使用4xx和5xx做爲錯誤頁面的文件名來匹配這種類型的全部錯誤,精確優先(優先尋找精確的狀態
碼.html);
頁面能獲取的信息;
timestamp:時間戳
status:狀態碼
error:錯誤提示
exception:異常對象
message:異常消息
errors:JSR303數據校驗的錯誤都在這裏
2)、沒有模板引擎(模板引擎找不到這個錯誤頁面),靜態資源文件夾下找;
3)、以上都沒有錯誤頁面,就是默認來到SpringBoot默認的錯誤提示頁面;
2)、如何定製錯誤的json數據;
1)、自定義異常處理&返回定製json數據;
protected ModelAndView resolveErrorView(HttpServletRequest request,
HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
//全部的ErrorViewResolver獲得ModelAndView
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
1
2
3
4
5
6
7
8
9
10
11
2)、轉發到/error進行自適應響應效果處理
3)、將咱們的定製數據攜帶出去;
出現錯誤之後,會來到/error請求,會被BasicErrorController處理,響應出去能夠獲取的數據是由
getErrorAttributes獲得的(是AbstractErrorController(ErrorController)規定的方法);
一、徹底來編寫一個ErrorController的實現類【或者是編寫AbstractErrorController的子類】,放在容器中;
二、頁面上能用的數據,或者是json返回能用的數據都是經過errorAttributes.getErrorAttributes獲得;
容器中DefaultErrorAttributes.getErrorAttributes();默認進行數據處理的;
自定義ErrorAttributes
@ControllerAdvice
public class MyExceptionHandler {
@ResponseBody
@ExceptionHandler(UserNotExistException.class)
public Map<String,Object> handleException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","user.notexist");
map.put("message",e.getMessage());
return map;
}
}
//沒有自適應效果...
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//傳入咱們本身的錯誤狀態碼 4xx 5xx,不然就不會進入定製錯誤頁面的解析流程
/**
* Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
*/
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user.notexist");
map.put("message",e.getMessage());
//轉發到/error
return "forward:/error";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
最終的效果:響應是自適應的,能夠經過定製ErrorAttributes改變須要返回的內容,
八、配置嵌入式Servlet容器
SpringBoot默認使用Tomcat做爲嵌入式的Servlet容器;
問題?
1)、如何定製和修改Servlet容器的相關配置;
一、修改和server有關的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】);
//給容器中加入咱們本身定義的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes,
includeStackTrace);
map.put("company","atguigu");
return map;
}
}
1
2
3
4
5
6
7
8
9
10
11
二、編寫一個EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定製器;來修改Servlet容器的
配置
2)、註冊Servlet三大組件【Servlet、Filter、Listener】
因爲SpringBoot默認是以jar包的方式啓動嵌入式的Servlet容器來啓動SpringBoot的web應用,沒有web.xml文
件。
註冊三大組件用如下方式
ServletRegistrationBean
FilterRegistrationBean
server.port=8081
server.context‐path=/crud
server.tomcat.uri‐encoding=UTF‐8
//通用的Servlet容器設置
server.xxx
//Tomcat的設置
server.tomcat.xxx
@Bean //必定要將這個定製器加入到容器中
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
//定製嵌入式的Servlet容器相關的規則
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
//註冊三大組件
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new
MyServlet(),"/myServlet");
return registrationBean;
}
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
ServletListenerRegistrationBean
SpringBoot幫咱們自動SpringMVC的時候,自動的註冊SpringMVC的前端控制器;DIspatcherServlet;
DispatcherServletAutoConfiguration中:
2)、SpringBoot能不能支持其餘的Servlet容器;
3)、替換爲其餘嵌入式Servlet容器
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new
ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name =
DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public ServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet, this.serverProperties.getServletMapping());
//默認攔截: / 全部請求;包靜態資源,可是不攔截jsp請求; /*會攔截jsp
//能夠經過server.servletPath來修改SpringMVC前端控制器默認攔截的請求路徑
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
1
2
3
4
5
6
7
1
2
3
4
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
默認支持:
Tomcat(默認使用)
Jetty
Undertow
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
引入web模塊默認就是使用嵌入式的Tomcat做爲Servlet容器;
</dependency>
<!‐‐ 引入web模塊 ‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!‐‐引入其餘的Servlet容器‐‐>
<dependency>
<artifactId>spring‐boot‐starter‐jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
<!‐‐ 引入web模塊 ‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
1
2
3
4
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
4)、嵌入式Servlet容器自動配置原理;
EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自動配置?
<!‐‐引入其餘的Servlet容器‐‐>
<dependency>
<artifactId>spring‐boot‐starter‐undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//導入BeanPostProcessorsRegistrar:Spring註解版;給容器中導入一些組件
//導入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//後置處理器:bean初始化先後(建立完對象,還沒賦值賦值)執行初始化工做
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })//判斷當前是否引入了Tomcat依賴;
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)//判斷當前容器沒有用戶本身定義EmbeddedServletContainerFactory:嵌入式的
Servlet容器工廠;做用:建立嵌入式的Servlet容器
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory()
{
return new TomcatEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
WebAppContext.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
return new JettyEmbeddedServletContainerFactory();
}
}
/**
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1)、EmbeddedServletContainerFactory(嵌入式Servlet容器工廠)
2)、EmbeddedServletContainer:(嵌入式的Servlet容器)
3)、以TomcatEmbeddedServletContainerFactory爲例
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowEmbeddedServletContainerFactory
undertowEmbeddedServletContainerFactory() {
return new UndertowEmbeddedServletContainerFactory();
}
}
public interface EmbeddedServletContainerFactory {
//獲取嵌入式的Servlet容器
EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers);
}
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
//建立一個Tomcat
Tomcat tomcat = new Tomcat();
//配置Tomcat的基本環節
File baseDir = (this.baseDirectory != null ? this.baseDirectory
38
39
40
41
42
43
44
45
46
47
48
49
50
51
1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
4)、咱們對嵌入式容器的配置修改是怎麼生效?
EmbeddedServletContainerCustomizer:定製器幫咱們修改了Servlet容器的配置?
怎麼修改的原理?
5)、容器中導入了EmbeddedServletContainerCustomizerBeanPostProcessor
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
//將配置好的Tomcat傳入進去,返回一個EmbeddedServletContainer;而且啓動Tomcat服務器
return getTomcatEmbeddedServletContainer(tomcat);
}
ServerProperties、EmbeddedServletContainerCustomizer
//初始化以前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
//若是當前初始化的是一個ConfigurableEmbeddedServletContainer類型的組件
if (bean instanceof ConfigurableEmbeddedServletContainer) {
//
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
//獲取全部的定製器,調用每個定製器的customize方法來給Servlet容器進行屬性賦值;
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
步驟:
1)、SpringBoot根據導入的依賴狀況,給容器中添加相應的
EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)、容器中某個組件要建立對象就會驚動後置處理器;
EmbeddedServletContainerCustomizerBeanPostProcessor;
只要是嵌入式的Servlet容器工廠,後置處理器就工做;
3)、後置處理器,從容器中獲取全部的EmbeddedServletContainerCustomizer,調用定製器的定製方法
5)、嵌入式Servlet容器啓動原理;
何時建立嵌入式的Servlet容器工廠?何時獲取嵌入式的Servlet容器並啓動Tomcat;
獲取嵌入式的Servlet容器工廠:
1)、SpringBoot應用啓動運行run方法
2)、refreshContext(context);SpringBoot刷新IOC容器【建立IOC容器對象,並初始化容器,建立容器中的每一
個組件】;若是是web應用建立AnnotationConfigEmbeddedWebApplicationContext,不然:
AnnotationConfigApplicationContext
3)、refresh(context);刷新剛纔建立好的ioc容器;
this.beanFactory
//從容器中獲取全部這葛類型的組件:EmbeddedServletContainerCustomizer
//定製Servlet容器,給容器中能夠添加一個EmbeddedServletContainerCustomizer類型的組件
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
ServerProperties也是定製器
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post‐processing of the bean factory in context subclasses.
25
26
27
28
29
30
31
32
33
34
35
36
37
1
2
3
4
5
6
7
8
9
10
11
12
13
4)、 onRefresh(); web的ioc容器重寫了onRefresh方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non‐lazy‐init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization ‐ " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
5)、webioc容器會建立嵌入式的Servlet容器;createEmbeddedServletContainer();
6)、獲取嵌入式的Servlet容器工廠:
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
從ioc容器中獲取EmbeddedServletContainerFactory 組件;TomcatEmbeddedServletContainerFactory建立
對象,後置處理器一看是這個對象,就獲取全部的定製器來先定製Servlet容器的相關配置;
7)、使用容器工廠獲取嵌入式的Servlet容器:this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
8)、嵌入式的Servlet容器建立對象並啓動Servlet容器;
先啓動嵌入式的Servlet容器,再將ioc容器中剩下沒有建立出的對象獲取出來;
IOC容器啓動建立嵌入式的Servlet容器
九、使用外置的Servlet容器
嵌入式Servlet容器:應用打成可執行的jar
優勢:簡單、便攜;
缺點:默認不支持JSP、優化定製比較複雜(使用定製器【ServerProperties、自定義
EmbeddedServletContainerCustomizer】,本身編寫嵌入式Servlet容器的建立工廠
【EmbeddedServletContainerFactory】);
外置的Servlet容器:外面安裝Tomcat---應用war包的方式打包;
步驟
1)、必須建立一個war項目;(利用idea建立好目錄結構)
2)、將嵌入式的Tomcat指定爲provided;
3)、必須編寫一個SpringBootServletInitializer的子類,並調用configure方法
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<scope>provided</scope>
</dependency>
1
2
3
4
5
4)、啓動服務器就可使用;
原理
jar包:執行SpringBoot主類的main方法,啓動ioc容器,建立嵌入式的Servlet容器;
war包:啓動服務器,服務器啓動SpringBoot應用【SpringBootServletInitializer】,啓動ioc容器;
servlet3.0(Spring註解版):
8.2.4 Shared libraries / runtimes pluggability:
規則:
1)、服務器啓動(web應用啓動)會建立當前web應用裏面每個jar包裏面ServletContainerInitializer實例:
2)、ServletContainerInitializer的實現放在jar包的META-INF/services文件夾下,有一個名爲
javax.servlet.ServletContainerInitializer的文件,內容就是ServletContainerInitializer的實現類的全類名
3)、還可使用@HandlesTypes,在應用啓動的時候加載咱們感興趣的類;
流程:
1)、啓動Tomcat
2)、org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\METAINF\
services\javax.servlet.ServletContainerInitializer:
Spring的web模塊裏面有這個文件:org.springframework.web.SpringServletContainerInitializer
3)、SpringServletContainerInitializer將@HandlesTypes(WebApplicationInitializer.class)標註的全部這個類型
的類都傳入到onStartup方法的Set>;爲這些WebApplicationInitializer類型的類建立實例;
4)、每個WebApplicationInitializer都調用本身的onStartup;
5)、至關於咱們的SpringBootServletInitializer的類會被建立對象,並執行onStartup方法
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//傳入SpringBoot應用的主程序
return application.sources(SpringBoot04WebJspApplication.class);
}
}
1
2
3
4
5
6
7
8
9
6)、SpringBootServletInitializer實例執行onStartup的時候會createRootApplicationContext;建立容器
7)、Spring的應用就啓動而且建立IOC容器
protected WebApplicationContext createRootApplicationContext(
ServletContext servletContext) {
//一、建立SpringApplicationBuilder
SpringApplicationBuilder builder = createSpringApplicationBuilder();
StandardServletEnvironment environment = new StandardServletEnvironment();
environment.initPropertySources(servletContext, null);
builder.environment(environment);
builder.main(getClass());
ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
if (parent != null) {
this.logger.info("Root context already created (using as parent).");
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
builder.initializers(new ParentContextApplicationContextInitializer(parent));
}
builder.initializers(
new ServletContextApplicationContextInitializer(servletContext));
builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
//調用configure方法,子類重寫了這個方法,將SpringBoot的主程序類傳入了進來
builder = configure(builder);
//使用builder建立一個Spring應用
SpringApplication application = builder.build();
if (application.getSources().isEmpty() && AnnotationUtils
.findAnnotation(getClass(), Configuration.class) != null) {
application.getSources().add(getClass());
}
Assert.state(!application.getSources().isEmpty(),
"No SpringApplication sources have been defined. Either override the "
+ "configure method or add an @Configuration annotation");
// Ensure error pages are registered
if (this.registerErrorPageFilter) {
application.getSources().add(ErrorPageFilterConfiguration.class);
}
//啓動Spring應用
return run(application);
}
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
啓動Servlet容器,再啓動SpringBoot應用
5、Docker
一、簡介
Docker是一個開源的應用容器引擎;是一個輕量級容器技術;
Docker支持將軟件編譯成一個鏡像;而後在鏡像中各類軟件作好配置,將鏡像發佈出去,其餘使用者能夠直接使
用這個鏡像;
運行中的這個鏡像稱爲容器,容器啓動是很是快速的。
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新IOC容器
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
二、核心概念
docker主機(Host):安裝了Docker程序的機器(Docker直接安裝在操做系統之上);
docker客戶端(Client):鏈接docker主機進行操做;
docker倉庫(Registry):用來保存各類打包好的軟件鏡像;
docker鏡像(Images):軟件打包好的鏡像;放在docker倉庫中;
docker容器(Container):鏡像啓動後的實例稱爲一個容器;容器是獨立運行的一個或一組應用
使用Docker的步驟:
1)、安裝Docker
2)、去Docker倉庫找到這個軟件對應的鏡像;
3)、使用Docker運行這個鏡像,這個鏡像就會生成一個Docker容器;
4)、對容器的啓動中止就是對軟件的啓動中止;
三、安裝Docker
1)、安裝linux虛擬機
1)、VMWare、VirtualBox(安裝);
2)、導入虛擬機文件centos7-atguigu.ova;
3)、雙擊啓動linux虛擬機;使用 root/ 123456登錄
4)、使用客戶端鏈接linux服務器進行命令操做;
5)、設置虛擬機網絡;
橋接網絡=選好網卡==接入網線;
6)、設置好網絡之後使用命令重啓虛擬機的網絡
service 1 network restart
操
做
命令說明
檢
索
docker search 關鍵字 eg:docker
search redis
咱們常常去docker hub上檢索鏡像的詳細信息,如鏡
像的TAG。
拉
取
docker pull 鏡像名:tag
:tag是可選的,tag表示標籤,多爲軟件的版本,默認
是latest
列
表
docker images 查看全部本地鏡像
刪
除
docker rmi image-id 刪除指定的本地鏡像
7)、查看linux的ip地址
8)、使用客戶端鏈接linux;
2)、在linux虛擬機上安裝docker
步驟:
四、Docker經常使用命令&操做
1)、鏡像操做
https://hub.docker.com/
2)、容器操做
ip addr
一、檢查內核版本,必須是3.10及以上
uname ‐r
二、安裝docker
yum install docker
三、輸入y確認安裝
四、啓動docker
[root@localhost ~]# systemctl start docker
[root@localhost ~]# docker ‐v
Docker version 1.12.6, build 3e8e77d/1.12.6
五、開機啓動docker
[root@localhost ~]# systemctl enable docker
Created symlink from /etc/systemd/system/multi‐user.target.wants/docker.service to
/usr/lib/systemd/system/docker.service.
六、中止docker
systemctl stop docker
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
軟件鏡像(QQ安裝程序)----運行鏡像----產生一個容器(正在運行的軟件,運行的QQ);
步驟:
3)、安裝MySQL示例
錯誤的啓動
一、搜索鏡像
[root@localhost ~]# docker search tomcat
二、拉取鏡像
[root@localhost ~]# docker pull tomcat
三、根據鏡像啓動容器
docker run ‐‐name mytomcat ‐d tomcat:latest
四、docker ps
查看運行中的容器
五、 中止運行中的容器
docker stop 容器的id
六、查看全部的容器
docker ps ‐a
七、啓動容器
docker start 容器id
八、刪除一個容器
docker rm 容器id
九、啓動一個作了端口映射的tomcat
[root@localhost ~]# docker run ‐d ‐p 8888:8080 tomcat
‐d:後臺運行
‐p: 將主機的端口映射到容器的一個端口 主機端口:容器內部的端口
十、爲了演示簡單關閉了linux的防火牆
service firewalld status ;查看防火牆狀態
service firewalld stop:關閉防火牆
十一、查看容器的日誌
docker logs container‐name/container‐id
更多命令參看
https://docs.docker.com/engine/reference/commandline/docker/
能夠參考每個鏡像的文檔
docker pull mysql
[root@localhost ~]# docker run ‐‐name mysql01 ‐d mysql
42f09819908bb72dd99ae19e792e0a5d03c48638421fa64cce5f8ba0f40f5846
mysql退出了
[root@localhost ~]# docker ps ‐a
CONTAINER ID IMAGE COMMAND CREATED STATUS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
1
2
3
4
5
6
正確的啓動
作了端口映射
幾個其餘的高級操做
PORTS NAMES
42f09819908b mysql "docker‐entrypoint.sh" 34 seconds ago Exited
(1) 33 seconds ago mysql01
538bde63e500 tomcat "catalina.sh run" About an hour ago Exited
(143) About an hour ago compassionate_
goldstine
c4f1ac60b3fc tomcat "catalina.sh run" About an hour ago Exited
(143) About an hour ago lonely_fermi
81ec743a5271 tomcat "catalina.sh run" About an hour ago Exited
(143) About an hour ago sick_ramanujan
//錯誤日誌
[root@localhost ~]# docker logs 42f09819908b
error: database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and
MYSQL_RANDOM_ROOT_PASSWORD;這個三個參數必須指定一個
[root@localhost ~]# docker run ‐‐name mysql01 ‐e MYSQL_ROOT_PASSWORD=123456 ‐d mysql
b874c56bec49fb43024b3805ab51e9097da779f2f572c22c695305dedd684c5f
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
b874c56bec49 mysql "docker‐entrypoint.sh" 4 seconds ago Up 3
seconds 3306/tcp mysql01
[root@localhost ~]# docker run ‐p 3306:3306 ‐‐name mysql02 ‐e MYSQL_ROOT_PASSWORD=123456 ‐d
mysql
ad10e4bc5c6a0f61cbad43898de71d366117d120e39db651844c0e73863b9434
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
ad10e4bc5c6a mysql "docker‐entrypoint.sh" 4 seconds ago Up 2
seconds 0.0.0.0:3306‐>3306/tcp mysql02
docker run ‐‐name mysql03 ‐v /conf/mysql:/etc/mysql/conf.d ‐e MYSQL_ROOT_PASSWORD=my‐secret‐pw
‐d mysql:tag
把主機的/conf/mysql文件夾掛載到 mysqldocker容器的/etc/mysql/conf.d文件夾裏面
改mysql的配置文件就只須要把mysql配置文件放在自定義的文件夾下(/conf/mysql)
docker run ‐‐name some‐mysql ‐e MYSQL_ROOT_PASSWORD=my‐secret‐pw ‐d mysql:tag ‐‐character‐setserver=
utf8mb4 ‐‐collation‐server=utf8mb4_unicode_ci
指定mysql的一些配置參數
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
6
6、SpringBoot與數據訪問
一、JDBC
效果:
默認是用org.apache.tomcat.jdbc.pool.DataSource做爲數據源;
數據源的相關配置都在DataSourceProperties裏面;
自動配置原理:
org.springframework.boot.autoconfigure.jdbc:
一、參考DataSourceConfiguration,根據配置建立數據源,默認使用Tomcat鏈接池;可使用
spring.datasource.type指定自定義的數據源類型;
二、SpringBoot默承認以支持;
三、自定義數據源類型
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
<scope>runtime</scope>
</dependency>
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.15.22:3306/jdbc
driver‐class‐name: com.mysql.jdbc.Driver
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
1
1
2
3
4
5
6
7
四、DataSourceInitializer:ApplicationListener;
做用:
1)、runSchemaScripts();運行建表語句;
2)、runDataScripts();運行插入數據的sql語句;
默認只須要將文件命名爲:
五、操做數據庫:自動配置了JdbcTemplate操做數據庫
二、整合Druid數據源
@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceBuilder建立數據源,利用反射建立響應type的數據源,而且綁定相關屬性
return properties.initializeDataSourceBuilder().build();
}
}
schema‐*.sql、data‐*.sql
默認規則:schema.sql,schema‐all.sql;
可使用
schema:
‐ classpath:department.sql
指定位置
導入druid數據源
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的監控
//一、配置一個管理後臺的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(),
"/druid/*");
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默認就是容許全部訪問
initParams.put("deny","192.168.15.21");
bean.setInitParameters(initParams);
8
9
10
11
12
13
14
1
2
3
4
5
6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
三、整合MyBatis
步驟:
1)、配置數據源相關屬性(見上一節Druid)
2)、給數據庫建表
3)、建立JavaBean
4)、註解版
return bean;
}
//二、配置一個web監控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis‐spring‐boot‐starter</artifactId>
<version>1.3.1</version>
</dependency>
//指定這是一個操做數據庫的mapper
@Mapper
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
1
2
3
4
5
1
2
問題:
自定義MyBatis的配置規則;給容器中添加一個ConfigurationCustomizer;
5)、配置文件版
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer(){
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
使用MapperScan批量掃描全部的Mapper接口;
@MapperScan(value = "com.atguigu.springboot.mapper")
@SpringBootApplication
public class SpringBoot06DataMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot06DataMybatisApplication.class, args);
}
}
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
更多使用參照
http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
四、整合SpringData JPA
1)、SpringData簡介
2)、整合SpringData JPA
JPA:ORM(Object Relational Mapping);
1)、編寫一個實體類(bean)和數據表進行映射,而且配置好映射關係;
mybatis:
config‐location: classpath:mybatis/mybatis‐config.xml 指定全局配置文件的位置
mapper‐locations: classpath:mybatis/mapper/*.xml 指定sql映射文件的位置
1
2
3
2)、編寫一個Dao接口來操做實體類對應的數據表(Repository)
3)、基本的配置JpaProperties
7、啓動配置原理
幾個重要的事件回調機制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
只須要放在ioc容器中
ApplicationRunner
CommandLineRunner
//使用JPA註解配置映射關係
@Entity //告訴JPA這是一個實體類(和數據表映射的類)
@Table(name = "tbl_user") //@Table來指定和哪一個數據表對應;若是省略默認表名就是user;
public class User {
@Id //這是一個主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主鍵
private Integer id;
@Column(name = "last_name",length = 50) //這是和數據表對應的一個列
private String lastName;
@Column //省略默認列名就是屬性名
private String email;
//繼承JpaRepository來完成對數據庫的操做
public interface UserRepository extends JpaRepository<User,Integer> {
}
spring:
jpa:
hibernate:
# 更新或者建立數據表結構
ddl‐auto: update
# 控制檯顯示SQL
show‐sql: true
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
1
2
3
4
5
6
7
啓動流程:
一、建立SpringApplication對象
二、運行run方法
initialize(sources);
private void initialize(Object[] sources) {
//保存主配置類
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判斷當前是否一個web應用
this.webEnvironment = deduceWebEnvironment();
//從類路徑下找到META‐INF/spring.factories配置的全部ApplicationContextInitializer;而後保存起
來
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//從類路徑下找到ETA‐INF/spring.factories配置的全部ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//從多個配置類中找到有main方法的主配置類
this.mainApplicationClass = deduceMainApplicationClass();
}
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//獲取SpringApplicationRunListeners;從類路徑下META‐INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回調全部的獲取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封裝命令行參數
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//準備環境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//建立環境完成後回調SpringApplicationRunListener.environmentPrepared();表示環境準
備完成
Banner printedBanner = printBanner(environment);
//建立ApplicationContext;決定建立web的ioc仍是普通的ioc
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//準備上下文環境;將environment保存到ioc中;並且applyInitializers();
//applyInitializers():回調以前保存的全部的ApplicationContextInitializer的initialize方法
//回調全部的SpringApplicationRunListener的contextPrepared();
//
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//prepareContext運行完成之後回調全部的SpringApplicationRunListener的contextLoaded();
//s刷新容器;ioc容器初始化(若是是web應用還會建立嵌入式的Tomcat);Spring註解版
//掃描,建立,加載全部組件的地方;(配置類,組件,自動配置)
refreshContext(context);
//從ioc容器中獲取全部的ApplicationRunner和CommandLineRunner進行回調
//ApplicationRunner先回調,CommandLineRunner再回調
afterRefresh(context, applicationArguments);
//全部的SpringApplicationRunListener回調finished方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整個SpringBoot應用啓動完成之後返回啓動的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
三、事件監聽機制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
public class HelloApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);
}
}
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
//必須有的構造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override
public void starting() {
System.out.println("SpringApplicationRunListener...starting...");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemProperties().get("os.name");
System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextPrepared...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextLoaded...");
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener...finished...");
}
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
配置(META-INF/spring.factories)
只須要放在ioc容器中
ApplicationRunner
CommandLineRunner
8、自定義starter
starter:
一、這個場景須要使用到的依賴是什麼?
二、如何編寫自動配置
org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}
34
1
2
3
4
5
1
2
3
4
5
6
7
1
2
3
4
5
6
7
三、模式:
啓動器只用來作依賴導入;
專門來寫一個自動配置模塊;
啓動器依賴自動配置;別人只須要引入啓動器(starter)
mybatis-spring-boot-starter;自定義啓動器名-spring-boot-starter
步驟:
1)、啓動器模塊
@Configuration //指定這個類是一個配置類
@ConditionalOnXXX //在指定條件成立的狀況下自動配置類生效
@AutoConfigureAfter //指定自動配置類的順序
@Bean //給容器中添加組件
@ConfigurationPropertie結合相關xxxProperties類來綁定相關的配置
@EnableConfigurationProperties //讓xxxProperties生效加入到容器中
自動配置類要能加載
將須要啓動就加載的自動配置類,配置在META‐INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
<?xml version="1.0" encoding="UTF‐8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven‐4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.starter</groupId>
<artifactId>atguigu‐spring‐boot‐starter</artifactId>
<version>1.0‐SNAPSHOT</version>
<!‐‐啓動器‐‐>
<dependencies>
<!‐‐引入自動配置模塊‐‐>
<dependency>
<groupId>com.atguigu.starter</groupId>
<artifactId>atguigu‐spring‐boot‐starter‐autoconfigurer</artifactId>
<version>0.0.1‐SNAPSHOT</version>
</dependency>
</dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2)、自動配置模塊
<?xml version="1.0" encoding="UTF‐8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven‐
4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.starter</groupId>
<artifactId>atguigu‐spring‐boot‐starter‐autoconfigurer</artifactId>
<version>0.0.1‐SNAPSHOT</version>
<packaging>jar</packaging>
<name>atguigu‐spring‐boot‐starter‐autoconfigurer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!‐‐ lookup parent from repository ‐‐>
</parent>
<properties>
<project.build.sourceEncoding>UTF‐8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF‐8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!‐‐引入spring‐boot‐starter;全部starter的基本配置‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter</artifactId>
</dependency>
</dependencies>
</project>
package com.atguigu.starter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "atguigu.hello")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
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;
}
}
package com.atguigu.starter;
public class HelloService {
HelloProperties helloProperties;
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHellAtguigu(String name){
return helloProperties.getPrefix()+"‐" +name + helloProperties.getSuffix();
}
}
package com.atguigu.starter;
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
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
更多SpringBoot整合示例
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samplescss