Implementation of a dependency injection library for Java 21. This is only a pastime, so it is neither complete nor tested. I also did not look up best practices, no guarantees are made, you know the drill.
Basic features and restrictions are:
- Create contexts with a specified package coverage
- Specify several packages. Components can depend on components from other packages
- Reuse of existing component contexts if same package coverage is requested again
- Fail early when context is inconsistent or contains cyclic dependencies
- Component registration via annotation
- Register classes as "Components" for injection via annotation
- Mark methods with a return type as Component sources to create instances from their classes
- Specify a name for components to support multiple alternative implementations of an interface or abstract class, as well as basic types like String and Integer
- Singleton scope for all components within one context
- Injection of other components
- Mark constructor/component source function parameters with the @ByName annotation for matching by component name
- No field injection
- Interfaces and abstract classes supported for injection or explicit instance loading
Mark your classes and functions with the annotation @Component, then use the class ContextBuilder to load your Java package and build instances of your classes.
A minimal example application to showcase the usage can be found in my other repository
The constructor is then used to instantiate it, any constructor parameters will be injected.
@Component
public class YourService {
private final Repository repository;
public YourService(Repository repository){
this.repository = repository;
}
// Business logic
}
The @BeanSource annotation can be used to mark classes as containing static methods that produce components. The @ByName annotation identifies beans by name in addition to their class when injecting.
@BeanSource
public class BeanSource {
@Component(name = "namedString")
public static String namedString() {
return "Some string that will be a component";
}
public static YourOtherService someClassInstance(
@ByName("namedString") String parameter
) {
return new YourOtherService(parameter);
}
}
// Create context once
ContextBuilder contextBuilder = ContextBuilder.getContextInstance("at.schrer.inject", "at.schrer.example", "at.schrer.util");
// Request instances
YourService service1 = contextBuilder.getComponent(YourService.class);
// YourOtherService will be identified by its name, so you can have several instances with different names in your context
YourOtherService service2 = contextBuilder.getComponent("serviceName", YourOtherService.class);
- The ContextBuilder, which can instantiate classes marked with the annotation @Component from a provided package.
- The ClassScanner, which is able to return a list of classes under a provided package name. The classes can also be filtered by annotations.
- An implementation of an acyclic graph. It is used in the ContextBuilder to build the dependency graph between all components.