12

I have 2 Main entry points in a single application.

The first main starts the server, maps the controllers and starts some worker threads. These workers receive messages from cloud queues.

In case of increased load, I want to be able to add additional workers to do my job. So I have a second Main entry point in my application which I want to be able to start without starting the default server in spring-boot (as a client application) so as to avoid port conflict (and obviously which will lead to failure).

How do I achieve this?

amitection
  • 2,696
  • 8
  • 25
  • 46
  • 1
    It'd be better to run this in Spring Cloud and let it manage the horizontal scaling for you. https://spring.io/guides/gs/spring-cloud-and-lattice/ – duffymo Aug 29 '16 at 11:51
  • Other clouds like aws (beanstalk) too can manage horizontal scaling. – amitection Aug 29 '16 at 12:07
  • 1
    Sure. My point is that you should let them do it; don't try to manage this yourself. Be lazy - use what's available. – duffymo Aug 29 '16 at 12:08

1 Answers1

24

Launching from the command line with server and client profiles

To use the same jar and same entry point with 2 different profiles, you should simply provide the Spring profile at runtime, to have distinct application-${profile}.properties loaded (and potentially Conditional Java config triggered).

Define 2 spring profiles (client and server):

  • Each will have its own application-${profile}.properties
  • The client's properties will disable the web container

Have a single SpringBootApp and entry point:

@SpringBootApplication
public class SpringBootApp {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(SpringBootApp.class)
            .run(args);
    }
}

Make this class your main-class.

src/main/resources/application-server.properties:

spring.application.name=server
server.port=8080

src/main/resources/application-client.properties:

spring.application.name=client
spring.main.web-environment=false

Launch both profiles from the command line:

$ java -jar -Dspring.profiles.active=server YourApp.jar
$ java -jar -Dspring.profiles.active=client YourApp.jar

You may have @Configuration classes triggered conditionally based on the active profile too:

@Configuration
@Profile("client")
public class ClientConfig {
    //...
}

Launching from the IDE with server and client profiles

Launchers:

@SpringBootApplication
public class SpringBootApp {
}

public class LauncherServer {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(SpringBootApp.class)
            .profiles("server")
            .run(args);
    }
}

public class ClientLauncher {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(SpringBootApp.class)
            .profiles("client")
            .web(false)
            .run(args);
    }
}

You may specify additional configuration classes (specific to client or server):

new SpringApplicationBuilder()
    .sources(SpringBootApp.class, ClientSpecificConfiguration.class)
    .profiles("client")
    .web(false)
    .run(args);

src/main/resources/application-server.properties:

spring.application.name=server
server.port=8080

src/main/resources/application-client.properties:

spring.application.name=client
#server.port= in my example, the client is not a webapp

Note, you may also have 2 SpringBootApp (ClientSpringBootApp, ServerSpringBootApp), each with its own main, it's a similar setup which allow you to configure different AutoConfiguration or ComponentScan:

@SpringBootApplication
@ComponentScan("...")
public class ServerSpringBootApp {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(ServerSpringBootApp.class)
            .profiles("server")
            .run(args);
    }
}

//Example of a difference between client and server
@SpringBootApplication(exclude = SecurityAutoConfiguration.class) 
@ComponentScan("...")
public class ClientSpringBootApp {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(ClientSpringBootApp.class)
            .profiles("client")
            .web(false)
            .run(args);
    }
}
alexbt
  • 16,415
  • 6
  • 78
  • 87
  • How do I run these two different apps "Server" and "Client" from the terminal? Do I need to have two different builds or can I do it simply using "-cp" ? – amitection Aug 30 '16 at 04:57
  • I went through [this](http://stackoverflow.com/questions/19882752/how-to-configure-pom-xml-to-run-2-java-mains-in-1-maven-project) but it doesn't seem to work with spring-boot. – amitection Aug 30 '16 at 11:00
  • 1
    Genius! Exactly what I was looking for. Thanks a ton! – amitection Aug 30 '16 at 12:02