This project provides a lightweight IoC (Inversion of Control) container implementation, inspired by the Spring Framework. The container manages the lifecycle of components, handles dependencies, and allows for the registration and retrieval of beans.
We use Semantic Versioning 2.0.0 to manage our releases.
- Lightweight: Designed to be minimalistic and easy to use, without the overhead of more complex frameworks.
- Component Scanning: Automatically scans packages to discover components and beans.
- Dependency Injection: Supports constructor and method injection.
- Flexible Lifecycle Management: Handles the initialization and destruction of beans, including methods annotated with
@PostConstruct
. The lifecycle is flexible due to event-driven mechanisms that allow developers to hook into different stages of the container's lifecycle. - Qualifier Support: Allows multiple implementations of the same interface with qualifiers.
- Circular Dependency Detection: Detects and prevents circular dependencies.
To use the lioc library, include it in your project as a dependency.
repositories {
maven("https://repo.jyraf.com/repository/maven-snapshots/")
}
dependencies {
implementation("dev.ckateptb:lioc:<version>")
}
To use the container, instantiate it and call the appropriate methods to register and retrieve beans.
Container<MyApplication> container = new Container<>();
container.scan(myAppInstance, "com.example.mypackage", packetNameFilter); // for scan class-path
container.scan(myAppInstance, packetNameFilter); // or for scan source-jar
container.initialize(); // initialize the container by creating instances of all bins and components
You can register beans manually or let the container scan for them. The container supports both explicit and silent registration. Using registerSilent
will not trigger lifecycle events, unlike the standard register
method.
container.register(myOwner, new MyBean());
container.register(myOwner, new MyBean(), "customQualifier");
container.registerSilent(myOwner, new MyBean());
container.registerSilent(myOwner, new MyBean(), "customQualifier");
Beans can be retrieved by their class type and optional qualifier.
Optional<MyBean> myBean = container.findBean(MyBean.class);
Optional<MyBean> myBeanWithQualifier = container.findBean(MyBean.class, "customQualifier");
The container's lifecycle is flexible and can be extended through event-driven mechanisms. Custom handlers can be added to hook into various stages of the lifecycle, providing a flexible way to manage components and their dependencies.
- ComponentRegisterHandler: Handles events when a component is registered.
- ContainerInitializeHandler: Handles events after the container is initialized.
You can add handlers to respond to specific lifecycle events:
container.addComponentRegisterHandler((bean, qualifier, owner) -> {
// Custom logic when a component is registered
});
container.addContainerInitializedHandler((container, components) -> {
// Custom logic after the container is initialized
});
public class MyApplication {
public static void main(String[] args) {
Container<MyApplication> container = new Container<>();
MyApplication app = new MyApplication();
container.scan(app);
container.initialize();
MyBean myBean = container.findBean(MyBean.class).orElseThrow();
myBean.doSomething();
}
}
In this IoC container, you can define components similarly to how you would in a Spring application. Here's an example that demonstrates creating a component, a bean method, and dependency injection.
To define a component, use the @Component
annotation. This annotation marks the class as a component, which the container will manage.
@Component
public class MyComponent {
private final MyDependency myDependency;
// Constructor injection
@Autowired
public MyComponent(MyDependency myDependency) {
this.myDependency = myDependency;
}
// Bean method
@Bean
public MyService myService() {
return new MyService();
}
// Call method after constructor
@PostConstruct
public void doSomething() {
myDependency.performTask();
myService().executeService();
}
}
Dependencies can also be components/beans or simple classes managed by the container.
@Component
public class MyDependency {
public void performTask() {
System.out.println("Task performed by MyDependency.");
}
}
The @Bean
annotation can be used on a method within a component to indicate that the method returns a bean that should be managed by the container.
public class MyService {
public void executeService() {
System.out.println("Service executed by MyService.");
}
}
In this example, MyComponent
is a component managed by the container. It has a dependency on MyDependency
, which is injected via the constructor. The myService
method is annotated with @Bean
, indicating that it produces a bean of type MyService
. When the container initializes, it automatically creates and wires these components, allowing you to use them in your application
This project is licensed under the GPL-3.0 license.
Contributions are welcome! Feel free to open an issue or submit a pull request.