#injection #di #spring #ioc #dependency-injection

springtime-di

Dependency injection framework based on automatic component discovery and runtime autowiring

8 releases (3 stable)

1.0.2 May 7, 2024
1.0.1 Nov 27, 2023
1.0.0 Apr 26, 2023
0.3.2 Apr 20, 2023
0.2.1 Apr 7, 2023

#317 in Asynchronous

Download history 4/week @ 2024-02-12 9/week @ 2024-02-19 17/week @ 2024-02-26 10/week @ 2024-03-04 8/week @ 2024-03-11 38/week @ 2024-03-18 36/week @ 2024-03-25 42/week @ 2024-04-01 5/week @ 2024-04-08 7/week @ 2024-04-22 147/week @ 2024-05-06

155 downloads per month
Used in 3 crates

MIT license

115KB
2.5K SLoC

Springtime Dependency Injection

crates.io version build status

A dependency injection crate inspired by the Spring Framework in Java.

The philosophy of Springtime is to provide the means of easy dependency injection without unnecessary manual configuration, e.g. without the need to explicitly create dependencies and storing them in containers. The core concept is the Component - something that can be created, injected, and managed by the framework. As much work as possible is placed on compile-time metadata creation and automatic component discovery, thus allowing users to focus on the usage of components, rather than their creation and management. With an accent placed on attributes, dependency configuration becomes declarative (what I want to accomplish) leaving the gritty details the framework itself (how to accomplish what was requested).

Features

  • Concrete and trait object injection
  • Automatic and manual registration support
  • Component filtering
  • Conditional component registration
  • Component priorities
  • Custom constructor functions
  • Per-field configurable initialization
  • Customizable instance scopes
  • Async + sync support (runtime agnostic)

Basic usage

Springtime is highly configurable, but the most basic usage example is quite simple and consists of using a few attributes to fully configure the dependency chain. For tutorial, advanced features, and patterns, please look at the examples, which form a step-by-step guide.

use springtime_di::factory::ComponentFactoryBuilder;
use springtime_di::instance_provider::{ComponentInstancePtr, TypedComponentInstanceProvider};
use springtime_di::{component_alias, injectable, Component};

// this is a trait we would like to use in our component
#[injectable]
trait TestTrait {
    fn foo(&self);
}

// this is a dependency which implements the above trait and also is an injectable component
#[derive(Component)]
struct TestDependency;

// we're telling the framework to provide TestDependency when asked for dyn TestTrait
#[component_alias]
impl TestTrait for TestDependency {
    fn foo(&self) {
        println!("Hello world!");
    }
}

// this is another component, but with a dependency
#[derive(Component)]
struct TestComponent {
    // the framework will know how to inject dyn TestTrait, when asked for TestComponent (Send + Sync are only needed
    // with the "threadsafe" feature)
    // more details are available in the documentation
    dependency: ComponentInstancePtr<dyn TestTrait + Send + Sync>,
    // alternatively, you can inject the concrete type
    // dependency: ComponentInstancePtr<TestDependency>,
}

impl TestComponent {
    fn call_foo(&self) {
        self.dependency.foo();
    }
}

// note: for the sake of simplicity, errors are unwrapped, rather than gracefully handled
fn main() {
    // components are created by a ComponentFactory
    // for convenience, ComponentFactoryBuilder can be used to create the factory with a reasonable
    // default configuration
    let mut component_factory = ComponentFactoryBuilder::new()
        .expect("error initializing ComponentFactoryBuilder")
        .build();

    let component = component_factory
        .primary_instance_typed::<TestComponent>()
        .expect("error creating TestComponent");

    // prints "Hello world!"
    component.call_foo();
}

Dependencies

~1.2–2MB
~39K SLoC