Home - microfox-framework/MicroFox GitHub Wiki
The core idea of this project is to establish communication between software layers without using Dependency Injection (DI) containers, instead relying on Functional Programming (FP) principles.
This approach fits well within microservice architectures that are often designed using Domain-Driven Design (DDD). In such architectures, each domain is implemented as an isolated and independent module. Since the number of business classes per domain is typically small, there is often no real need for a heavy DI framework. Hence, we prefer to replace DI containers with lightweight functional constructs.
While Dependency Injection as a design pattern remains valuable, many frameworks use DI containers primarily for:
- Object Lifecycle Management
- Dependency Resolution via Interfaces
Popular frameworks like Spring and Jakarta EE achieve this through CDI (Contexts and Dependency Injection) and IoC (Inversion of Control) containers.
In practice, most microservice-based projects:
- Define their components (beans) as Singletons
- Use interfaces to abstract their dependencies
If we choose not to use a DI container, the best alternatives are:
- Implementing business classes using the Singleton Design Pattern
- Making them Stateless, thus eliminating shared state across invocations
Since Java 8, it has been possible to pass methods as parameters using method references and lambda expressions—concepts similar to function pointers in languages like C/C++.
This allows for highly composable and decoupled design. A simple example:
class Scratch {
private static final Logger logger = LoggerFactory.getLogger(Scratch.class);
public static void main(String[] args) {
// Inject method using System.out
JLogger sysLogger = System.out::println;
count(sysLogger::info);
// Inject method using SLF4J
JLogger slfLogger = logger::info;
count(slfLogger::info);
}
public static void count(Consumer<String> consumer) {
for (int i = 0; i < 10; i++) {
consumer.accept("Count: " + i);
}
}
interface JLogger {
void info(String message);
}
}
This technique is very common in functional-first environments such as Dart (Flutter), and is straightforward to implement in modern Java as well.