iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0
自我挑戰組

探索 Spring Boot Doc系列 第 29

Doc 7.1.5. Fluent Builder API

  • 分享至 

  • xImage
  •  

If you need to build an ApplicationContext hierarchy (multiple contexts with a parent/child relationship) or if you prefer using a “fluent” builder API, you can use the SpringApplicationBuilder.

假若需要建立ApplicationContext(容器) 繼承關係,或是使用者偏好流順的建立API ,那麼可以使用 SpringApplicationBuilder

直接採用 class SpringApplication 啟動 application,得到下方畫面

public static void main(String[] args) {
        SpringApplication.run(CtxFluentApplication.class, args);
    }

https://ithelp.ithome.com.tw/upload/images/20231014/20161770ZtCsakFb1m.png

父類別(/parent)

這裡採用 Fluent Builder API 啟動 application (這裡只填入 父類別的註冊類別)

public static void main(String[] args) {
        new SpringApplicationBuilder().parent(ParentConfig.class)
            .web(WebApplicationType.NONE)
            .run(args);
    }

https://ithelp.ithome.com.tw/upload/images/20231014/20161770ALcyoqo8tP.png
此時,啟動application啟動完就會關閉,因為WebApplicationType.NONE 就是當作一般 Java 程式。

Parent 註冊類別

@Configuration
@ComponentScan
public class ParentConfig {

}

@ComponentScan 採用預設值會自動掃描 class ParentConfig 所在 /parent 的內容

Parent Service Interface

public interface IHomeService {

    String getGreeting();
}

Parent Service

@Service
public class HomeService implements IHomeService{

    @Override
    public String getGreeting() {
        return "Welcome User";
    }
}

Childe one(/ctx1)

child one 自己實作介面

@Service
public class GreetingService implements IHomeService {

    @Override
    public String getGreeting() {
        return "Greetings for the day";
    }
}

child one’s configuration

@Configuration
@ComponentScan
@PropertySource("classpath:ctx1.properties")
@EnableAutoConfiguration
public class Ctx1Config {

    @Bean
    public IHomeService homeService() {
        return new GreetingService();
    }
}

透過 @PropertySource 去讀取不同的 Properties

child one’s controller

@RestController
public class Ctx1Controller {
    @Autowired
    private IHomeService homeService;

    @GetMapping("/home")
    public String greeting() {
        return homeService.getGreeting();
    }
}

Child Two(/ctx2)

child two’s configuration

@Configuration
@ComponentScan
@EnableAutoConfiguration
@PropertySource("classpath:ctx2.properties")
public class Ctx2Config {

}

child two’s controller

@RestController
public class Ctx2Controller {
    @Autowired
    private IHomeService homeService;

    @GetMapping("/greeting")
    public String getGreeting() {
        return homeService.getGreeting();
    }
}

調整SpringApplicationBuilder

public static void main(String[] args) {
        new SpringApplicationBuilder().parent(
                ParentConfig.class)
            .web(WebApplicationType.NONE)
            .child(Ctx1Config.class)
            .web(WebApplicationType.SERVLET)
            .sibling(Ctx2Config.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }

這裡透過 SpringApplicationBuilder 去建立 parent 的 context,在透過 child 去建立第一個 child context 之後透過 sibling 去建立第二個 child context ,這裡有一個疑問,如果第二個child ctx2 也是用 child 去建立會發生什麼事情?
程式碼,只會完成一個context 的建立。 至於為什麼?

SpringApplicationBuilder.child 會另外開一個 Builder 並將之回傳

public SpringApplicationBuilder child(Class<?>... sources) {
		SpringApplicationBuilder child = new SpringApplicationBuilder();
		child.sources(sources);
	//省略以下內容

		return child;
}

所以後面builder chain 的時候,就是以child 去的角度去建立context,自然是 chlid’s sibling,
而不是 child’s child 。

children’s properties

ctx1.properties(Child one)

server.port=8074
server.servlet.context-path=/ctx1

spring.application.admin.enabled=false
spring.application.admin.jmx-name=org.springframework.boot:type=Ctx1Rest,name=Ctx1Application

ctx1.properties(Child two)

server.port=8075
server.servlet.context-path=/ctx2

spring.application.admin.enabled=false
spring.application.admin.jmx-name=org.springframework.boot:type=WebAdmin,name=SpringWebApplication

啟動log

這裡application 會啟監聽不同port號的tomcat server,註冊檔有刻意切割兩個Root URI。
下方為啟動應用時的log,第一段是啟動 Parent 的部分
https://ithelp.ithome.com.tw/upload/images/20231014/20161770uMW4vOT7Xn.png
log 第二段是第一個 child ctx1 的 tomcat 啟動
https://ithelp.ithome.com.tw/upload/images/20231014/20161770Eh4Y7XSkSp.png
log第三段是第二個child ctx2 的 tomcat 啟動
https://ithelp.ithome.com.tw/upload/images/20231014/201617705SpXbe3GZu.png

下方為 API 回應的 log,透過不同URL 打兩個child 的 API 發現,ctx1 有自己實作 IHomeService,所以這時候注入的會是child 自己實作的 service(由打印內容可以知道是ctx1 是用自己實作的service),而 ctx2 是用 parent 實作的 service。
https://ithelp.ithome.com.tw/upload/images/20231014/20161770kEPGOLARE3.png
https://ithelp.ithome.com.tw/upload/images/20231014/20161770FOA3u0D4Rr.png

參考資料
{官方} SpringApplicationBuilder
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/builder/SpringApplicationBuilder.html

Context Hierarchy with the Spring Boot Fluent Builder API
https://www.baeldung.com/spring-boot-context-hierarchy


上一篇
Doc 7.1.4 Customizing SpringApplication
下一篇
參賽感言
系列文
探索 Spring Boot Doc30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言