1. 程式人生 > 其它 >SpringBoot2基礎—入門和了解自動配置原理

SpringBoot2基礎—入門和了解自動配置原理

Spring與SpringBoot

1、Spring的生態

https://spring.io/projects/spring-boot

覆蓋了:

web開發

資料訪問

安全控制

分散式

訊息服務

移動開發

批處理

Spring5的升級

響應式程式設計

為什麼要用SpringBoot

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

能快速創建出生產級別的Spring應用

SpringBoot的優點

  • Create stand-alone Spring applications

    • 建立獨立Spring應用
  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)

    • 內嵌web伺服器
  • Provide opinionated 'starter' dependencies to simplify your build configuration

    • 自動starter依賴,簡化構建配置
  • Automatically configure Spring and 3rd party libraries whenever possible

    • 自動配置Spring以及第三方功能
  • Provide production-ready features such as metrics, health checks, and externalized configuration

    • 提供生產級別的監控、健康檢查及外部化配置
  • Absolutely no code generation and no requirement for XML configuration

    • 無程式碼生成、無需編寫XML

SpringBoot是整合Spring技術棧的一站式框架

SpringBoot是簡化Spring技術棧的快速開發腳手架

SpringBoot缺點

1、版本迭代快,需要時刻關注變化

2、封裝太深了,內部原理複雜

時代背景(微服務)

微服務

微服務的完整概念:https://martinfowler.com/microservices/

  • 微服務是一種架構風格

  • 一個應用拆分為一組小型服務

  • 每個服務執行在自己的程序內,也就是可獨立部署和升級

  • 服務之間使用輕量級HTTP互動

  • 服務圍繞業務功能拆分

  • 可以由全自動部署機制獨立部署

  • 去中心化,服務自治。服務可以使用不同的語言、不同的儲存技術

分散式

分散式的困難

  • 遠端呼叫
  • 服務發現
  • 負載均衡
  • 服務容錯
  • 配置管理
  • 服務監控
  • 鏈路追蹤
  • 日誌管理
  • 任務排程

分散式的解決:

SpringBoot+SpringCloud

雲原生

原生應用如何上雲。 Cloud Native

雲原生的困難:

  • 服務自愈

  • 彈性伸縮

  • 服務隔離

  • 自動化部署

  • 灰度釋出

  • 流量治理

如何學習SpringBoot

SpringBoot官方文件:https://spring.io/

檢視版本更新日誌:

或者直接網址:https://github.com/spring-projects/spring-boot/wiki#release-notes

SpringBoot2入門

系統要求:

JDK8 以上

Maven3.3+

Maven設定

需要更改Maven映象倉庫地址(改成阿里雲) 和更改JDK版本號

<mirrors>
      <mirror>
        <id>nexus-aliyun</id>
        <mirrorOf>central</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
      </mirror>
  </mirrors>
 
  <profiles>
         <profile>
              <id>jdk-1.8</id>
              <activation>
                <activeByDefault>true</activeByDefault>
                <jdk>1.8</jdk>
              </activation>
              <properties>
                <maven.compiler.source>1.8</maven.compiler.source>
                <maven.compiler.target>1.8</maven.compiler.target>
                <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
              </properties>
         </profile>
  </profiles>

HelloWorld

需要:瀏覽傳送/hello請求,響應Hello , Spring Boot 2

建立maven工程

引入依賴

    <!--SpringBoot版本號-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.0</version>
    </parent>


    <dependencies>
        <!--Web場景開發的一套-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

建立主程式

/**
 * @author 喂S別鬧
 * @create 2021/10/13-14:26
 * @Version 1.0
 * @Description: 主程式入口
 */

//@SpringBootApplication:這是一個SpringBoot應用    主程式類
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class , args);
    }
}

編寫業務程式碼

//@ResponseBody 也可以寫在方法名上  表示這個類下的每一個方法的返回的資料直接是寫給瀏覽器的。
//@Controller

@RestController //等於@Controller+@ResponseBody
public class HelloController {
    @RequestMapping("/hello")
    public String hand01(){
        return "Hello,SpringBoot2!!";
    }
}

測試

直接執行main方法

簡化配置

在資原始檔下配置:

application.properties檔案

# 埠更改
server.port=8081  

簡化部署

在Pom檔案下新增外掛

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

把專案打成jar包,直接在目標伺服器執行即可。

注意點:

  • 在執行jar過程時,需要取消cmd的快速編輯模式

瞭解自動配置原理

SpringBoot的特點:

依賴管理

  • 父專案做依賴管理
<!--SpringBoot版本號-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
</parent>

它的父專案
 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.4.0</version>
  </parent>
裡面就是幾乎聲明瞭所有開發中常用的依賴的版本號,自動版本仲裁機制
  • 開發匯入starter場景啟動器

1、見到很多 spring-boot-starter-* : *就某種場景

2、只要引入starter,這個場景的所有常規需要的依賴我們都自動引入

3、SpringBoot所有支援的場景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter

4、見到的 *-spring-boot-starter: 第三方為我們提供的簡化開發的場景啟動器。

5、所有場景啟動器最底層的依賴

  <!--Web場景開發的一套-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

這個裡面的
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.4.0</version>
      <scope>compile</scope>
    </dependency>
  • 我們不再需要關注版本號,SpringBoot有自動版本仲裁

1、引入依賴預設都可以不寫版本

2、引入非版本仲裁的jar,要寫版本號。

  • 可以修改預設版本號

在pom.xml檔案

1、檢視spring-boot-dependencies裡面規定當前依賴的版本 用的 key。

2、在當前專案裡面重寫配置

    <properties>
        <mysql.version>5.1.43</mysql.version>
    </properties>

    <dependencies>
        <!--Web場景開發的一套-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

如果不寫SpringBoot就會預設使用仲裁的版本號

自動配置

  • 自動配置好Tomcat
    • 引入Tomcat依賴
    • 配置Tomcat
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
  <version>2.4.0</version>
  <scope>compile</scope>
</dependency>
  • 自動配好SpringMVC

    • 引入SpringMVC全套元件

    • 自動配置好SpringMVC常用元件(功能)

  • 自動配好Web常見功能,如:字元編碼問題

    • SpringBoot幫配置好了所有Web開發的常見場景
  • 預設的包結構

    • 主程式所在包及其下面的所有子包裡面的元件都會被預設掃描
    • 無需以前的包掃描配置
    • 想要改變掃描路徑@SpringBootApplication(scanBasePackages = "com.li")
      • 或者@ComponentScan指定掃描路徑
      • 或者把SpringBootApplication換成一下三個:
//@SpringBootApplication:這是一個SpringBoot應用    主程式類
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.li")
public class MainApplication {
    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、檢視容器裡面的元件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}
  • 各種配置擁有預設值
    • 預設配置最終都是對映到MultipartProperties
    • 配置檔案的值最終會繫結每個類上,這個類會在容器建立物件
  • 按需載入所有自動配置項
    • 非常多的starter
    • 引入了哪些場景這個場景的自動配置才會開啟
    • SpringBoot所有的自動配置功能都在 spring-boot-autoconfigure 包裡面

容器功能

元件新增

1、@Configuration

  • 基本使用
  • Full模式與Lite模式

例子:

    • 配置 類元件之間無依賴關係用Lite模式加速容器啟動過程,減少判斷

    • 配置類元件之間有依賴關係,方法會被呼叫得到之前單例項元件,用Full模式

#############################Configuration使用示例######################################################
/**
 * 1、配置類裡面使用@Bean標註在方法上給容器註冊元件,預設也是單例項的
 * 2、配置類本身也是元件
 * 3、proxyBeanMethods:代理bean的方法
 *      Full(proxyBeanMethods = true)、【保證每個@Bean方法被呼叫多少次返回的元件都是單例項的】
 *      Lite(proxyBeanMethods = false)【每個@Bean方法被呼叫多少次返回的元件都是新建立的】
 *      元件依賴必須使用Full模式預設。其他預設是否Lite模式
 *
 *
 *
 */
@Configuration(proxyBeanMethods = false) //告訴SpringBoot這是一個配置類 == 配置檔案
public class MyConfig {

    /**
     * Full:外部無論對配置類中的這個元件註冊方法呼叫多少次獲取的都是之前註冊容器中的單例項物件
     * @return
     */
    @Bean //給容器中新增元件。以方法名作為元件的id。返回型別就是元件型別。返回的值,就是元件在容器中的例項
    public User user01(){
        User zhangsan = new User("zhangsan", 18);
        //user元件依賴了Pet元件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}


################################@Configuration測試程式碼如下########################################
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
public class MainApplication {

    public static void main(String[] args) {
        //1、返回我們IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、檢視容器裡面的元件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        //3、從容器中獲取元件

        Pet tom01 = run.getBean("tom", Pet.class);

        Pet tom02 = run.getBean("tom", Pet.class);

        System.out.println("元件:"+(tom01 == tom02));


        //4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

        //如果@Configuration(proxyBeanMethods = true)代理物件呼叫方法。SpringBoot總會檢查這個元件是否在容器中有。
        //保持元件單例項
        User user = bean.user01();
        User user1 = bean.user01();
        System.out.println(user == user1);


        User user01 = run.getBean("user01", User.class);
        Pet tom = run.getBean("tom", Pet.class);

        System.out.println("使用者的寵物:"+(user01.getPet() == tom));



    }
}

@Bean、@Component、@Controller、@Service、@Repository

  • bean:
  • Component:表示是一個元件
  • Controller:控制器
  • Service:業務邏輯元件
  • Repository:資料庫層元件

@ComponentScan、@Import新增元件

@Import:匯入元件

@Import({Pet.calss,Person.class})給容器中自動創建出這兩個型別的元件、預設元件的名字就是全類名

@Import 高階用法: https://www.bilibili.com/video/BV1gW411W7wy?p=8

@Conditional

條件裝配:滿足Conditional指定的條件,則進行元件注入

=====================測試條件裝配==========================
@Configuration(proxyBeanMethods = false) //告訴SpringBoot這是一個配置類 == 配置檔案
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {


    /**
     * Full:外部無論對配置類中的這個元件註冊方法呼叫多少次獲取的都是之前註冊容器中的單例項物件
     * @return
     */

    @Bean //給容器中新增元件。以方法名作為元件的id。返回型別就是元件型別。返回的值,就是元件在容器中的例項
    public User user01(){
        User zhangsan = new User("zhangsan", 18);
        //user元件依賴了Pet元件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom22")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}

public static void main(String[] args) {
        //1、返回我們IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、檢視容器裡面的元件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        boolean tom = run.containsBean("tom");
        System.out.println("容器中Tom元件:"+tom);

        boolean user01 = run.containsBean("user01");
        System.out.println("容器中user01元件:"+user01);

        boolean tom22 = run.containsBean("tom22");
        System.out.println("容器中tom22元件:"+tom22);


    }

原生配置檔案引入

@ImportResource

======================beans.xml=========================
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="haha" class="com.atguigu.boot.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>

    <bean id="hehe" class="com.atguigu.boot.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>
@ImportResource("classpath:beans.xml")
public class MyConfig {}

======================測試=================
        boolean haha = run.containsBean("haha");
        boolean hehe = run.containsBean("hehe");
        System.out.println("haha:"+haha);//true
        System.out.println("hehe:"+hehe);//true

配置繫結

使用Java讀取到properties檔案中的內容,並且把它封裝到JavaBean中,以供隨時使用;

public class getProperties {
     public static void main(String[] args) throws FileNotFoundException, IOException {
         Properties pps = new Properties();
         pps.load(new FileInputStream("a.properties"));
         Enumeration enum1 = pps.propertyNames();//得到配置檔案的名字
         while(enum1.hasMoreElements()) {
             String strKey = (String) enum1.nextElement();
             String strValue = pps.getProperty(strKey);
             System.out.println(strKey + "=" + strValue);
             //封裝到JavaBean。
         }
     }
 }

@ConfigurationProperties

/**
 * 只有在容器中的元件,才會擁有SpringBoot提供的強大功能
 */
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {

    private String brand;
    private Integer price;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}

@EnableConfigurationProperties + @ConfigurationProperties

@Component + @ConfigurationProperties

@EnableConfigurationProperties(Car.class)
//1、開啟Car配置繫結功能
//2、把這個Car這個元件自動註冊到容器中
public class MyConfig {
}

自動配置原理入門

引入載入自動配置類(SpringBootApplication)

SpringBootApplication()註解裡面的方法

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication

@SpringBootConfiguration裡面就是Configuration

@Configuration。代表當前是一個配置類

@ComponentScan:指定掃描哪些包

重點是:

EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration

@AutoConfigurationPackage:自動配置包

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage
    
    //利用Registrar給容器中匯入一系類元件
    //將指定的一個包下的所有元件匯入進來MainApplication所在包下。

@Import:給容器中匯入一個元件