springBoot 基礎入門

來處:是spring項目中的一個子項目css

 

優勢  (被稱爲搭建項目的腳手架)html

        減小一切xml配置,作到開箱即用,快速上手,專一於業務而非配置前端

    從建立項目上: -- 快速建立獨立運行的spring項目以及與主流框架集成(雲計算)java

     從運行項目上:--使用嵌入式的Servlet 容器,應用無需打成war包    直接打成jar包使用java -jar就能夠啓動mysql

    從項目jar包上 :-- starters 自動依賴與版本控制,大量的自動配置。jquery

    

微服務:linux

     一個應用就是一組小型的服務,能夠經過http的方式進行互通git

     每個功能元素最終都是一個可獨立替換和獨立升級的軟件單元web

     查看maven版本  mvn -vredis

    搭建一個springboot應用(由淺到深的瞭解便於記憶)

       1. 1.1同以往搭建項目同樣首先重視的就是環境配置 

                 jar包會被場景啓動器所替換首先會引入場景啓動器

      

   <!--全部的springboot應用都須要以該工程爲父工程包含了啓動springboot所需的所有jar包-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

從官網上拷貝下來的依賴須要什麼場景啓動器就引入什麼場景啓動器就行

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
       也能夠加入日誌文件
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
</dependencies> <properties> <java.version>1.8</java.version> </properties>

spring的幾個項目結構介紹

libraries 庫(maven自定下載的jar包)

compiler.xml 編譯器(主要用於maven初始化的編譯)

modules.xml(模塊的xml)

.mvn :主要用於版本切換   由於maven的版本和插件配合並非那麼完美,.mvn爲解決這個問題有一個第三方的插件wrapper可使用

 

 properties文件中記錄你要使用的maven版本當用戶執行mvn的clear命令時發現當前用戶使用的maven版本和用戶指望的版本不同那麼就下載指望的maven版本。

.gitignore 的做用 忽略不須要上傳的文件

demo.iml    idea工程的配置文件是當前project的一些配置信息

開啓第一個springboot項目

MVC 中  建立的第一個Controller類

 

註解

@RestController  /*ResponseBody+Controller  返回json類型的數據*/   http://www.javashuo.com/article/p-finclvbr-bh.html RESTFUL風格基礎概念
@RequestMapping("hello")   請求映射 能夠配置全局的也能夠配置局部的
@EnableAutoConfiguration /*啓用自動配置若是不聲明那麼他就認爲你不須要自動配置*/
實際上springboot的自動配置是根據你引入了什麼依賴,若是你引入了他就會給你自動配置這些須要的config 或則javabean 或者class

 

 後來我將springboot啓動類換到了另一個方法中

出現了一個異常   http://www.javashuo.com/article/p-fwzwursd-t.html 解決辦法

由於我換了類可是忘記了換類名因此才報錯

** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.

 這個是由於  ComponentScan註解的默認掃描範圍是啓動程序XxxApplication. java所在目錄及其下的全部子包。

 因此你不能夠直接放在java目錄下須要建一個父包 而後進行掃描,這時就能夠了

 對比之前的寫法

Properties properties = new Properties(); properties.load(JDBCUtil.class.getResourceAsStream("/jdbc.properties"));
底層使用流來進行讀取
  

springboot 如今的寫法

1.在resources下建立jdbc.properties
@Configuration  //聲明一個類是java配置類至關於一個xml配置文件
@PropertySource("classpath:jdbc.properties") //指定外部屬性文件 讀取咱們的資源文件
public class jdbcConfiguration {
//聲明jdbc的配置文件
//使用屬性注入的方式
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean //相似一個bean標籤將方法的返回值加入bean容器
public DataSource dateSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(this.driverClassName);
dataSource.setUrl(this.url);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password); 這裏用上this主要是爲了區分紅員變量和局部變量
return null;

}
}

 升級寫法

 

 

 設置set/get方法

 

 

 

 springboot   給咱們提供了四種注入方式 第一種是set/get方式也就是上面那種方式

第二種是經過 構造方法

 

 

 第三種:經過bean方法的形參也能夠自動注入

 

 第四種:是一種更加簡單的方法

@ConfigurationProperties(prefix = "jdbc") 不只能夠用在類上也能夠用在方法上。

 

 

 

 底層使用Datasource 的構造方法 get/set方法

 

 

 

 

 

 

 

4.yml文件中的值不能以*開頭,能夠用 "*" 加個引號開頭。

 

 

/*來標註主程序類,來講明這是一個spring boot應用
* */
@SpringBootApplication
public class SpringBoot01ConfigApplication {

    public static void main(String[] args) {
        /*springboot應用啓動起來*/
        SpringApplication.run(SpringBoot01ConfigApplication.class, args);
    }

 

package cn.edu.aynu.springboot01config;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    @RequestMapping("/some")
    public String doFirst(){
        return "Helloworld";
    }

}

將一下工程的監控器,監控工程的運行狀態

ActuatorSpring Boot提供的一個可插拔模塊,用於對工程進行監控。其經過不一樣的監控終端實現不一樣的監控功能。其功能與Dubbo的監控中心相似,不一樣的是,Dubbo的監控中心是須要專門部署的,而Spring BootActuator是存在於每個工程中的。官網https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#production-ready

導入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

 有一點要注意:Actuator 與 elasticsearch 是相互衝突的。若是導入了 Acturtor 就不要再使用 elasticserach 不然報錯

 

server:
  port: 8081
  tomcat:
    uri-encoding: UTF-8


management:
  server:
    port: 9999
    servlet:
      context-path: /xxx
  endpoints:
    web:
      base-path: /base
  endpoint:
    health:
      show-details: always
actuator配置
{
    "status": "DOWN",
    "details": {
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 15453913088,
                "free": 7720787968,
                "threshold": 10485760
            }
        },
        "redis": {
            "status": "DOWN",
            "details": {
                "error": "org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379"
            }
        }
    }
}
postman響應結果

 

management.server.port=9999
management.server.servlet.context-path=/xxx
management.endpoints.web.base-path=/actuator



#自定義info 信息
info.company.name=abc
info.auth.name=lisi
自定義info信息
{
    "company": {
        "name": "abc"
    },
    "auth": {
        "name": "lisi"
    }
}
響應結果

開放全部的監控終端

management.endpoints.web.exposure.include=*

排除某些不想開放的終端

management.endpoints.web.exposure.exclude=env,beans

經常使用的監控終端

 

 

在配置文件中取出屬性值

方法一:

使用主配置文件或者自定義的配置文件均可以
@RestController
@PropertySource(value = "classpath:student.properties",encoding = "utf-8")
/*@PropertySource(value = "application.properties")*/
public class controller {


   @Value("${student.id}")
   int id;

   @Value("${student.name}")
   String name;
   @Value("${student.age}")
   int age;

    @RequestMapping("/hello")
    public String handler(){

        return id+","+name+","+age;
    }
Controller   在controller 中的註解式 @PropertySource
student.id = 111111111
student.name = zhu
student.age = 12
student.properties

可是建議通常不要寫在主主配置文件中

 方法二

 將實體類聲明爲一個組件,並使用ConfigurationProperties註解將配置文件中的屬性賦值上去

package cn.edu.aynu.bean;

import com.sun.tracing.dtrace.ArgsAttributes;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "student")
public class Student {

    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @Override
    public String toString() {



        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Student
student:
  id: 12
  name: lisi
  age: 34
application.yml
package cn.edu.aynu.controller;

import cn.edu.aynu.bean.Student;
import cn.edu.aynu.service.ServiceHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.*;


@RestController
public class controller {

    @Autowired
    Student  student;
    @RequestMapping("/hello")
    public String handler(){

        System.out.println(student);
        return "/hello";
    }


}
Controller

controller 中須要注意一點,當咱們使用自動注入bean的時候,是能夠獲得值的,可是若是咱們在從新定義一個劇不能獲得值了,應爲那就至關因而重寫了這個方法。

須要注意一點,有時候咱們不只僅須要的屬性只是int 或者是String 咱們可能須要的是map 或者list

若是配置文件沒有了提示就導入這個jar包

<!‐‐導入配置文件處理器,配置文件進行綁定就會有提示‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>
processor

 

能夠將程序打包成jar包

  <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

怎麼打成jar包

能夠直接在命令行上進行啓動執行

 

 

執行成功 這個路徑是Controller裏面的requestMapping

探究原理

自動導入的jar包

父項目

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

因此又叫他Springboot的仲裁中心

 導入的依賴

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

主程序類

package cn.edu.aynu.springboot01config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/*來標註主程序類,來講明這是一個spring boot應用
* */
@SpringBootApplication
public class SpringBoot01ConfigApplication {

    public static void main(String[] args) {
        /*springboot應用啓動起來*/
        SpringApplication.run(SpringBoot01ConfigApplication.class, args);
    }
}

 

 

 

/*這個類的全部方法返回的數據寫給瀏覽器,若是是對象轉爲json格式*/
/*@ResponseBody
@Controller*/
@RestController  /*@RestController 直接表明了@RequestBody 和@Controller*/
public class MyController {

    @RequestMapping("/some")
    public String doFirst(){
        return "Helloworld";
    }

}

 

application.properties的配置文件

server.port=9090 # 服務端口號
server.tomcat.uri-encoding=UTF-8 #以Tomcat爲web容器時的字符編碼

spring.application.name=customer # 應用名稱,通常就是項目名稱,這個名稱在SpringCloud中比較關鍵
spring.profiles.active=dev #指定當前的活動配置文件,主要用於多環境多配置文件的應用中
spring.http.encoding.charset=UTF-8 #http請求的字符編碼
spring.http.multipart.max-file-size=10MB #設置文件上傳時單個文件的大小限制
spring.http.multipart.max-request-size=100MB #設置文件上傳時總文件大小限制

spring.thymeleaf.prefix=classpath:/templates/ #配置在使用Thymeleaf作頁面模板時的前綴,即頁面所在路徑
spring.thymeleaf.suffix=.html #設置在使用Thymeleaf作頁面模板時的後綴
spring.thymeleaf.cache=false #設置在使用Thymeleaf作頁面模板時是否啓用緩存

spring.mvc.static-path-pattern=/** #設置靜態資源的請求路徑
spring.resources.static-locations=classpath:/static/,classpath:/public/ #指定靜態資源的路徑

##如下是使用MySQL數據庫的配置
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect #指定數據庫方言
hibernate.show_sql=true #是否顯示sql語句
hibernate.hbm2dll.auto=update #設置使用Hibernate的自動建表方式
entitymanager.packagesToScan=com.zslin #設置自動掃描的包前綴

spring.datasource.url=jdbc:mysql://localhost:3306/customer?\
useUnicode=true&characterEncoding=utf-8&useSSL=true&autoReconnect=true #數據庫連接
spring.datasource.username=root #數據庫用戶名
spring.datasource.password=123 #數據庫用戶對應的密碼
spring.datasource.driver-class-name=com.mysql.jdbc.Driver #數據庫驅動名稱
application.properties

@ConfigurationProperties主要做用:就是綁定application.properties中的屬性

使用方法
@ConfigurationProperties(prefix = "spring.datasource")
application.properties 文件 spring.datasource.password
=root spring.datasource.username=root spring.datasource.url=jdbc:mysql:///jdbc spring.datasource.driver-class-name=com.alibaba.druid.proxy.DruidDriver

springboot的包掃描問題

根據英文的提示是在配置中找不到一個指定自動注入類型的bean,SpringBoot項目的Bean裝配默認規則是根據Application類所在的包位置從上往下掃描!Application類是指SpringBoot項目入口類。
這個類的位置很關鍵:若是mapper、service所在包不在其子包下,則不會被掃描。
即, 把Application類放到mapper、service所在包的上級,

兩種解決辦法: 
  1 .將接口與對應的實現類放在與application啓動類的同一個目錄或者他的子目錄下,這樣註解能夠被掃描到,這是最省事的辦法
  2 .在指定的application類上加上這麼一行註解,手動指定application類要掃描哪些包下的註解(圖3)

圖3

@ComponentScan(basePackages = "cn.edu.aynu.*")

 

 

server:
   port: 8087

 xml

<server>
  port:8087
</server>

 <!--導入配置文件處理器,配置文件進行綁定就會有提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

作一個小練習

定義兩個類  在yaml文件中給屬性賦值

people:
   lastName: zs
   age: 12
   boss: ls
   birth: 2017/12/14
   maps: {k1: v1,k2: v2}
   lists:
      - lisi
      - zhou
   dog:
      name: 小狗
      age: 23
    

如今如何將兩個屬性與java bean類進行綁定

/*將配置文件中的每個值映射到這個組件中
* @ConfigurationProperties 告訴springboot這個類中的屬性和配置文件的屬性進行綁定
* 加上前綴是由於配置文件中能夠寫入不少的屬性值要找到相對應的那一個。進行一一映射
* 只有這個組件是容器中的組件才能使用容器中提供的功能,因此要將這個類聲明爲組件
* */
@Component
@ConfigurationProperties(prefix = "people")
public class People {
    private String lastName;
    private Integer age;
    private Boolean boss;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
public class Dog {
    private String name;
    private Integer age;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBoot01ConfigApplicationTests {
    @Autowired
   People people;
    @Test
    public void contextLoads() {
     System.out.println(people);

    }

執行成功

 在properties配置文件中進行配置

people.last-name=zs
people.age=23
people.birth=2013/12/12
people.boss=false
people.maps.k1=v1
people.maps.k2=v2
people.lists=a,b,c
people.dog.name=li
people.dog.age=34

若是在peoperties文件中產生了亂碼就在idea中改變一下,file-setting-輸入file Enconding 調一下

 

@Component
//@ConfigurationProperties(prefix = "people")
public class People {
    /*在spring中進行給變量賦值
    * <bean>
    *     <property name="" values="字面量/#{}從EL表達式中獲取/${}從配置文件,環境變量中獲取"></property>
    * </bean>那麼註解也支持這幾種方式
    * 採用註解的方式
    */
    @Value("${people.last-name}")
    private String lastName;
    @Value("#{11*2}")
    private Integer age;
    private Boolean boss;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

@ConfigurationProperties(prefix = "people")表明從全局配置文件中獲取值,本身也能夠定義配置文件
@PropertySource(value = {"classpath:people.properties"})
@Component
@ConfigurationProperties(prefix = "people")
public class People {
    /*在spring中進行給變量賦值
    * <bean>
    *     <property name="" values="字面量/#{}從EL表達式中獲取/${}從配置文件,環境變量中獲取"></property>
    * </bean>那麼註解也支持這幾種方式
    * 採用註解的方式
    */
    @Value("${people.last-name}")
    private String lastName;
    @Value("#{11*2}")
    private Integer age;
    private Boolean boss;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

 

 

這裏面須要補充一點,也是須要注意的地方

 @PropertySources 和 ConfigurationProprtties 這兩個註解式相輔相成的

若是隻是加上 @COnfigurationSources這個註解那麼,與bean綁定的屬性值默認是從主配置文件中加載,

可是若是加上 PropertySources這個註解,則能夠從本身自定義的 XXX.properties 中加載。

 

@PropertySource(value = {"classpath:person.properties"})  //加載指定的配置文件;

@ImportResource  //導入Spring的配置文件,讓配置文件裏面的內容生效;Spring Boot裏面沒有Spring的配置文件,咱們本身編寫的配置文件,也不能自動識別;想讓Spring的配置文件生效,加載進來;@ImportResource標註在一個配置類上

用法:

@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>
beans.xml

 

@Bean

SpringBoot推薦給容器中添加組件的方式;推薦使用全註解的方式一、配置類@Configuration------>Spring配置文件二、使用@Bean給容器中添加

舉個例子

* 在配置文件中用<bean><bean/>標籤添加組件
*
*/
@Configuration
public class MyAppConfig {
//將方法的返回值添加到容器中;容器中這個組件默認的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("配置類@Bean給容器中添加組件了...");
return new HelloService();
}
}

 

@ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定;prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能;@ConfigurationProperties(prefix = "person")默認從全局配置文件中獲取值;

 

<?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="hello" class="cn.edu.aynu.springboot01config.helloService"></bean>
</beans>
 @Test
    public void testService(){
        boolean helloService = ioc.containsBean("hello");
        System.out.println(helloService);
    }

 

@ImportResource(locations = {"classpath:beans.xml"})
@SpringBootApplication
public class SpringBoot01ConfigApplication {

    public static void main(String[] args) {
        /*springboot應用啓動起來*/
        SpringApplication.run(SpringBoot01ConfigApplication.class, args);
    }
}

/*@Configuration 指明當前類就是一個配置類,用來代替以前的spring配置文件
* 在標籤中使用<bean></bean>添加組件
*
* */

@Configuration
public class RegisterConfig {
    /*將方法的返回值添加到容器中;容器中這個組件默認的id就是方法名*/
    @Bean
    public helloService helloService02(){
        return new helloService();
    }
}
View Code
package cn.edu.aynu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: review-project
 * Created by lenovo on 2019/4/26 16:33
 */
@Configuration  //告訴springboot 這是一個配置類
public class MyConfig {
    @Bean  //將方法的返回值添加到容器中,容器中這個組件默認的id就是方法名
    public HelloService configApp(){
        System.out.println("@bean給容器中添加了組件,根據方法名這到這個類");
        return  new HelloService();
    }

}
自定義配置類
2019-04-26 16:38:36.327  INFO 11556 --- [           main] cn.edu.aynu.ReviewApplication            : Starting ReviewApplication on LAPTOP-4U4DHM78 with PID 11556 (E:\sturts2\review-project\target\classes started by lenovo in E:\sturts2\review-project)
2019-04-26 16:38:36.336  INFO 11556 --- [           main] cn.edu.aynu.ReviewApplication            : No active profile set, falling back to default profiles: default
2019-04-26 16:38:38.298  INFO 11556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2019-04-26 16:38:38.302  INFO 11556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-04-26 16:38:38.414  INFO 11556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 88ms. Found 0 repository interfaces.
2019-04-26 16:38:39.418  INFO 11556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2019-04-26 16:38:39.449  INFO 11556 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-04-26 16:38:39.449  INFO 11556 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-26 16:38:39.653  INFO 11556 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-04-26 16:38:39.653  INFO 11556 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3207 ms
@bean給容器中添加了組件,根據方法名這到這個類
控制檯打印的內容

經過這個控制檯打印的信息能夠看出  Root WebApplicationContext: initialization completed in 3207 ms

當WebApplicationContext 初始化完成後,就打印了自定義信息

看一下控制檯的輸出就能夠知道程序執行的前後順序,挑幾個我認識的

1.先檢查一個有沒有多環境選擇的profile
No active profile set, falling back to default profiles: default
2.是對 Spring Data repository 的掃描
Finished Spring Data repository scanning in 88ms. Found 0 repository interfaces.

 Tomcat initialized with port(s): 8081 (http)
 Starting service [Tomcat]
 Starting Servlet engine: [Apache Tomcat/9.0.17]
 Initializing Spring embedded WebApplicationContext
 Root WebApplicationContext: initialization completed in 3207 ms

.................

在配置文件中的代碼,通常都是按照配置文件的前後循序執行。

解釋一下spring Data (https://www.cnblogs.com/airycode/p/6535323.html能夠參考這個博主)

Repository 接口是 Spring Data 的一個核心接口,它不提供任何方法,開發者須要在本身定義的接口中聲明須要的方法  public interface Repository<T, ID extends Serializable> { } 

Spring Data可讓咱們只定義接口,只要遵循 Spring Data的規範,就無需寫實現類。
與繼承 Repository 等價的一種方式,就是在持久層接口上使用 @RepositoryDefinition 註解,併爲其指定 domainClass 和 idClass 屬性。以下兩種方式是徹底等價的

Repository 的子接口

基礎的 Repository 提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能。它們的繼承關係以下:
1.Repository: 僅僅是一個標識,代表任何繼承它的均爲倉庫接口類

2.CrudRepository: 繼承 Repository,實現了一組 CRUD 相關的方法

3.PagingAndSortingRepository: 繼承 CrudRepository,實現了一組分頁排序相關的方法

4.JpaRepository: 繼承 PagingAndSortingRepository,實現一組 JPA 規範相關的方法

5.自定義的 XxxxRepository 須要繼承 JpaRepository,這樣的 XxxxRepository 接口就具有了通用的數據訪問控制層的能力。

6.JpaSpecificationExecutor: 不屬於Repository體系,實現一組 JPA Criteria 查詢相關的方法

https://www.cnblogs.com/airycode/p/6535323.html
springData

 

---表明一個文檔

 配置文件的加載順序:

springboot啓動會掃描如下位置的application.properties或者application.yml做爲springboot的默認配置文件

-file:./config

-file:./

-classpath:/config/

-classpath:/

優先級從高到低,高優先級的配置會覆蓋低優先級的配置。

最重要的是,springboot會從這四個位置所有加載配置文件,想成互補配置  

咱們還能夠經過改變

spring.config.location 來改變默認配置文件的位置,可是這個方式有一個前提就是須要在項目打包好之後,啓動項目的時候指定配置文件的新位置,

全部的配置文件都會造成互補配置

java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties

剛纔講的都是內部文件的加載順序,如今講一下外部文件的加載順序

1.命令行參數,全部你命令均可以在命令行中進行指定

java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc

特色:能夠同時加載多個配置項,可是多個配置項之間須要使用空格隔開

2由jar包外向jar包內進行尋找

優先加載帶profile的

    jar包外部的application-{profile}.properties或application.yml(帶spring.profile)配置文件
    jar包內部的application-{profile}.properties或application.yml(帶spring.profile)配置文件

再來加載不帶profile的

   jar包外部的application.properties或application.yml(不帶spring.profile)配置文件
   jar包內部的application.properties或application.yml(不帶spring.profile)配置文件

配置文件上進行指定

  @Configuration註解類上的@PropertySource

  經過SpringApplication.setDefaultProperties指定的默認屬性

 8.自動配置原理

springboot啓動的時候加載了主啓動類開啓了自動配置功能

@EnableAutoConfiguration的做用是:

@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 {
@EnableAutoConfiguration  裏面封裝了
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {

 利用EnableAutoConfigurationImportSelector,先判斷是屬於什麼註解,而後再進行下一步操做

類的全名就做爲組件的id.

List configurations = getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置,也就是將候選的組件組件獲取內容保存起來。

接着,有一個類SpringFactoriesLoader.loadFactoryNames()

掃描全部jar包類路徑下 META‐INF/spring.factories把掃描到的這些文件的內容包裝成properties對象從properties中獲取到EnableAutoConfiguration.class類(類名)對應的值,而後把他們添加在容器中

將 類路徑下 META-INF/spring.factories 裏面配置的全部EnableAutoConfiguration的值加入到了容器中;

這時,自定義配置纔算真正的加載到容器中

一但這個配置類生效;這個配置類就會給容器中添加各類組件;這些組件的屬性是從對應的properties類中獲取
的,這些類裏面的每個屬性又是和配置文件綁定的;

全部在配置文件中能配置的屬性都是在xxxxProperties類中封裝者‘;配置文件能配置什麼就能夠參照某個功
能對應的這個屬性類精髓:

1)、SpringBoot啓動會加載大量的自動配置類

2)、咱們看咱們須要的功能有沒有SpringBoot默認寫好的自動配置類;
3)、咱們再來看這個自動配置類中到底配置了哪些組件;(只要咱們要用的組件有,咱們就不須要再來配置了)
4)、給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。咱們就能夠在配置文件中指定這
些屬性的值;

xxxxAutoConfigurartion:自動配置類;
給容器中添加組件

xxxxProperties:封裝配置文件中相關屬性

細節

一、@Conditional派生註解(Spring註解版原生的@Conditional做用)
做用:必須是@Conditional指定的條件成立,纔給容器中添加組件,配置配裏面的全部內容才生效;

 自動配置類在必定條件下才能生效  咱們怎麼知道哪些配置類生效

咱們能夠經過啓用 debug=true屬性;來讓控制檯打印自動配置報告,這樣咱們就能夠很方便的知道哪些自動配置
類生效;

 
0.日誌門面: SLF4J;
日誌實現:Logback;
SpringBoot:底層是Spring框架,Spring框架默認是用JCL;
SpringBoot選用 SLF4j和logbac

     SpringBoot底層也是使用slf4j+logback的方式進行日誌記錄
     SpringBoot也把其餘的日誌都替換成了slf4j;
     中間替換包

 
     

     SpringBoot能自動適配全部的日誌,並且底層使用slf4j+logback的方式記錄日誌,引入其餘框架的時候,只須要
     把這個框架依賴的日誌框架排除掉。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring‐core</artifactId>
    <exclusions>
       <exclusion>
          <groupId>commons‐logging</groupId>
          <artifactId>commons‐logging</artifactId>
       </exclusion>
   </exclusions>
</dependency

 

 



1.springboot 如何切換日誌框架,其實很簡單,將原先有的框架的依賴刪去,導入新的依賴便可
不過你必定很好奇。怎麼知道本身是什麼依賴吧,這個不難,兩種方法
(1),就是查看你的pom的父項目文件的版本仲裁中心,查看。
(2)在你的idea 項目中能夠查看你的依賴樹。
日誌級別
trace<debug<info<warn<err


2
、指定配置 給類路徑下放上每一個日誌框架本身的配置文件便可;SpringBoot就不使用他默認配置的了 logback.xml:直接就被日誌框架識別了; logback-spring.xml:日誌框架就不直接加載日誌的配置項,由SpringBoot解析日誌配置,可使用SpringBoot的高級Profile功能 <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> 若是使用logback.xml做爲日誌配置文件,還要使用profile功能,會有如下錯誤 no applicable action for [springProfile

日誌文件產生的位置

1.在當前磁盤的根路徑下建立spring文件夾和裏面的log文件夾;使用 spring.log 做爲默認文件

 

logging:
 path: /spring/log

2.在控制檯輸出的日誌的格式

logging:
  path: /spring/log
  pattern:
    console: %d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n

3.指定文件中日誌輸出的格式

 

logging:
  path: /spring/log
  pattern:
    console: %d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n
    file: %d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n

下面進行web開發

咱們必定要養成一個好習慣就是,遇到底層代碼

咱們要知道底層配置中,以springboot爲例:

1.springbooot幫咱們配置了什麼

2.能不能修改,能修改哪些配置

3.能不能擴展

xxxxAutoConfiguration:幫咱們給容器中自動配置。
xxxxProperties:配置類來封裝配置文件的內。

Springboot 對靜態資源的映射規則

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };

這就是爲何可以自動識別static,public,redources 文件夾了,在這裏都已經定義了。

這個類就厲害了,幾乎包含了咱們入門水平對配置類怎麼來的的所須要的全部方法了。

WebMvcAuotConfiguration:

@Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
                return;
            }
            if (!registry.hasMappingForPattern("/webjars/**")) {
                ResourceHandlerRegistration registration = registry
                        .addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/");
                configureResourceCaching(registration);
                customizeResourceHandlerRegistration(registration);
            }
String staticPathPattern
= this.webFluxProperties.getStaticPathPattern();
靜態資源映射文件夾 執行了上面的addResourceHandler()方法。
if (!registry.hasMappingForPattern(staticPathPattern)) { ResourceHandlerRegistration registration = registry .addResourceHandler(staticPathPattern).addResourceLocations( this.resourceProperties.getStaticLocations()); configureResourceCaching(registration); customizeResourceHandlerRegistration(registration); } } private void configureResourceCaching(ResourceHandlerRegistration registration) { Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); ResourceProperties.Cache.Cachecontrol cacheControl = this.resourceProperties .getCache().getCachecontrol(); if (cachePeriod != null && cacheControl.getMaxAge() == null) { cacheControl.setMaxAge(cachePeriod); } registration.setCacheControl(cacheControl.toHttpCacheControl()); } @Override public void configureViewResolvers(ViewResolverRegistry registry) { this.viewResolvers.orderedStream().forEach(registry::viewResolver); } @Override public void addFormatters(FormatterRegistry registry) { for (Converter<?, ?> converter : getBeansOfType(Converter.class)) { registry.addConverter(converter); } for (GenericConverter converter : getBeansOfType(GenericConverter.class)) { registry.addConverter(converter); } for (Formatter<?> formatter : getBeansOfType(Formatter.class)) { registry.addFormatter(formatter); } } private <T> Collection<T> getBeansOfType(Class<T> type) { return this.beanFactory.getBeansOfType(type).values(); } private void customizeResourceHandlerRegistration( ResourceHandlerRegistration registration) { if (this.resourceHandlerRegistrationCustomizer != null) { this.resourceHandlerRegistrationCustomizer.customize(registration); } }

下面這個是對歡迎頁面的 底層註解

final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {

    private static final Log logger = LogFactory.getLog(WelcomePageHandlerMapping.class);

    private static final List<MediaType> MEDIA_TYPES_ALL = Collections
            .singletonList(MediaType.ALL);

    WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
            ApplicationContext applicationContext, Optional<Resource> welcomePage,
            String staticPathPattern) {
        if (welcomePage.isPresent() && "/**".equals(staticPathPattern)) {
            logger.info("Adding welcome page: " + welcomePage.get());
            setRootViewName("forward:index.html");
        }
        else if (welcomeTemplateExists(templateAvailabilityProviders,
                applicationContext)) {
            logger.info("Adding welcome page template: index");
            setRootViewName("index");
        }
    }

    private boolean welcomeTemplateExists(
            TemplateAvailabilityProviders templateAvailabilityProviders,
            ApplicationContext applicationContext) {
        return templateAvailabilityProviders.getProvider("index",
                applicationContext) != null;
    }

    private void setRootViewName(String viewName) {
        ParameterizableViewController controller = new ParameterizableViewController();
        controller.setViewName(viewName);
        setRootHandler(controller);
        setOrder(2);
    }

    @Override
    public Object getHandlerInternal(HttpServletRequest request) throws Exception {
        for (MediaType mediaType : getAcceptedMediaTypes(request)) {
            if (mediaType.includes(MediaType.TEXT_HTML)) {
                return super.getHandlerInternal(request);
            }
        }
        return null;
    }

    private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) {
        String acceptHeader = request.getHeader(HttpHeaders.ACCEPT);
        if (StringUtils.hasText(acceptHeader)) {
            return MediaType.parseMediaTypes(acceptHeader);
        }
        return MEDIA_TYPES_ALL;
    }

下面這個就是咱們須要的圖標了

    public static class FaviconConfiguration implements ResourceLoaderAware {

            private final ResourceProperties resourceProperties;

            private ResourceLoader resourceLoader;

            public FaviconConfiguration(ResourceProperties resourceProperties) {
                this.resourceProperties = resourceProperties;
            }

            @Override
            public void setResourceLoader(ResourceLoader resourceLoader) {
                this.resourceLoader = resourceLoader;
            }

            @Bean
            public SimpleUrlHandlerMapping faviconHandlerMapping() {
                SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
                mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
                mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
                        faviconRequestHandler()));
                return mapping;
            }

總結:1)、全部 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找資源;

webjars:以jar包的方式引入靜態資源;

 

<!‐‐引入jquery‐webjar‐‐>在訪問的時候只須要寫webjars下面資源的名稱便可
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>

(2)"/**" 訪問當前項目的任何資源,都去(靜態資源的文件夾)找映射

 

"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":當前項目的根路徑

3)、歡迎頁; 靜態資源文件夾下的全部index.html頁面;被"/**"映射;

 

4)、全部的 **/favicon.ico 都是在靜態資源文件下找;

 模板引擎

 

SpringBoot推薦的Thymeleaf;
語法更簡單,功能更強大;

 先看一下,Thyemleaf的底層配置文件

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

    public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html";

能夠看到,它的底層其實已經配置好了,初始就是在classpath下,以.html結尾,因此他是不能解析jsp等文件的。

若是咱們要使用Thyemleaf 就要使用它的名稱空間

<html lang="en" xmlns:th="http://www.thymeleaf.org">

Thyemleaf經常使用的四個標誌就是

*{}

#{...}:獲取國際化內容

${} 

@{...}:定義URL;

:*{...}:選擇表達式:和${}在功能上是同樣

 ~{...}:片斷引用表達式

下面就來真正的表現吧。

 

 

springmvc的自動配置

 講一下簡單的吧,

擴展springmvc

編寫一個配置類(@Configuration),是WebMvcConfigurerAdapter類型;不能標註@EnableWebMvc;

 既保留了全部的自動配置,也能用咱們擴展的配置;

 這裏咱們想要重寫 webMvcApplication中的方法有下面幾種方式

1.繼承WebMvcConfigurationSupport

public class MyConfig extends WebMvcConfigurationSupport {
 @Bean  //將方法的返回值添加到容器中,容器中這個組件默認的id就是方法名
    public HelloService configApp(){
        System.out.println("@bean給容器中添加了組件,根據方法名這到這個類");
        return  new HelloService();
    }


   @Override protected void addViewControllers(ViewControllerRegistry registry) { super.addViewControllers(registry); registry.addViewController("/zhulina").setViewName("index.html"); } }

2.implements WebMvcConfigure

 

public class MyConfig implements WebMvcConfigurer {
 @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/zhulina").setViewName("index.html");
    }
}

那麼這倆個類是什麼關係呢

WebMvcConfigurationSupport與WebMvcConfigurerAdapter、接口WebMvcConfigurer處於同一個目錄下,而且擁有更多的方法與屬性(WebMvcConfigurer中有的方法,此類中全都存在)

 

WebMvcConfigurationSupport應該是新版本中對WebMvcConfigurerAdapter的替換和擴展,若是新版本中應該是推薦使用WebMvcConfigurationSupport類

 

原理:
1)、WebMvcAutoConfiguration是SpringMVC的自動配置類
2)、在作其餘自動配置時會導入;@Import(EnableWebMvcConfiguration.class)

@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); // }
} } }

容器中全部的WebMvcConfigurer都會一塊兒起做用;
咱們的配置類也會被調用;
效果:SpringMVC的自動配置和咱們的擴展配置都會起做用

 

分析源碼能夠看出

 EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration 
 DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport

若是說,有一天你以爲本身水平特別高,或者想嘗試一下本身配置全部的springmvc的底層代碼

可使用註解@EnableWebMvc  在你的自動配置類中聲明

//使用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"); } }

原理:爲何配置了@EnableWebMvc就失效了呢

 查看@EnableWebMvc的註解就會發現

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc {
}

點開查看就知道

 

 */
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();


    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }

再查看EnableWebMvcConfig

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//這個註解就是檢查bean是否是存在,只有當容器中沒有這個組件的時候這個自動配置類纔會生效
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
        TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

而@EnableWebMvc將WebMvcConfigurationSupport組件導入進來;這個時候容器中存在了組件那麼,自動配置類就不會再起做用了。

導入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;因此,不少功能都要本身寫了。

下面一個問題如何修改springboot的默認配置

SpringBoot在自動配置不少組件的時候,先看容器中有沒有用戶本身配置的(@Bean、@Component)如
果有就用用戶配置的,若是沒有,才自動配置;若是有些組件能夠有多個(ViewResolver)將用戶配置的和本身默
認的組合起來;

 在SpringBoot中會有很是多的xxxConfigurer幫助咱們進行擴展配置

 在SpringBoot中會有不少的xxxCustomizer幫助咱們進行定製配置

 國際化

 

 

首先創建一個它就知道了

SpringBoot自動配置好了管理國際化資源文件的組件;

 根據瀏覽器語言設置切換國際化

原理:

國際化(Local)區域信息對象  LocalResolver  獲取區域信息對象

@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;
}
源碼
@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進行國
源碼

 

進行了一個小例子

第一次遇到的問題是:我使用模板引擎可是html頁面中的css js都不能訪問,因而我花了很長時間將網上的解決方法都試了一下,可是很惋惜所有沒有成功

真是替本身感受到悲哀,浪費了那麼長的時間,無奈之下,我就有新建了一個工程將頁面copy進去這時就所有能正常執行。

我緊接着就遇到了第二個問題,多是因爲第一個問題太過於燒腦,我第二個工程就忘記了配置文件中加入

# 國際化配置文件(包名.基礎名)
spring.messages.basename=i18N.login

fuck ,真是氣死我了又浪費了很長時間。

而後就能夠正常訪問了。

 並且更搞笑的是,當我將服務器切換成8081端口就產生亂碼,樣式也所有亂了,使用默認端口8080 就能夠。

我又遇到了問題三

package cn.edu.aynu.springboot.zhaoyujing.Component;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/*解決區域信息*/
public class MyLocalResolver implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if (!StringUtils.isEmpty(l)){
            String[] s = l.split("_");
            locale = new Locale(s[0], s[1]);

        }

        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}
自定義的MyLocalResolver
package cn.edu.aynu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/*@EnableWebMvc*/
@Configuration  //告訴springboot 這是一個配置類
public class MyConfig extends WebMvcConfigurationSupport {


/*
    @Bean  //將方法的返回值添加到容器中,容器中這個組件默認的id就是方法名
    public HelloService configApp(){
        System.out.println("@bean給容器中添加了組件,根據方法名這到這個類");
        return  new HelloService();
    }*/

    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);
        registry.addViewController("/zhulina").setViewName("index.html");
        registry.addViewController("/").setViewName("index.html");
    }

   /* @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        *//*引入靜態資源css js無效時加上*//*
        registry.addResourceHandler("/static").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX+"/static/**");

    }*/
   @Bean
   public MyLocalResolverre myLocalResolver(){
       System.out.println("執行了");
       return new MyLocalResolverre();
   }

}
MyMvcConfig

可是它竟然不執行,重寫的resolveLocal 這個方法

開始寫攔截器

 國際化都不執行了,那麼我這個攔截器確定也不執行了。

待續...............................

直接下一步了

 

引入片斷的時候

spring.mvc.date-format=yyyy-MM-dd

 有時候咱們的修改頁面和添加頁面是相同的,這個時候咱們就能夠將他倆合二爲一

<body>
        <!--引入抽取的topbar-->
        <!--模板名:會使用thymeleaf的先後綴配置規則進行解析-->
        <div th:replace="commons/bar::topbar"></div>

        <div class="container-fluid">
            <div class="row">
                <!--引入側邊欄-->
                <div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>

                <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
                    <!--須要區分是員工修改仍是添加;-->
                    <form th:action="@{/emp}" method="post">
                        <!--發送put請求修改員工數據-->
                        <!--
                        1、SpringMVC中配置HiddenHttpMethodFilter;(SpringBoot自動配置好的)
                        2、頁面建立一個post表單
                        3、建立一個input項,name="_method";值就是咱們指定的請求方式
                        -->
                        <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>
                </main>
            </div>
        </div>

若是是修改,那麼從後臺取出的確定是當前修改的信息而後保存在一個變量中,若是是添加那麼就即將這個變量職位空,而後在前臺頁面中進行判斷

變量是否爲空,爲空就是添加,不然就是修改。

 工刪除

                         <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>
                                        <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>

springboot默認的錯誤處理機制

瀏覽器返回一個默認錯誤處理的頁面

若是咱們想本身修改錯誤頁面就須要參考

ErrorMvcAutoConfiguration;錯誤處理的自動配置;

 

 咱們自定義的錯誤類是如何進行工做的

首先咱們能夠找到這個方法

BasicErrorController
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

//產生html類型的數據;瀏覽器發送的請求來到這個方法處理
    @RequestMapping(produces = "text/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) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity<Map<String, Object>>(body, status); } }

 ErrorPageCustomizer

 

@Value("${error.path:/error}")
private String path = "/error"; 系統出現錯誤之後來到error請求進行處理;(web.xml註冊的錯誤頁面規則


private
static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered { private final ServerProperties properties; protected ErrorPageCustomizer(ServerProperties properties) { this.properties = properties; } @Override public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { ErrorPage errorPage = new ErrorPage(this.properties.getServletPrefix() + this.properties.getError().getPath()); errorPageRegistry.addErrorPages(errorPage); }

DefaultErrorViewResolver

 

@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) {
       String errorViewName = "error/" + viewName; //默認SpringBoot能夠去找到一個頁面? error/404

TemplateAvailabilityProvider provider
= this.templateAvailabilityProviders //模板引擎能夠解析這個頁面地址就用模板引擎解析 .getProvider(errorViewName, this.applicationContext); if (provider != null) { return new ModelAndView(errorViewName, model); //模板引擎可用的狀況下返回到errorViewName指定的視圖 } return resolveResource(errorViewName, model); //模板引擎不可用,就在靜態資源文件夾下找errorViewName對應的頁面 error/404.html } private ModelAndView resolveResource(String viewName, Map<String, Object> model) { for (String location : this.resourceProperties.getStaticLocations()) { try { Resource resource = this.applicationContext.getResource(location); resource = resource.createRelative(viewName + ".html"); if (resource.exists()) { return new ModelAndView(new HtmlResourceView(resource), model); } } catch (Exception ex) { } } return null; }

步驟:
一但系統出現4xx或者5xx之類的錯誤;ErrorPageCustomizer就會生效(定製錯誤的響應規則);就會來到/error
請求;就會被BasicErrorController處理;

 響應頁面;去哪一個頁面是由DefaultErrorViewResolver解析獲得的;

 如何定製錯誤頁面

 

  1)有模板引擎的狀況下;error/狀態碼; 【將錯誤頁面命名爲 錯誤狀態碼.html 放在模板引擎文件夾裏面的error文件夾下】,發生此狀態碼的錯誤就會來到 對應的頁面;

      咱們可使用4xx和5xx做爲錯誤頁面的文件名來匹配這種類型的全部錯誤,精確優先(優先尋找精確的狀態碼.html);

    頁面能獲取的信息;
    timestamp:時間戳
    status:狀態碼
   error:錯誤提示
   exception:異常對象
   message:異常消息
  errors:JSR303數據校驗的錯誤都在這裏
  2)、沒有模板引擎(模板引擎找不到這個錯誤頁面),靜態資源文件夾下找;
  3)、以上都沒有錯誤頁面,就是默認來到SpringBoot默認的錯誤提示頁面;

 

 自定義異常處理返回json數據

 

當出現錯誤之後,會來到/Error請求  會被BasicErrorController 這個類進行處理後 響應頁面去哪一個頁面是由DefaultErrorViewResolver解析獲得的

將響應的值保存起來而後能夠經過調用getErrorAttributes獲得的

getErrorAttributes 這個方法是 AbstractErrorController(ErrorController) 這個類規定的方法

public class BasicErrorController extends AbstractErrorController 
public abstract class AbstractErrorController implements ErrorController 

 

 

因此,若是想要自定義錯誤就能夠這樣作

1.寫一個ErrorController的實現類【或者是編寫AbstractErrorController的子類】,放在容器中;

 

2.頁面上能用的數據,或者是json返回能用的數據都是經過errorAttributes.getErrorAttributes獲得;
容器中DefaultErrorAttributes.getErrorAttributes()默認進行數據處理的

配置嵌入式Servlet容器

 

package com.atguigu.springboot.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

    //處理get請求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Hello MyServlet");
    }
}
new MyServlet

 

 

package com.atguigu.springboot.filter;

import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("MyFilter process...");
        chain.doFilter(request,response);

    }

    @Override
    public void destroy() {

    }
}
MuFilter

 

 

 

new  MyListener

 

綜合

package com.atguigu.springboot.config;

import com.atguigu.springboot.filter.MyFilter;
import com.atguigu.springboot.listener.MyListener;
import com.atguigu.springboot.servlet.MyServlet;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

@Configuration
public class MyServerConfig {

    //註冊三大組件
    @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
        registrationBean.setLoadOnStartup(1);
        return registrationBean;
    }

    @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;
    }


    //配置嵌入式的Servlet容器
    @Bean
    public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
        return new EmbeddedServletContainerCustomizer() {

            //定製嵌入式的Servlet容器相關的規則
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                container.setPort(8083);
            }
        };
    }

}

 

 原理:

 

SpringBoot幫咱們自動SpringMVC的時候,自動的註冊SpringMVC的前端控制器;DIspatcherServlet;
DispatcherServletAutoConfiguration中:

spring也支持配置其餘Servlet容器

默認支持  默認使用(Tomcat)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId> 引入web模塊默認就是使用嵌入式的Tomcat做爲Servlet容器; </dependency>

jetty(Jetty 是一個開源的servlet容器,它爲基於Java的web容器,例如JSP和servlet提供運行環境。Jetty是使用Java語言編寫的,

它的API以一組JAR包的形式發佈。開發人員能夠將Jetty容器實例化成一個對象,能夠迅速爲一些獨立運行(stand-alone)的Java應用提供網絡和web鏈接。)

(1)Jetty更輕量級。這是相對Tomcat而言的

(2)Jetty更靈活,體如今其可插拔性和可擴展性,更易於開發者對Jetty自己進行二次開發,定製一個適合自身需求的Web Server。

然而,當支持大規模企業級應用時,Jetty也許便須要擴展,在這場景下Tomcat即是更優的。
總結:Jetty更知足公有云的分佈式環境的需求,而Tomcat更符合企業級環境。
<!‐‐ 引入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>

Undertow

  • Undertow 是紅帽公司開發的一款基於 NIO 的高性能 Web 嵌入式服務器
  • 輕量級:它是一個 Web 服務器,但不像傳統的 Web 服務器有容器概念,它由兩個核心 Jar 包組成,加載一個 Web 應用能夠小於 10MB 內存
  •          Servlet3.1 支持:它提供了對 Servlet3.1 的支持
    • WebSocket 支持:對 Web Socket 徹底支持,用以知足 Web 應用巨大數量的客戶端
    • 嵌套性:它不須要容器,只需經過 API 便可快速搭建 Web 服務器
    • 默認狀況下 Spring Cloud 使用 Tomcat 做爲內嵌 Servlet 容器,可啓動一個 Tomcat 的 Spring Boot 程序與一個 Undertow 的 Spring Boot 程序,經過 VisualVM 工具進行比較,可看到 Undertow 性能優於 Tomcat
<!‐‐ 引入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‐undertow</artifactId>
     <groupId>org.springframework.boot</groupId>
</dependency>

 嵌入式Servlet容器自動配置原理

EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自動配置

 

 

 

 

 嵌入式Servlet 容器啓動原理

1.springboot根據依賴導入的狀況給容器中添加相應的EmbeddedServletContainerFactory
也便是 TomcatEmbeddedServletContineryFactory.


2.容器中某個組件要建立對象就會驚動後置處理器
EmbeddedServletContainerCustomizerBeanPostProcessor;
只要是嵌入式的Servlet容器工廠後置處理器就工做
3.後置處理器從容器中獲取全部的EmbeddedServletContainerCustomizer 調用定製器的定製方法
嵌入式Servlet容器啓動原理

   首先獲取嵌入式的Servlet容器工廠

 springboot啓動後運行 run方法,調用 refreshContext(context) 方法 springboot 刷新IOC容器 [ 建立Ioc容器對象,並初始化容器,建立容器中的每個組件];若是是web應用建立

AnnotationConfigEmbeddedWebApplicationContext  .  若是不是web應用建立 AnnoctionConfigApplicationContext .

 refreshContext(context)  這個方法的做用就是刷新Ioc剛纔建立好的IOC容器

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.
 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(); } } }

 onRefresh(); web的ioc容器重寫了onRefresh方法

 web   ioc 容器會建立嵌入式的Servlet容器;createEmbeddedServletContainer();

 而後經過下面的方法獲取嵌入式的容器工廠

 EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

 

從ioc容器中獲取EmbeddedServletContainerFactory 組件;TomcatEmbeddedServletContainerFactory建立
對象,後置處理器一看是這個對象,就獲取全部的定製器來先定製Servlet容器的相關配置;

 使用容器工廠獲取嵌入式的Servlet容器

this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());
嵌入式的Servlet容器建立對象並啓動Servlet容器

 先啓動嵌入式的Servlet容器,再將ioc容器中剩下沒有建立出的對象獲取出來

IOC容器啓動建立嵌入式的Servlet容器

 使用外置的Servlet容器

 嵌入式的Servlet容器打包成可執行的jar包  優勢:簡單,便捷  

缺點:默認不支持jsp     優化定製比較複雜 (使用定製器ServerProperties)

 自定義EmbeddedServletContionerCustomizer,  本身編寫嵌入式Servlet容器的建立工廠

EmbeddedServletContioneryFactory

 

外置的Servlet容器:外面安裝Tomcat--應用war包的方式打包

步驟:

 1.必須建立好一個war項目(利用idea建立好目錄結構
2)將嵌入式的Tomcat指定爲Provider

 

 

對於scope=compile的狀況(默認scope),也就是說這個項目在編譯,測試,運行階段都須要這個artifact對應的jar包在classpath中。而對於scope=provided的狀況,

則能夠認爲這個provided是目標容器已經provide這個artifact。

 這麼說可能不是很好理解:換個簡單的,就是你在把這個項目打成war包時,scope=provided的jar包,不會出如今WEB-INFO/lib目錄下,而scope=compile的jar包,會放到WEB-INFO/lib目錄

 這樣能夠避免像servlet-api.jar這樣的jar包衝突,可是若是遇到idea下默認不提供servlet-api.jar時,使用scope=provided就會缺乏對應的jar包.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<scope>provided</scope>
</dependency>

必須編寫一個SpringBootServletInitializer的子類,並調用configure方法

package cn.edu.aynu.defineconfig;

import cn.edu.aynu.WebProjectApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

/**
 * Description: 02-web-project
 * Created by lenovo on 2019/5/1 18:30
 */
public class servletInitializer extends SpringBootServletInitializer {


    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {

        /*傳入Springboot應用的主程序*/
        return builder.sources(WebProjectApplication.class);




    }
}
MyConfig

啓動服務器便可
原理:

jar包:執行SpringBoot主類的main方法,啓動ioc容器,建立嵌入式的Servlet容

war包:啓動服務器,服務器啓動SpringBoot應用【SpringBootServletInitializer】,啓動ioc容器;

規則:

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類型的類建立實例;

SpringBootServletInitializer實例執行onStartup的時候會createRootApplicationContext;建立容器

 

 protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
        SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
        builder.main(this.getClass());
        ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
        if (parent != null) {
            this.logger.info("Root context already created (using as parent).");
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
            builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
        }

        builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
        builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
        builder = this.configure(builder);
        builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)});
        SpringApplication application = builder.build();
        if (application.getAllSources().isEmpty() && AnnotationUtils.findAnnotation(this.getClass(), Configuration.class) != null) {
            application.addPrimarySources(Collections.singleton(this.getClass()));
        }

        Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
        if (this.registerErrorPageFilter) {
            application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
        }

        return this.run(application);
    }
createRootApplicationContext

//調用configure方法,子類重寫了這個方法,將SpringBoot的主程序類傳入了進來

//使用builder建立一個Srin

//啓動Sring

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
run

啓動Servlet容器,再啓動SpringBoot

 ------------------------------------------------------------------

自定義啓動器

 

@Configuration     //指定這個類是一個配置類
@ConditionalOnXXX  //在指定條件成立的狀況下自動配置類生效
@AutoConfigureAfter//指定自動配置類的順序
@Bean              //給容器中添加組件
@ConfigurationPropertie       //結合相關xxxProperties類來綁定相關的配置
@EnableConfigurationProperties//讓xxxProperties生效加入到容器中

 

 先放上個人代碼吧  自定義的場景啓動類

package cn.edu.aynu.config;

import cn.edu.aynu.properties.SomeServiveProperties;
import cn.edu.aynu.service.SomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: 01-project-myweb
 * Created by lenovo on 2019/5/1 9:00
 */
@Configuration  //指定這個類是配置類
@ConditionalOnClass(SomeService.class)  //判斷這個類是否是存在,若是存在的狀況下,自動配置類生效
@EnableConfigurationProperties(SomeServiveProperties.class)//讓SomeServiveProperties生效加入到容器中,這個時候它裏面已經保存了從配置文件讀取到的值。
                                                            //經過自動注入就能取到這個對象裏面的值

public class SomeServiceConfig {
    @Autowired
    private SomeServiveProperties sp;


    /*讓咱們的自定義方法生效將這個方法加入到容器中*/
    @Bean
    public SomeService someService(){

        return new SomeService(sp.getBefore(),sp.getAfter());
    }




}
SomeServiceConfig
package cn.edu.aynu.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Description: 01-project-myweb
 * Created by lenovo on 2019/5/1 8:32
 */
@Data
@ConfigurationProperties("some.service")
public class SomeServiveProperties {

    private String before;
    private String after;


}
SomeServiveProperties
package cn.edu.aynu.service;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * Description: 01-project-myweb
 * Created by lenovo on 2019/5/1 8:21
 */
@Data
@NoArgsConstructor
@ToString
public class SomeService {
    private String before;
    private String after;

    public SomeService(String before, String after) {
        this.before = before;
        this.after = after;
    }

    /*核心方法,會調用這個方法*/
    public String wrap(String word){

        return before+word+after;
    }
}
SomeService

org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.edu.aynu.config.SomeServiceConfig
spring.factories

 而後再自定義一個工程用於檢測咱們的場景啓動器是否成功的創建

<dependency>
            <groupId>wrapproject</groupId>
            <artifactId>wrap-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
pom
package cn.edu.aynu.controller;

import cn.edu.aynu.service.SomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description: 02-web-project
 * Created by lenovo on 2019/5/1 16:04
 */
@RestController
public class Handler {

    @Autowired
    SomeService someService;

    @RequestMapping("/myquest")
    public String handlerQequest(){

     return someService.wrap("hello");


    }


}
controller
some.service.before=hello
some.service.after=bye
pom

遇到的問題

1.把以war 打包的方式改爲以jar的方式打包

若是是maven文件只須要改pom文件就能夠了

   pom文件上面也是須要改的
<groupId>wrap-project</groupId>
<artifactId>wrap-spring-boot-stater</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>



<plugin> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> </plugin>

若是還不行那你試試

把它改了,應該就好了吧,個人是能夠的不一樣的電腦一樣的錯誤改法可能不同啊。

 

當我打包測試類的時候出現錯誤

-------------------------------------------------------------------------------
Test set: cn.edu.aynu.WebprojectApplicationTests
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.806 s <<< FAILURE! - in cn.edu.aynu.WebprojectApplicationTests
initializationError(cn.edu.aynu.WebprojectApplicationTests)  Time elapsed: 0.01 s  <<< ERROR!
java.lang.IllegalStateException: Found multiple @SpringBootConfiguration annotated classes [Generic bean: class [cn.edu.aynu.WebprojectApplication]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Users\lenovo\Desktop\190429\01-project-myweb\web-project\target\classes\cn\edu\aynu\WebprojectApplication.class], Generic bean: class [cn.edu.aynu.WrapSpringBootStaterApplication]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/D:/Maven/Repositories/wrap-project/wrap-spring-boot-stater/1.0-SNAPSHOT/wrap-spring-boot-stater-1.0-SNAPSHOT.jar!/cn/edu/aynu/WrapSpringBootStaterApplication.class]]

這個問題的解決方案

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

由於個人啓動類不是springboot快速建立,而是一個通常的maven工程,因此出現了這個錯誤。而後個人最簡單的辦法就是建立兩個快速建立的springboot項目

而後要勾選上

當代碼寫完了以後要進行 install 安裝到倉庫中。到此,其餘用戶就能夠經過引入該Starter依賴,

而後從容器中獲取咱們自定義組件實現該業務。

 

 而後呢咱們須要的業務可不是就這麼簡單

@ConditionalOnProperty來控制Configuration是否生效

package cn.edu.aynu.config;

import cn.edu.aynu.properties.SomeServiveProperties;
import cn.edu.aynu.service.SomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: 01-project-myweb
 * Created by lenovo on 2019/5/1 9:00
 */
@Configuration  //指定這個類是配置類
@ConditionalOnClass(SomeService.class)  //判斷這個類是否是存在,若是存在的狀況下,自動配置類生效
@EnableConfigurationProperties(SomeServiveProperties.class)//讓SomeServiveProperties生效加入到容器中,這個時候它裏面已經保存了從配置文件讀取到的值。
                                                            //經過自動注入就能取到這個對象裏面的值
//@ConditionalOnProperty(prefix = "some.service",name = "enabled",havingValue = "true")
public class SomeServiceConfig {
    @Autowired
    private SomeServiveProperties sp;


    /*讓咱們的自定義方法生效將這個方法加入到容器中*/
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "some.service",name = "enabled",havingValue = "true")
    public SomeService someService(){

        return new SomeService(sp.getBefore(),sp.getAfter());
    }
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "some.service",name = "enabled",havingValue = "false")
    public SomeService someService1(){

        return new SomeService(sp.getBefore(),sp.getAfter());
    }




}
SomeServiceConfig

 

查看源碼能夠發現

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {

    String[] value() default {}; //數組,獲取對應property名稱的值,與name不可同時使用  
  
    String prefix() default "";//property名稱的前綴,無關緊要  
  
    String[] name() default {};//數組,property完整名稱或部分名稱(可與prefix組合使用,組成完整的property名稱),與value不可同時使用  
  
    String havingValue() default "";//可與name組合使用,比較獲取到的屬性值與havingValue給定的值是否相同,相同才加載配置  
  
    boolean matchIfMissing() default false;//缺乏該property時是否能夠加載。若是爲true,沒有該property也會正常加載;反之報錯  
  
    boolean relaxedNames() default true;//是否能夠鬆散匹配,至今不知道怎麼使用的  
} 
}
經過其兩個屬性name以及havingValue來實現的,其中name用來從application.properties中讀取某個屬性值。
若是該值爲空,則返回false;
若是值不爲空,則將該值與havingValue指定的值進行比較,若是同樣則返回true;不然返回false。
若是返回值爲false,則該configuration不生效;爲true則生效。

該註解還有個屬性: matchIfMissing=true (默認爲false)  意思就是說當沒配置framework.web.filter.enabled也會使其生效

 prefix是   application.properties配置的前綴

name 屬性是從application.properties配置文件中讀取屬性值

matchIfMissing = true表示若是沒有在application.properties設置該屬性,則默認爲條件符合

解釋幾個註解

@Bean默認狀況下bean的名稱和方法名稱相同,首字母小寫,你也可使用name屬性來指定

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

}
bean的基本定義

這個配置就等同於以前在xml裏的配置

<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
xml

bean的依賴

@bean 也能夠依賴其餘任意數量的bean,若是TransferService 依賴 AccountRepository,咱們能夠經過方法參數實現這個依賴

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }

}
bean依賴

接受生命週期的回調

任何使用@Bean定義的bean,也能夠執行生命週期的回調函數,相似@PostConstruct and @PreDestroy的方法。用法以下

public class Foo {
    public void init() {
        // initialization logic
    }
}

public class Bar {
    public void cleanup() {
        // destruction logic
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public Foo foo() {
        return new Foo();
    }

    @Bean(destroyMethod = "cleanup")
    public Bar bar() {
        return new Bar();
    }

}
bean 回調

默認使用javaConfig配置的bean,若是存在close或者shutdown方法,則在bean銷燬時會自動執行該方法,若是你不想執行該方法,則添加@Bean(destroyMethod="")來防止出發銷燬方法

@Bean 還支持註解

@Configuration
public class AppConfig {

    @Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
    public DataSource dataSource() {
        // instantiate, configure and return DataSource bean...
    }

}
bean別名

指定bean的scope

使用@Scope註解

你可以使用@Scope註解來指定使用@Bean定義的bean

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }

}
bean 的scope

bean的描述

 有時候提供bean的詳細信息也是頗有用的,bean的描述可使用 @Description來提供

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Foo foo() {
        return new Foo();
    }

}
bean的描述

 註解二

(https://blog.csdn.net/qq_36567005/article/details/80611139)

  @Qualifier

 在controller中須要注入service 那麼個人這個service 有兩個實現類如何區分

 

 

package cn.edu.aynu.defineconfig;

import cn.edu.aynu.WebProjectApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

/**
 * Description: 02-web-project
 * Created by lenovo on 2019/5/1 18:30
 */
public class servletInitializer extends SpringBootServletInitializer {


    @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {

        /*傳入Springboot應用的主程序*/
return builder.sources(WebProjectApplication.class);




}
}
View Code

Docker簡介

 簡介:Docker是一個開源的應用容器引擎;是一個輕量級容器技術;

 

Docker支持將軟件編譯成一個鏡像;而後在鏡像中各類軟件作好配置,將鏡像發佈出去,其餘使用者能夠直接使
用這個鏡像;
運行中的這個鏡像稱爲容器,容器啓動是很是快速的。

 

核心概念

 

 

 

docker主機(Host):安裝了Docker程序的機器(Docker直接安裝在操做系統之上);
docker客戶端(Client):鏈接docker主機進行操做;
docker倉庫(Registry):用來保存各類打包好的軟件鏡像;
docker鏡像(Images):軟件打包好的鏡像;放在docker倉庫中;
docker容器(Container):鏡像啓動後的實例稱爲一個容器;容器是獨立運行的一個或一組應用

 

 

 

使用Docker的步驟:
1)、安裝Docker
2)、去Docker倉庫找到這個軟件對應的鏡像;
3)、使用Docker運行這個鏡像,這個鏡像就會生成一個Docker容器;
4)、對容器的啓動中止就是對軟件的啓動中止;

 1)、安裝linux虛擬機1)、VMWare、VirtualBox(安裝);

2)、導入虛擬機文件centos7-atguigu.ova

3)、雙擊啓動linux虛擬機;使用 root/ 123456登錄

4)、使用客戶端鏈接linux服務器進行命令操做;

5)、設置虛擬機網絡;橋接網絡=選好網卡==接入網線;

6)、設置好網絡之後使用命令重啓虛擬機的

 

service network restart

查看linux的ip地址

 

ip addr

使用客戶端鏈接linux;

 在linux虛擬機上安裝docker

 

1、檢查內核版本,必須是3.10及以上
uname ‐r
2、安裝docker
yum install docker
3、輸入y確認安裝
4、啓動docker
[root@localhost ~]# systemctl start docker
[root@localhost ~]# docker ‐v
Docker version 1.12.6, build 3e8e77d/1.12.6
5、開機啓動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.
6、中止docker
systemctl stop docker

Docker經常使用命令&操做

 

https://hub.docker.co

 軟件鏡像(QQ安裝程序)----運行鏡像----產生一個容器(正在運行的軟件,運行的QQ);

 

1、搜索鏡像
[root@localhost ~]# docker search tomcat
2、拉取鏡像
[root@localhost ~]# docker pull tomcat
3、根據鏡像啓動容器
docker run ‐‐name mytomcat ‐d tomcat:latest
4、docker ps
查看運行中的容器
5、 中止運行中的容器
docker stop 容器的id
6、查看全部的容器
docker ps ‐a
7、啓動容器
docker start 容器id
8、刪除一個容器
docker rm 容器id
9、啓動一個作了端口映射的tomcat
[root@localhost ~]# docker run ‐d ‐p 8888:8080 tomcat
‐d:後臺運行
‐p: 將主機的端口映射到容器的一個端口 主機端口:容器內部的端口
10、爲了演示簡單關閉了linux的防火牆
service firewalld status ;查看防火牆狀態
service firewalld stop:關閉防火牆
11、查看容器的日誌
docker logs container‐name/container‐id
更多命令參看
https://docs.docker.com/engine/reference/commandline/docker/
能夠參考每個鏡像的文檔

安裝MySQL示例

docker pull mysql

SpringBoot與數據訪問

JDBC
<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做爲數據源;
數據源的相關配置都在DataSourceProperties裏面;

public interface DataSource  extends CommonDataSource, Wrapper {

  Connection getConnection() throws SQLException;
  Connection getConnection(String username, String password)
    throws SQLException;
abstract class DataSourceConfiguration {

    @SuppressWarnings("unchecked")
    protected static <T> T createDataSource(DataSourceProperties properties,
            Class<? extends DataSource> type) {
        return (T) properties.initializeDataSourceBuilder().type(type).build();
    }

    /**
     * Tomcat Pool DataSource configuration.
     */
    @Configuration
    @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type",
            havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
    static class Tomcat {

        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.tomcat")
        public org.apache.tomcat.jdbc.pool.DataSource dataSource(
                DataSourceProperties properties) {
            org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
                    properties, org.apache.tomcat.jdbc.pool.DataSource.class);
            DatabaseDriver databaseDriver = DatabaseDriver
                    .fromJdbcUrl(properties.determineUrl());
            String validationQuery = databaseDriver.getValidationQuery();
            if (validationQuery != null) {
                dataSource.setTestOnBorrow(true);
                dataSource.setValidationQuery(validationQuery);
            }
            return dataSource;
        }

    }

    /**
     * Hikari DataSource configuration.
     */
    @Configuration
    @ConditionalOnClass(HikariDataSource.class)
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type",
            havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
    static class Hikari {

        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.hikari")
        public HikariDataSource dataSource(DataSourceProperties properties) {
            HikariDataSource dataSource = createDataSource(properties,
                    HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }
            return dataSource;
        }

    }

    /**
     * DBCP DataSource configuration.
     */
    @Configuration
    @ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type",
            havingValue = "org.apache.commons.dbcp2.BasicDataSource",
            matchIfMissing = true)
    static class Dbcp2 {

        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.dbcp2")
        public org.apache.commons.dbcp2.BasicDataSource dataSource(
                DataSourceProperties properties) {
            return createDataSource(properties,
                    org.apache.commons.dbcp2.BasicDataSource.class);
        }

    }

    /**
     * Generic DataSource configuration.
     */
    @Configuration
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type")
    static class Generic {

        @Bean
        public DataSource dataSource(DataSourceProperties properties) {
            return properties.initializeDataSourceBuilder().build();
        }

    }

自動配置原理:
org.springframework.boot.autoconfigure.jdbc:
一、參考DataSourceConfiguration,根據配置建立數據源,默認使用Tomcat鏈接池;可使用
spring.datasource.type指定自定義的數據源類型;

二、SpringBoot默承認以支持;

org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、

自定義數據源類型

/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
   @Bean
   public DataSource dataSource(DataSourceProperties properties) {
  //使用DataSourceBuilder建立數據源,利用反射建立響應type的數據源,而且綁定相關屬性
   return properties.initializeDataSourceBuilder().build();
   }
}

DataSourceInitializer:ApplicationListener;

做用:
1)、runSchemaScripts();運行建表語句;
2)、runDataScripts();運行插入數據的sql語句;

默認只須要將文件命名爲:

schema‐*.sql、data‐*.sql
默認規則:schema.sql,schema‐all.sql;
可使用
schema:
‐ classpath:department.sql
指定位置

五、操做數據庫:自動配置了JdbcTemplate操做數據庫

 spring:
      datasource:
        username: root
        password: root
        url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
        schema:
          - classpath:sql/department.sql
          - classpath:sql/employee.sql
pom

根據上面的配置,能夠知道掃描 resources下面的.sql文件,而後加載這個sql文件,在數據庫中進行建立

 

如何整合Druid數據源

首先確定是一個配置文件,當配置好了druid數據源以後,根據.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); 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; } }


 

整合Mybaties

<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis‐spring‐boot‐starter</artifactId>
   <version>1.3.1</version>
</dependency>

註解版

//指定這是一個操做數據庫的mapper
@Mapperpublic 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);
}

問題:
自定義MyBatis的配置規則;給容器中添加一個ConfigurationCustomizer;

@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);
}
}

 

 

下面一個就是配置文件版

像spring 寫sql文件同樣聲明配置文件,還有映射文件、

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.edu.aynu.springboot.zhaoyujing.mapper.EmployeeMapper">
   <!--    public Employee getEmpById(Integer id);

    public void insertEmp(Employee employee);-->
    <select id="getEmpById" resultType="cn.edu.aynu.springboot.zhaoyujing.entities.Employee">
        SELECT * FROM employee WHERE id=#{id}
    </select>

    <insert id="insertEmp">
        INSERT INTO employee(lastName,email,gender,d_id) VALUES (#{lastName},#{email},#{gender},#{dId})
    </insert>

    <select id="getAll" resultType="cn.edu.aynu.springboot.zhaoyujing.entities.Employee">
         SELECT * FROM employee
    </select>
    <delete id="delete">
        delete from employee WHERE id=#{id}
    </delete>
</mapper>
EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--駝峯命名法-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>
Mybatis-config.xml

整合srpingData    JPA

 

1.寫一個實體類

//使用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;

2)、編寫一個Dao接口來操做實體類對應的數據表(Repository)

也就是你能夠自定義sql語句而後直接就能夠被使用了,可是定義的方法名要符合一些規則
具體信息在下面這個網址中(https://www.cnblogs.com/zhulina-917/p/10504377.html)
//繼承JpaRepository來完成對數據庫的操做
public interface UserRepository extends JpaRepository<User,Integer> {
}

 基本的配置JpaProperties

spring:
jpa:
hibernate:
# 更新或者建立數據表結構
ddl‐auto: update
# 控制檯顯示SQL
show‐sql: true

講解springboot的啓動配置原理

幾個重要的事件回調機制

配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener

 

只須要放在ioc容器中
ApplicationRunner
CommandLineRunner

啓動流程

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();
}

運行run方法

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();      
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);
}
}

 

 事件的監聽機制

配置在META-INF/spring.factories
ApplicationContextInitializer

public class HelloApplicationContextInitializer implements
   ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("ApplicationContextInitializer...initialize..."+applicationContext); } }

SpringApplicationRunListener

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...");
}
}

配置(META-INF/spring.factories)

org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener

相關文章
相關標籤/搜索