Spring Boot Fluent Builder APIを使用したコンテキスト階層
1. 概要
Spring Bootでは、個別のコンテキストを作成し、それらを階層に編成することができます。
コンテキスト階層は、Spring Bootアプリケーションでさまざまな方法で定義できます。 この記事では、how we can create multiple contexts using the fluent builder APIについて説明します。
Spring Bootアプリケーションの設定方法については詳しく説明しませんので、このarticleを確認することをお勧めします。
2. アプリケーションコンテキスト階層
親子関係を共有する複数のアプリケーションコンテキストを持つことができます。
A context hierarchy allows multiple child contexts to share beans which reside in the parent context.各子コンテキストは、親コンテキストから継承された構成をオーバーライドできます。
さらに、コンテキストを使用して、あるコンテキストで登録されたBeanが別のコンテキストでアクセスできないようにすることができます。 これにより、疎結合モジュールの作成が容易になります。
ここで、注目に値するいくつかのポイントは、コンテキストは1つの親しか持つことができず、親コンテキストは複数の子コンテキストを持つことができるということです。 また、子コンテキストは親コンテキストのBeanにアクセスできますが、その逆はできません。
3. SpringApplicationBuilderAPIの使用
SpringApplicationBuilderクラスは、parent()、child() 、およびsibling()メソッドを使用してコンテキスト間の親子関係を作成するための流暢なAPIを提供します。
コンテキスト階層を例示するために、we’ll set up a non-web parent application context with 2 child web contexts.
これを実証するために、それぞれが独自のWebアプリケーションコンテキストを持ち、両方とも単一のJVMで実行される組み込みTomcatの2つのインスタンスを開始します。
3.1. 親コンテキスト
まず、親パッケージに存在するBean定義クラスとともにサービスBeanを作成しましょう。 このBeanは、Webアプリケーションのクライアントに表示される挨拶を返します。
@Service
public class HomeService implements IHomeService {
public String getGreeting() {
return "Welcome User";
}
}
そして、Bean定義クラス:
@Configuration
@ComponentScan("com.example.parent")
public class ServiceConfig {}
次に、2つの子コンテキストの構成を作成します。
3.2. 子コンテキスト
すべてのコンテキストはデフォルトの構成ファイルを使用して構成されているため、サーバーポートなどのコンテキスト間で共有できないプロパティに対して個別の構成を提供する必要があります。
競合する構成が自動構成によって取得されるのを防ぐために、クラスも別々のパッケージに保持します。
最初の子コンテキストのプロパティファイルを定義することから始めましょう。
server.port=8081
server.servlet.context-path=/ctx1
spring.application.admin.enabled=false
spring.application.admin.jmx-name=org.springframework.boot:type=Ctx1Rest,name=Ctx1Application
アプリケーション名が競合しないように、ポートとコンテキストパス、およびJMX名を構成したことに注意してください。
次に、このコンテキストのメイン構成クラスを追加しましょう。
@Configuration
@ComponentScan("com.example.ctx1")
@EnableAutoConfiguration
public class Ctx1Config {
@Bean
public IHomeService homeService() {
return new GreetingService();
}
}
このクラスは、親からのものを上書きするhomeServiceBeanの新しい定義を提供します。
GreetingServiceクラスの定義を見てみましょう。
@Service
public class GreetingService implements IHomeService {
public String getGreeting() {
return "Greetings for the day";
}
}
最後に、homeServiceBeanを使用してユーザーにメッセージを表示するこのWebコンテキストのコントローラーを追加します。
@Controller
public class Ctx1Controller {
@Autowired
HomeService homeService;
@GetMapping("/home")
@ResponseBody
public String greeting() {
return homeService.getGreeting();
}
}
3.3. 兄弟コンテキスト
2番目のコンテキストでは、前のセクションのものと非常によく似たコントローラーと構成クラスを作成します。
今回は、homeService Beanを作成しません。これは、親コンテキストからアクセスするためです。
まず、このコンテキストのプロパティファイルを追加しましょう。
server.port=8082
server.servlet.context-path=/ctx2
spring.application.admin.enabled=false
spring.application.admin.jmx-name=org.springframework.boot:type=WebAdmin,name=SpringWebApplication
そして、兄弟アプリケーションの構成クラス:
@Configuration
@ComponentScan("com.example.ctx2")
@EnableAutoConfiguration
@PropertySource("classpath:ctx2.properties")
public class Ctx2Config {}
依存関係としてHomeServiceを持つコントローラーも追加しましょう。
@RestController
public class Ctx2Controller {
@Autowired
IHomeService homeService;
@GetMapping(value = "/greeting", produces = "application/json")
public String getGreeting() {
return homeService.getGreeting();
}
}
この場合、コントローラーは親コンテキストからhomeServiceBeanを取得する必要があります。
3.4. コンテキスト階層
これで、すべてをまとめて、SpringApplicationBuilder:を使用してコンテキスト階層を定義できます。
public class App {
public static void main(String[] args) {
new SpringApplicationBuilder()
.parent(ParentConfig.class).web(WebApplicationType.NONE)
.child(WebConfig.class).web(WebApplicationType.SERVLET)
.sibling(RestConfig.class).web(WebApplicationType.SERVLET)
.run(args);
}
}
最後に、Spring Bootアプリを実行すると、localhost:8081/ctx1/home とlocalhost:8082/ctx2/greeting.を使用して、それぞれのポートで両方のアプリケーションにアクセスできます。
4. 結論
SpringApplicationBuilder APIを使用して、最初にアプリケーションの2つのコンテキスト間に親子関係を作成しました。 次に、子コンテキストで親構成をオーバーライドする方法を説明しました。 最後に、親コンテキストの構成を他の子コンテキストと共有する方法を示すために、兄弟コンテキストを追加しました。
例のソースコードは利用可能なover on GitHubです。