Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-context spring-boot application: how to define standard spring-boot properties for each child context

There is good question about ability to add multiple tomcat connectors and bind them to separate controllers each.

The essense of Andy Wilkinson's good answer is here:

public static void main(String[] args) {
    SpringApplicationBuilder parentBuilder 
            = new SpringApplicationBuilder(ApplicationConfiguration.class);
    parentBuilder.child(ServiceOneConfiguration.class)
            .properties("server.port:8080").run(args);
    parentBuilder.child(ServiceTwoConfiguration.class)
            .properties("server.port:8081").run(args);      
}

I want to go on this futher and ask another question:

Is there a way to make each child application context to read some child specific application properties with support of all standard spring-boot's features, like profile-suffix file names etc.

One hypothetical way to achieve it:

Have three separate property files:

  • application.properties
  • child1.properties
  • child2.properties

And have ability to set one file for each context.

But what is important to me, that they must support all spring-boot magic. For example, if I activate new profile like passing command line argument --spring.profiles.active=dev, then automagically not only these three files should be loaded (one for each context), but another set of files (if they exist) also should be loaded automatically:

  • application-dev.properties
  • child1-dev.properties
  • child2-dev.properties

Of course, these files should be searched at standard spring-boot's supported paths in defined order etc.

Is it possible out if the box of maybe with some coding?

Another hypothetical way to achieve it

Have only one application.properties file (with support for profiles etc), but somehow to map prefixed properties to unprefixed properties of child contexts.

Example:

child1.server.port=8081
child1.foo=bar
child2.server.port=8082
child2.foo=baz

First child context should see these properties like if they were just:

server.port=8081
foo=bar

Second child context should see these properties like if they were just:

server.port=8082
foo=baz

So, standard spring-boot's autoconfigurations will work and correctly set tomcat's port etc.


I am not looking for specific approach (but if you ask me, I'm leaning towards second approach), but any working out-of-the-box or achievable with minimum conding apporach will suffice me.

like image 359
Ruslan Stelmachenko Avatar asked Jan 22 '19 12:01

Ruslan Stelmachenko


1 Answers

You can achieve your first suggestion using spring.config.name:

public static void main(String[] args) {
    SpringApplicationBuilder parentBuilder =
            new SpringApplicationBuilder(ParentApplication.class)
                    .web(WebApplicationType.NONE);
    parentBuilder.run(args);
    parentBuilder.child(ServiceOneConfiguration.class)
            .properties("spring.config.name=child1").run(args);
    parentBuilder.child(ServiceTwoConfiguration.class)
            .properties("spring.config.name=child2").run(args);
}

You can then use child1{-profile}.properties and child2{-profile}.properties to configure service one and service two respectively.

For example, with server.port=8081 in child1.properties and server.port=8082 in child2.properties, you should see output similar to the following when starting an app that's using auto-configuration in the two child services and has a dependency on spring-boot-starter-web:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2019-01-22 13:38:09.690  INFO 80968 --- [           main] com.example.parent.ParentApplication     : Starting ParentApplication on …
2019-01-22 13:38:09.692  INFO 80968 --- [           main] com.example.parent.ParentApplication     : No active profile set, falling back to default profiles: default
2019-01-22 13:38:09.842  INFO 80968 --- [           main] com.example.parent.ParentApplication     : Started ParentApplication in 0.371 seconds (JVM running for 0.644)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2019-01-22 13:38:10.046  INFO 80968 --- [           main] com.example.parent.ParentApplication     : No active profile set, falling back to default profiles: default
2019-01-22 13:38:10.584  INFO 80968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2019-01-22 13:38:10.604  INFO 80968 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-01-22 13:38:10.605  INFO 80968 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.14]
2019-01-22 13:38:10.613  INFO 80968 --- [           main] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/awilkinson/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2019-01-22 13:38:10.668  INFO 80968 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-01-22 13:38:10.668  INFO 80968 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 612 ms
2019-01-22 13:38:10.829  INFO 80968 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-01-22 13:38:10.981  INFO 80968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2019-01-22 13:38:10.981  INFO 80968 --- [           main] com.example.parent.ParentApplication     : Started ParentApplication in 0.955 seconds (JVM running for 1.784)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2019-01-22 13:38:11.003  INFO 80968 --- [           main] com.example.parent.ParentApplication     : No active profile set, falling back to default profiles: default
2019-01-22 13:38:11.093  INFO 80968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8082 (http)
2019-01-22 13:38:11.095  INFO 80968 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-01-22 13:38:11.096  INFO 80968 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.14]
2019-01-22 13:38:11.100  INFO 80968 --- [           main] o.a.c.c.C.[Tomcat-1].[localhost].[/]     : Initializing Spring embedded WebApplicationContext
2019-01-22 13:38:11.101  INFO 80968 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 97 ms
2019-01-22 13:38:11.135  INFO 80968 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-01-22 13:38:11.164  INFO 80968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8082 (http) with context path ''
2019-01-22 13:38:11.165  INFO 80968 --- [           main] com.example.parent.ParentApplication     : Started ParentApplication in 0.183 seconds (JVM running for 1.967)
like image 124
Andy Wilkinson Avatar answered Oct 17 '22 11:10

Andy Wilkinson