Java
Microservice basics
Write a small HTTP-based microservice skeleton.
The service registry pattern
The microservice foundation starts with a Registry that holds @Service-marked classes by name. The Registry keeps a Map; put(name, instance) adds and get(name) finds. This is the core of dependency injection.
In this project you will add a HelloService instance to the Registry under the name "hello". In the next lesson this registry is used in the combine step.
The native bridge
NativeBridge is a class that builds the C function name of a native call. Its describe(cls, method, sig) method returns "Java_" + cls + "_" + method + sig. This models the JNI naming; no real call is made.
This model is used to decide which class and method to bind to native code. In the combine step NativeBridge works together with the service registry.
Exercise Write the Registry and NativeBridge classes
Add a class Registry to the structure above with a java.util.Map<String, Object> field and void put(String name, Object instance) and Object get(String name) methods. Add a class NativeBridge with a static String describe(String cls, String method, String sig) method that returns "Java_" + cls + "_" + method + sig. In main create Registry registry = new Registry();, call registry.put("hello", new HelloService()); and print System.out.println(NativeBridge.describe("HelloService", "greet", "()Ljava/lang/String;"));.
Show example solution
@interface Service {}
@Service
class HelloService {
String greet() { return "hello"; }
}
interface Subscriber {
void onNext(String item);
}
class SimplePublisher {
java.util.List<Subscriber> subs = new java.util.ArrayList<>();
void subscribe(Subscriber s) { subs.add(s); }
void publish(String item) {
for (Subscriber s : subs) s.onNext(item);
}
}
class TimedPublisher {
SimplePublisher delegate;
TimedPublisher(SimplePublisher delegate) {
this.delegate = delegate;
}
void publish(String item) {
long start = System.nanoTime();
delegate.publish(item);
long elapsed = System.nanoTime() - start;
System.out.println("elapsed measured: " + (elapsed >= 0));
}
}
class Registry {
java.util.Map<String, Object> services = new java.util.HashMap<>();
void put(String name, Object instance) { services.put(name, instance); }
Object get(String name) { return services.get(name); }
}
class NativeBridge {
static String describe(String cls, String method, String sig) {
return "Java_" + cls + "_" + method + sig;
}
}
public class Main {
public static void main(String[] args) {
Registry registry = new Registry();
registry.put("hello", new HelloService());
System.out.println(NativeBridge.describe("HelloService", "greet", "()Ljava/lang/String;"));
}
}
Test yourself
-
Complete the registry put call
registry.put(____, new HelloService());
Show answer
registry.put("hello", new HelloService());
-
What does the Registry pattern provide?
- Class compilation
- Name-to-instance mapping
- Thread pool
- File reading
Show answer
Name-to-instance mapping — The Registry holds a name-to-instance mapping.
-
Match the microservice elements
- Registry
- Service registry
- @Service
- Service marker
- NativeBridge
- Native call
- put
- Add entry
Next lesson: Putting it together