1. Overview
1.概述
It’s possible to create separate contexts and organize them in a hierarchy in Spring Boot.
在Spring Boot中,可以创建独立的上下文,并将它们组织成一个层次结构。
A context hierarchy can be defined in different ways in Spring Boot application. In this article, we’ll look at how we can create multiple contexts using the fluent builder API.
在Spring Boot应用程序中,可以通过不同的方式来定义上下文层次结构。在这篇文章中,我们将探讨如何使用流畅的构建器API创建多个上下文。
As we won’t go into details on how to set up a Spring Boot application, you might want to check out this article.
由于我们不会详细介绍如何设置Spring Boot应用程序,您可能想看看这篇文章。
2. Application Context Hierarchy
2.应用程序上下文层次结构
We can have multiple application contexts that share a parent-child relationship.
我们可以拥有多个共享父子关系的应用程序上下文。
A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Each child context can override configuration inherited from the parent context.
上下文层次结构允许多个子上下文共享位于父上下文中的Bean。每个子上下文都可以覆盖从父上下文继承的配置。
Furthermore, we can use contexts to prevent beans registered in one context from being accessible in another. This facilitates the creation of loosely coupled modules.
此外,我们可以使用上下文来防止在一个上下文中注册的Bean在另一个上下文中被访问。这有利于创建松散耦合的模块。
Here some points worth noting are that a context can have only one parent while a parent context can have multiple child contexts. Also, a child context can access beans in the parent context but not vice-versa.
这里值得注意的几点是,一个上下文只能有一个父级,而一个父级上下文可以有多个子级上下文。另外,一个子上下文可以访问父上下文中的Bean,反之则不行。
3. Using SpringApplicationBuilder API
3.使用SpringApplicationBuilder API
The SpringApplicationBuilder class provides a fluent API to create a parent-child relationship between contexts using parent(), child() and sibling() methods.
SpringApplicationBuilder类提供了一个流畅的API,以使用parent()、child()和sibling()方法创建上下文之间的父子关系。
To exemplify the context hierarchy, we’ll set up a non-web parent application context with 2 child web contexts.
为了说明上下文的层次结构,我们将设置一个非网络的父应用程序上下文和两个子网络上下文。
To demonstrate this, we’ll start two instances of embedded Tomcat each with its own web application context and both running in a single JVM.
为了证明这一点,我们将启动两个嵌入式Tomcat的实例,每个实例都有自己的Web应用上下文,并且都在一个JVM中运行。
3.1. Parent Context
3.1.母体背景
To begin, let’s create a service bean along with a bean definition class which reside in the parent package. We want this bean to return a greeting which is displayed to the client of our web application:
首先,让我们创建一个服务Bean和一个位于父包中的Bean定义类。我们希望这个Bean能够返回一个问候语,显示给我们的Web应用程序的客户端。
@Service
public class HomeService implements IHomeService {
public String getGreeting() {
return "Welcome User";
}
}
And the bean definition class:
还有Bean定义类。
@Configuration
@ComponentScan("com.baeldung.parent")
public class ServiceConfig {}
Next, we’ll create the configuration for the two child contexts.
接下来,我们将为两个子背景创建配置。
3.2. Child Context
3.2.儿童背景
Since all contexts are configured using the default configuration file, we need to provide separate configurations for properties which cannot be shared among contexts such as server ports.
由于所有的上下文都是使用默认的配置文件配置的,我们需要为那些不能在上下文之间共享的属性提供单独的配置,如服务器端口。
To prevent conflicting configurations being picked up by the auto-configuration, we’ll also keep the classes in separate packages.
为了防止冲突的配置被自动配置拾取,我们也将把这些类放在不同的包里。
Let’s start by defining a properties file for the first child context:
让我们首先为第一个子环境定义一个属性文件。
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
Note that we’ve configured the port and context path, as well as a JMX name so the application names don’t conflict.
注意,我们已经配置了端口和上下文路径,以及一个JMX名称,这样应用程序的名称就不会冲突。
Let’s now add the main configuration class for this context:
现在让我们为这个上下文添加主配置类。
@Configuration
@ComponentScan("com.baeldung.ctx1")
@EnableAutoConfiguration
public class Ctx1Config {
@Bean
public IHomeService homeService() {
return new GreetingService();
}
}
This class provides a new definition for the homeService bean that will overwrite the one from the parent.
这个类为homeService bean提供了一个新的定义,它将覆盖来自父类的定义。
Let’s see the definition of the GreetingService class:
让我们看看GreetingService类的定义。
@Service
public class GreetingService implements IHomeService {
public String getGreeting() {
return "Greetings for the day";
}
}
Finally, we’ll add a controller for this web context that use the homeService bean to display a message to the user:
最后,我们将为这个Web上下文添加一个控制器,使用homeService Bean来向用户显示一个消息。
@RestController
public class Ctx1Controller {
@Autowired
private HomeService homeService;
@GetMapping("/home")
public String greeting() {
return homeService.getGreeting();
}
}
3.3. Sibling Context
3.3.兄弟姐妹的背景
For our second context, we’ll create a controller and configuration class which are very similar to the ones in the previous section.
对于我们的第二个上下文,我们将创建一个控制器和配置类,它们与上一节中的非常相似。
This time, we won’t create a homeService bean – as we’ll access it from the parent context.
这一次,我们不会创建一个homeService bean – 因为我们将从父级上下文中访问它。
First, let’s add a properties file for this context:
首先,让我们为这个上下文添加一个属性文件。
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
And the configuration class for the sibling application:
以及同级别的应用程序的配置类。
@Configuration
@ComponentScan("com.baeldung.ctx2")
@EnableAutoConfiguration
@PropertySource("classpath:ctx2.properties")
public class Ctx2Config {}
Let’s also add a controller, which has HomeService as a dependency:
让我们也添加一个控制器,它将HomeService作为一个依赖项。
@RestController
public class Ctx2Controller {
@Autowired
private IHomeService homeService;
@GetMapping("/greeting")
public String getGreeting() {
return homeService.getGreeting();
}
}
In this case, our controller should get the homeService bean from the parent context.
在这种情况下,我们的控制器应该从父级上下文中获得homeService Bean。
3.4. Context Hierarchy
3.4.语境层次结构
Now we can put everything together and define the context hierarchy using SpringApplicationBuilder:
现在我们可以把所有东西放在一起,并使用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);
}
}
Finally, on running the Spring Boot App we can access both applications at their respective ports using localhost:8074/ctx1/home and localhost:8075/ctx2/greeting.
最后,在运行Spring Boot应用程序时,我们可以使用localhost:8074/ctx1/home和localhost:8075/ctx2/greeting.在各自的端口访问两个应用程序。
4. Conclusion
4.总结
Using the SpringApplicationBuilder API, we first created a parent-child relationship between two contexts of an application. Next, we covered how to override the parent configuration in the child context. Lastly, we added a sibling context to demonstrate how the configuration in the parent context can be shared with other child contexts.
使用SpringApplicationBuilder API,我们首先在一个应用程序的两个上下文之间创建了一个父子关系。接下来,我们介绍了如何在子上下文中覆盖父级配置。最后,我们添加了一个兄弟姐妹上下文,以演示如何将父上下文中的配置与其他子上下文共享。
The source code of the example is available over on GitHub.
该示例的源代码可在GitHub上获得,。