Skip to content

Commit 76df59d

Browse files
committed
Multi service single jvm post
1 parent 73e655e commit 76df59d

File tree

5 files changed

+134
-12
lines changed

5 files changed

+134
-12
lines changed

stubbornjava-examples/src/main/java/com/stubbornjava/examples/undertow/MicroMonolith.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.stubbornjava.examples.undertow;
22

33
import com.stubbornjava.common.undertow.Exchange;
4+
import com.stubbornjava.common.undertow.handlers.Middleware;
45
import com.stubbornjava.examples.undertow.contenttypes.ContentTypesServer;
56
import com.stubbornjava.examples.undertow.rest.RestServer;
67
import com.stubbornjava.examples.undertow.routing.ConstantStringHandler;
@@ -15,35 +16,35 @@ public static void main(String[] args) {
1516

1617
// {{start:restServer}}
1718
Undertow.builder()
18-
.addHttpListener(8080, "0.0.0.0", RestServer.ROOT)
19+
.addHttpListener(8080, "0.0.0.0", Middleware.common(RestServer.ROOT))
1920
.build()
2021
.start();
2122
// {{end:restServer}}
2223

2324
// {{start:contentTypesServer}}
2425
Undertow.builder()
25-
.addHttpListener(8081, "0.0.0.0", ContentTypesServer.ROUTES)
26+
.addHttpListener(8081, "0.0.0.0", Middleware.common(ContentTypesServer.ROUTES))
2627
.build()
2728
.start();
2829
// {{end:contentTypesServer}}
2930

30-
// {{start:multiPortServer}}
31-
Undertow.builder()
32-
.addHttpListener(8082, "0.0.0.0", RestServer.ROOT)
33-
.addHttpListener(8083, "0.0.0.0", ContentTypesServer.ROUTES)
34-
.build()
35-
.start();
36-
// {{end:multiPortServer}}
37-
3831
// {{start:combinedServer}}
3932
RoutingHandler combinedHanlder = new RoutingHandler().addAll(RestServer.ROUTES)
4033
.addAll(ContentTypesServer.ROUTES);
4134
Undertow.builder()
42-
.addHttpListener(8084, "0.0.0.0", combinedHanlder)
35+
.addHttpListener(8082, "0.0.0.0", Middleware.common(combinedHanlder))
4336
.build()
4437
.start();
4538
// {{end:combinedServer}}
4639

40+
// {{start:multiPortServer}}
41+
Undertow.builder()
42+
.addHttpListener(8083, "0.0.0.0", Middleware.common(RestServer.ROOT))
43+
.addHttpListener(8084, "0.0.0.0", Middleware.common(ContentTypesServer.ROUTES))
44+
.build()
45+
.start();
46+
// {{end:multiPortServer}}
47+
4748
// {{start:microserviceService}}
4849
Undertow.builder()
4950
.addHttpListener(8085, "0.0.0.0", exchange -> {

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/PostData.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,21 @@ public class PostData {
616616
))
617617
.build()
618618
);
619+
posts.add(PostRaw.builder()
620+
.postId(897667693920523259L)
621+
.title("Sharing routes and running multiple Java services in a single JVM with Undertow")
622+
.metaDesc("Build out microservice ready codebases but deploy as a monolith. Don't ride the hype train.")
623+
.dateCreated(LocalDateTime.parse("2017-09-04T01:15:30"))
624+
.dateUpdated(LocalDateTime.parse("2017-09-04T01:15:30"))
625+
.javaLibs(Lists.newArrayList(JavaLib.Undertow))
626+
.tags(Lists.newArrayList(Tags.Microservice, Tags.Monolith))
627+
.gitFileReferences(Lists.newArrayList(
628+
FileReference.stubbornJava(
629+
"services",
630+
"stubbornjava-examples/src/main/java/com/stubbornjava/examples/undertow/MicroMonolith.java")
631+
))
632+
.build()
633+
);
619634
}
620635

621636
public static List<PostRaw> getPosts() {

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/Tags.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class Tags {
2222
public static final Tag Webpack = addTag(new Tag(876957148741446344L, "Webpack"));
2323
public static final Tag NPM = addTag(new Tag(876957148739332593L, "NPM"));
2424
public static final Tag SEO = addTag(new Tag(880770018813220697L, "SEO"));
25+
public static final Tag Microservice = addTag(new Tag(897667693917183622L, "Microservice"));
26+
public static final Tag Monolith = addTag(new Tag(897667693920667427L, "Monolith"));
2527

2628
private static Tag addTag(Tag tag) {
2729
TAGS.add(tag);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<div class="anchored-md">
2+
{{#assign "markdown"}}
3+
Microservices has become an industry standard term and everyone is jumping aboard the hype train. There are definitely pros and cons in both building and maintaining microservices, however, they will not be discussed in this article, just remember [you are not Google](https://blog.bradfieldcs.com/you-are-not-google-84912cf44afb). We are going to show some options for sharing endpoints across services as well as run multiple services in a single JVM.
4+
5+
## Services
6+
Since we are talking about code reuse, let's grab our `RouteHandler`'s from two previous examples to demonstrate. We will be using our [lightweight REST server example](/posts/lightweight-embedded-java-rest-server-without-a-framework#routing-server) as well as the simple [content types example](/posts/handling-content-types-with-undertow#content-type-routes). To start we are going to run each of them as their own stand alone service on their own port.
7+
8+
{{> templates/src/widgets/code/code-snippet file=services section=services.sections.restServer}}
9+
<pre class="line-numbers"><code class="language-text">curl -X POST "localhost:8080/users" -d '
10+
{
11+
"email": "user1@test.com",
12+
"roles": ["USER"]
13+
}
14+
';
15+
{
16+
"email" : "user1@test.com",
17+
"roles" : [ "USER" ],
18+
"dateCreated" : "2017-09-04"
19+
}
20+
21+
curl -X GET "localhost:8080/users/user1@test.com"
22+
{
23+
"email" : "user1@test.com",
24+
"roles" : [ "USER" ],
25+
"dateCreated" : "2017-09-04"
26+
}</code></pre>
27+
28+
{{> templates/src/widgets/code/code-snippet file=services section=services.sections.contentTypesServer}}
29+
<pre class="line-numbers"><code class="language-text">curl localhost:8081/helloWorldText
30+
Hello World</code></pre>
31+
Everything looks good we are in business.
32+
33+
## Combining RoutingHandlers
34+
A simple use case for shared routes would be ping / healthchecks / server status that all of your services might share. We don't have one prepared so use your imagination with our existing services. With `RoutingHandler.addAll` we can combine both `RoutingHandler`'s into a single `RoutingHandler` and have a server listen to all of the routes on a single port. This allows us to combine common code across routing handlers or even run multiple micro services together under a single port (see next section for some reasons why you might want to do this).
35+
36+
{{> templates/src/widgets/code/code-snippet file=services section=services.sections.combinedServer}}
37+
<pre class="line-numbers"><code class="language-text">curl -X POST "localhost:8082/users" -d '
38+
{
39+
"email": "user1@test.com",
40+
"roles": ["USER"]
41+
}
42+
';
43+
{
44+
"email" : "user1@test.com",
45+
"roles" : [ "USER" ],
46+
"dateCreated" : "2017-09-04"
47+
}
48+
49+
curl -X GET "localhost:8082/users/user1@test.com"
50+
{
51+
"email" : "user1@test.com",
52+
"roles" : [ "USER" ],
53+
"dateCreated" : "2017-09-04"
54+
}</code></pre>
55+
<pre class="line-numbers"><code class="language-text">curl localhost:8082/helloWorldText
56+
Hello World</code></pre>
57+
Once again everything is working but under a single port this time.
58+
59+
## One Server Listening on Multiple Ports
60+
Testing microservices, especially ones that depend on other services to be up can be quite the pain. You either need to run N services in your IDE / command line or possibly set up something like docker so it is easy to reproduce. With each of these sometimes you need to remember which order to start each service in, yikes lots of fun. If all of our services are Java based and use the same dependencies we have another option. We already showed that the services could be combined into a single `RoutingHandler`. Maybe this doesn't meet your needs and each service is split by port and expects everything to work that way. Undertow has you covered, we can run multiple ports in a single undertow instance.
61+
62+
Note: If you have proper loose coupling both of the servers shouldn't be accessible from the same maven / gradle project so what do we do? Just make a new module that includes both server modules. This is not ideal and not necessarily recommended for prod since there could be some dependency issues. However if the dependencies line up across services (not such a bad thing to enforce especially on smaller teams / code bases) we can make such a shortcut. Whether you run this way in prod to reduce OPS work or only run this mode in development to save time is up to you. If you have a low traffic app running them together might make perfect sense. You would essentially have microservice ready code which can easily be split out into its own service when needed but for now it just shares the same CI pipeline, deploy script, and servers.
63+
64+
{{> templates/src/widgets/code/code-snippet file=services section=services.sections.multiPortServer}}
65+
<pre class="line-numbers"><code class="language-text">curl -X POST "localhost:8083/users" -d '
66+
{
67+
"email": "user1@test.com",
68+
"roles": ["USER"]
69+
}
70+
';
71+
{
72+
"email" : "user1@test.com",
73+
"roles" : [ "USER" ],
74+
"dateCreated" : "2017-09-04"
75+
}
76+
77+
curl -X GET "localhost:8083/users/user1@test.com"
78+
{
79+
"email" : "user1@test.com",
80+
"roles" : [ "USER" ],
81+
"dateCreated" : "2017-09-04"
82+
}</code></pre>
83+
<pre class="line-numbers"><code class="language-text">curl localhost:8084/helloWorldText
84+
Hello World</code></pre>
85+
Surprise, its all working under a single Undertow instance but listening on multiple ports.
86+
87+
88+
## MicroserviceService
89+
Let's take it one step too far just for fun. What if our service itself spun up new services inside the same JVM listening on new ports. Totally useless? probably, possible? Totally!
90+
91+
{{> templates/src/widgets/code/code-snippet file=services section=services.sections.microserviceService}}
92+
<pre class="line-numbers"><code class="language-text">curl localhost:9000
93+
curl: (7) Failed to connect to localhost port 9000: Connection refused</code></pre>
94+
<pre class="line-numbers"><code class="language-text">curl localhost:8085/?port=9000
95+
server with port 9000 created</code></pre>
96+
<pre class="line-numbers"><code class="language-text">curl localhost:9000
97+
web server with port 9000</code></pre>
98+
99+
### Bonus
100+
All of the above examples are inside of a single main method and all run together in the same JVM. Click any of the github links to view the source.
101+
102+
{{/assign}}
103+
{{md markdown}}
104+
</div>

stubbornjava-webapp/ui/src/widgets/social/twitter/summary-card.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
<meta name="twitter:site" content="@StubbornJava" />
33
<meta name="twitter:title" content="{{title}}" />
44
<meta name="twitter:description" content="{{desc}}" />
5-
{{!-- <meta name="twitter:image" content="https://pbs.twimg.com/profile_images/831134625296740352/Bs3vAfX3.jpg" /> --}}
5+
<meta name="twitter:image" content="/images/PenguinHQ.png" />

0 commit comments

Comments
 (0)