Spring boot 概觀

October 17, 2021

Spring 能做什麼

Spring 生態圈很大。包含以下

Spring boot 底層是 Spring Framework。Spring5 後有了變化,有了 spring reactive

JAVA 8 的特性也改變底層的實現原理,像是預設的 interface。

什麼是 Spring boot

Spring boot makes it easy to create stand-alone, production-grade Spring based Application that you can “just run”.

其優點官方描述有以下

也因為封裝太好,內部原始碼複雜,不容易精通。

建立一個 Spring boot 專案

使用 Maven 啟動項目後其 pom.xml 如下配置

    <packaging>jar</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
    </parent>
    
    <dependencies>
<!--     引入開發 Web 包     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
<!--   將應用打包成 jar   -->
    <build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

建立主程序

@SpringBootApplication // 表示這是一個 Spring boot 應用
public class MainApplication {
    public static void main(String[] atgs) {
        SpringApplication.run(MainApplication.class, args);
    }
}

撰寫業務

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String handle01(){
        return "Hello";
    }
}

透過 application.properties 可進行環境配置像是端口等,否則都會是預設值。最後透過 maven 打包成 jar 檔即可運行。

自動配置原理

依賴管理

在 maven 配置中,使用了 parent 進行依賴管理

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
    </parent>
    而它的父項目是
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependncies</artifactId>
        <version>2.5.5</version>
    </parent>
    在往上追蹤可以看到其聲明了常用的開發依賴版本號,因此會自動賦予版本

官方提供了很多關於 starter 場景啟動器,可參考官方,只要引入,該場景的所有依賴都會自動引入。

而這些依賴幫我們配置了以下

@SpringBootApplication 
相當於
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("PACKAGE_NAME")

容器功能

  1. @Configuration
@Configuration
public class MyConfig {
    @Bean
    public User user01() {
        return User.builder().name("name").age(12).build();
    }

    @Bean()
    public Pet pet() {
        return Pet.builder().name("tomcat").build();
    }
}
@SpringBootApplication
public class DemoApplication {
    
	public static void main(String[] args) {
        // 返回 IOC 容器
		ConfigurableApplicationContext run =  SpringApplication.run(DemoApplication.class, args);
		String[] names = run.getBeanDefinitionNames();
        // 查看使否存在於 IOC 容器中
		Arrays.stream(names).filter(i -> Objects.equals("user01", i)).forEach(System.out::println);
		Arrays.stream(names).filter(i -> Objects.equals("pet", i)).forEach(System.out::println);
	}

}

如果不要預設名稱為方法名稱,則可以如下設置 @Bean(別名)。 透過以下方式可以知道說 Bean 預設是單例的

        Pet one = run.getBean("pet", Pet.class);
		Pet two = run.getBean("pet", Pet.class);

		System.out.println(one == two);

MyConfig 本身也是一個組件,@Configuration 預設 proxyBeanMethods 是 true,代理 bean 的方法。

下面的方式可以證明說,外部無論對配置類中的某個組件註冊方法都是先前註冊容器的單例方法。其原因是 proxyBeanMethods=true,Spring boot 會檢查該組件是否在容器中。預設是保持單例,如果設定為 false每次調用都會產生一個新物件,這表示會少了檢查是否存在容器中的步驟,可提升性能。

        MyConfig bean = run.getBean(MyConfig.class);
		User u1 = bean.user01();
		User u2 = bean.user01();
		System.out.println(u1 == u2);
  1. @Import 給容器中自動創建出指定類型的組件,預設組件名稱是類名。
  2. @Conditional 條件裝配,滿足 Conditional 指定的條件,則進行組件注入。其用法有如下圖中的等方法

在底層經常使用。

  1. @ImportResource 資源引入,像是導入 Spring 的配置檔案
@ImportResource(classpath:beans.xml)

配置綁定

  1. @ConfigurationProperties
@Data
@ToString
@ConfigurationProperties(prefix = "tw")
@Component // 將此類添加到容器中
public class Car {
    private String brand;
    private Integer price;
}

接著我們在 application.properties 中就可以使用定義的配置

tw.brand=VOLVO
tw.price=100000

只有在容器中的組件,才會有 Spring boot 提供的功能

透過簡易的 controller 設置,我們可以驗證是否存在我們設定的值

@RestController
public class Hello {
    @Autowired
    Car car;

    @GetMapping(value="/car")
    public Car getMethodName() {
        return car;
    }
    
}
// {"brand":"VOLVO","price":100000}
  1. @EnableConfigurationProperties(CLASSNAME.class)

引導加載自動配置類

@SpringBootApplication 
相當於
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("PACKAGE_NAME")
  1. @SpringBootConfiguration 表示一個配置類
  2. @ComponentScan 指定掃描那些
  3. @EnableAutoConfiguration EnableAutoConfiguration 是以下註解的合成
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})

往下追會發現說其利用 Register 給容器中導入一系列組件,會從指定的 package 下,也就是 @SpringBootApplication 註解下該類 package。