dart_ddi 0.6.0 copy "dart_ddi: ^0.6.0" to clipboard
dart_ddi: ^0.6.0 copied to clipboard

A Dependency Injection package, with Qualifier, Decorators, Interceptors, Events and more. Inspired by Java CDI and get_it.

Dart Dependency Injection (DDI) Library #

pub package CI Last Commits Issues Pull Requests Code size License

Overview #

The Dart Dependency Injection (DDI) library is a robust and flexible dependency injection mechanism inspired by the Contexts and Dependency Injection (CDI) framework in Java and by Get_It dart package. DDI facilitates the management of object instances and their lifecycles by introducing different scopes and customization options. This documentation aims to provide an in-depth understanding of DDI's core concepts, usage, and features.

🚀 Contribute to the DDI by sharing your ideas, feedback, or practical examples.

Summary

  1. Getting Started
  2. Core Concepts
    1. Singleton
    2. Application
    3. Session
    4. Dependent
    5. Object
    6. Common Considerations
  3. Qualifiers
    1. How Qualifiers Work
    2. Use Cases for Qualifiers
    3. Considerations
  4. Extra Customization
    1. PostConstruct
    2. Decorators
    3. Interceptor
    4. RegisterIf
    5. Destroyable
  5. Modules
    1. Adding a Class
    2. Adding Multiple Class
  6. Mixins
    1. Post Construct
    2. Pre Destroy
    3. Pre Dispose
    4. DDIModule Mixin
    5. DDIInject and DDIInjectAsync Mixins
    6. DDIEventSender and DDIStreamSender Mixins
  7. Events
    1. Creating and Managing Events
    2. Subscribing an Event
    3. Unsubscribing an Event
    4. Firing an Event
    5. Events Considerations
    6. Use Cases
  8. Stream
    1. Subscription
    2. Closing Stream
    3. Firing Events
    4. Retrieving Stream
  9. API Reference
    1. registerSingleton
    2. registerApplication
    3. registerDependent
    4. registerSession
    5. registerObject
    6. get
    7. getAsync
    8. getByType
    9. call
    10. destroy
    11. destroyByType
    12. dispose
    13. disposeByType
    14. addDecorator
    15. addInterceptor
    16. refreshObject

Getting Started #

To incorporate DDI into your Dart project, you must implement the DDI abstract class. The default implementation, can be accessed through the instance getter.

// Instantiate DDI
DDI ddi = DDI.instance;

// Register a singleton instance
ddi.registerSingleton<MyService>(MyService.new);

// Retrieve the singleton instance
MyService myService = ddi.get<MyService>();

// Register an application-scoped instance
ddi.registerApplication<MyAppService>(MyAppService.new);

// Retrieve the application-scoped instance
MyAppService appService = ddi.get<MyAppService>();

// ... (similar usage for other scopes)

Core Concepts #

Scopes #

The Dart Dependency Injection (DDI) Library supports various scopes for efficient management of object instances. Each scope determines how instances are created, reused, and destroyed throughout the application lifecycle. Below are detailed characteristics of each scope, along with recommendations, use cases, and considerations for potential issues.

Singleton #

Description: This scope creates a single instance during registration and reuses it in all subsequent requests.

Recommendation: Suitable for objects that need to be globally shared across the application, maintaining a single instance.

Use Case: Sharing a configuration manager, a logging service, or a global state manager.

Application #

Description: Generates an instance when first used and reuses it for all subsequent requests during the application's execution.

Recommendation: Indicated for objects that need to be created only once per application and shared across different parts of the code.

Use Case: Managing application-level resources, such as a network client or a global configuration.

Session #

Description: Ties an instance to a specific session, persisting throughout the session's lifespan.

Recommendation: Suitable for objects that need to be retained while a session is active, such as user-specific data or state.

Use Case: Managing user authentication state or caching user-specific preferences.

Dependent #

Description: Produces a new instance every time it is requested, ensuring independence and uniqueness.

Recommendation: Useful for objects that should remain independent and different in each context or request.

Use Case: Creating instances of transient objects like data repositories or request handlers.

Object #

Description: Registers an Object in the Object Scope, ensuring it is created once and shared throughout the entire application, functioning similarly to a Singleton.

Recommendation: Suitable for objects that are stateless or have shared state across the entire application.

Use Case: Application or device properties, like platform or dark mode settings, where the object's state needs to be consistent across the entire application.

Common Considerations: #

Single Registration: Ensure that the instance to be registered is unique for a specific type or use qualifiers to enable the registration of multiple instances of the same type.

Memory Management: Be aware of memory implications for long-lived objects, especially in the Singleton and Application scopes.

Nested Instances: Avoid unintentional coupling by carefully managing instances within larger-scoped objects.

const and Modifiers: Take into account the impact of const and other class modifiers on the behavior of instances within different scopes.

Qualifiers #

Qualifiers play a crucial role in the DDI Library by differentiating between instances of the same type, enabling to uniquely identify and retrieve specific instances within a given scope. In scenarios where multiple instances coexist within a single scope, qualifiers serve as optional labels or identifiers associated with the registration and retrieval of instances, ensuring precision in managing dependencies.

How Qualifiers Work #

When registering an instance, can provide a qualifier as part of the registration process. This qualifier acts as metadata associated with the instance and can later be used during retrieval to specify which instance is needed.

Example Registration with Qualifier

ddi.registerSingleton<MyService>(MyService.new, qualifier: "specialInstance");

Retrieval with Qualifiers #

During retrieval, if multiple instances of the same type exist, can use the associated qualifier to specify the desired instance. But remember, if you register using qualifier, should retrieve with qualifier.

Example Retrieval with Qualifier

MyService specialInstance = ddi.get<MyService>(qualifier: "specialInstance");

Use Cases for Qualifiers #

Configuration Variations

When there are multiple configurations for a service, such as different API endpoints or connection settings.

ddi.registerSingleton<ApiService>(() => ApiService("endpointA"), qualifier: "endpointA");
ddi.registerSingleton<ApiService>(() => ApiService("endpointB"), qualifier: "endpointB");

Feature Flags

When different instances are required based on feature flags or runtime conditions.

ddi.registerSingleton<FeatureService>(() => FeatureService(enabled: true), qualifier: "enabled");
ddi.registerSingleton<FeatureService>(() => FeatureService(enabled: false), qualifier: "disabled");

Platform-Specific Implementations

In scenarios where platform-specific implementations are required, such as different services for Android and iOS, qualifiers can be employed to distinguish between the platform-specific instances.

ddi.registerSingleton<PlatformService>(AndroidService.new, qualifier: "android");
ddi.registerSingleton<PlatformService>(iOSService.new, qualifier: "ios");

Considerations #

Consistent Usage: Maintain consistent usage of qualifiers throughout the codebase to ensure clarity and avoid confusion.

Avoid Overuse: While qualifiers offer powerful customization, avoid overusing them to keep the codebase clean and maintainable.

Type Identifiers: Qualifiers are often implemented using string-based identifiers, which may introduce issues such as typos or potential naming conflicts. To mitigate these concerns, it is highly recommended to utilize enums or constants.

Extra Customization #

The DDI Library provides features for customizing the lifecycle of registered instances. These features include postConstruct, decorators, interceptor, registerIf and destroyable.

PostConstruct #

The postConstruct callback allows to perform additional setup or initialization after an instance is created. This is particularly useful for executing logic that should run once the instance is ready for use.

Example Usage:

ddi.registerSingleton<MyService>(
  MyService.new,
  postConstruct: () {
    // Additional setup logic after MyService instance creation.
    print("MyService instance is ready!");
  },
);

Decorators #

Decorators provide a way to modify or enhance the behavior of an instance before it is returned. Each decorator is a function that takes the existing instance and returns a modified instance. Multiple decorators can be applied, and they are executed in the order they are specified during registration.

Example Usage:


class ModifiedMyService extends MyService {
  ModifiedMyService(MyService instance) {
    super.value = 'new value';
  }
}

ddi.registerSingleton<MyService>(
  MyService.new,
  decorators: [
    (existingInstance) => ModifiedMyService(existingInstance),
    // Additional decorators can be added as needed.
  ],
);

Interceptor #

The Interceptor is a powerful mechanism that provides fine-grained control over the instantiation, retrieval, destruction, and disposal of instances managed by the DDI Library. By creating a custom class that extends DDIInterceptor, you can inject custom logic at various stages of the instance's lifecycle.

Interceptor Methods #

aroundConstruct #

  • Invoked during the instance creation process.
  • Customize or replace the instance creation logic by returning a modified instance.

aroundGet #

  • Invoked when retrieving an instance.
  • Customize the behavior of the retrieved instance before it is returned.
  • If you change any value, the next time you get this instance, it will be applied again. Be aware that this can lead to unexpected behavior.

aroundDestroy #

  • Invoked when an instance is being destroyed.
  • Allows customization of the instance destruction process.

aroundDispose #

  • Invoked during the disposal of an instance.
  • Provides an opportunity for customization before releasing resources or performing cleanup.

Example Usage

class CustomInterceptor<BeanT> extends DDIInterceptor<BeanT> {
  @override
  BeanT aroundConstruct(BeanT instance) {
    // Logic to customize or replace instance creation.
    return CustomizedInstance();
  }

  @override
  BeanT aroundGet(BeanT instance) {
    // Logic to customize the behavior of the retrieved instance.
    return ModifiedInstance(instance);
  }

  @override
  void aroundDestroy(BeanT instance) {
    // Logic to perform cleanup during instance destruction.
    // This method is optional and can be overridden as needed.
  }

  @override
  void aroundDispose(BeanT instance) {
    // Logic to release resources or perform custom cleanup during instance disposal.
    // This method is optional and can be overridden as needed.
  }
}

RegisterIf #

The registerIf parameter is a boolean function that determines whether an instance should be registered. It provides conditional registration based on a specified condition. This is particularly useful for ensuring that only a single instance is registered, preventing issues with duplicated instances.

Example Usage:

ddi.registerSingleton<MyService>(
  MyServiceAndroid.new,
  registerIf: () {
    return Platform.isAndroid && MyUserService.isAdmin();
  },
);
ddi.registerSingleton<MyService>(
  MyServiceIos.new,
  registerIf: () {
    return Platform.isIOS && MyUserService.isAdmin();
  },
);
ddi.registerSingleton<MyService>(
  MyServiceDefault.new,
  registerIf: () {
    return !MyUserService.isAdmin();
  },
);

Destroyable #

The destroyable parameter, introduced in various registration methods, is optional and can be set to false if you want to make the registered instance indestructible. When set to false, the instance cannot be removed using the destroy or destroyByType methods, providing control over the lifecycle and preventing accidental removal.

Example Usage:

// Register an Application instance that is indestructible
ddi.registerApplication<MyService>(
  MyService.new,
  destroyable: false,
);

Modules #

Modules offer a convenient way to modularize and organize dependency injection configuration in your application. Through the use of the addChildModules and addChildrenModules methods, you can add and configure specific modules, grouping related dependencies and facilitating management of your dependency injection container.

When you execute dispose or destroy for a module, they will be executed for all its children.

Adding a Class #

To add a single class to a module to your dependency injection container, you can use the addChildModules method.

  • child: This refers to the type or qualifier of the subclasses that will be part of the module. Note that these are not instances, but rather types or qualifiers.
  • qualifier (optional): This parameter refers to the main class type of the module. It is optional and is used as a qualifier if needed.
// Adding a single module with a possible specific qualifier.
ddi.addChildModules<MyModule>(
  child: MySubmoduleType, 
  qualifier: 'MyModule',
);

Adding Multiple Class #

To add multiple class to a module at once, you can utilize the addChildrenModules method.

// Adding multiple modules at once.
ddi.addChildrenModules<MyModule>(
  child: [MySubmoduleType1, MySubmoduleType2], 
  qualifier: 'MyModule',
);

With these methods, you can modularize your dependency injection configuration, which can be especially useful in larger applications with complex instance management requirements.

Regsiter With Children Parameter #

The children parameter is designed to receive types or qualifiers. This parameter allows you to register multiple classes under a single parent module, enhancing the organization and management of your dependency injection configuration.

// Adding multiple modules at once.
ddi.registerApplication<ParentModule>(
  () => ParentModule(),
  children: [
    ChildModule,
    OtherModule,
    'ChildModuleQualifier',
    'OtherModuleQualifier'
  ],
);

Mixins #

Post Construct Mixin #

The PostConstruct mixin has been added to provide the ability to execute specific rules after the construction of an instance of the class using it. Its primary purpose is to offer an extension point for additional logic that needs to be executed immediately after an object is created.

By including the PostConstruct mixin in a class and implementing the onPostConstruct() method, you can ensure that this custom logic is automatically executed right after the instantiation of the class.

Example Usage:

class MyClass with PostConstruct {
  final String name;

  MyClass(this.name);

  @override
  void onPostConstruct() {
    // Custom logic to be executed after construction.
    print('Instance of MyClass has been successfully constructed.');
    print('Name: $_name');
  }
}

Pre Destroy Mixin #

The PreDestroy mixin has been created to provide a mechanism for executing specific actions just before an object is destroyed. This mixin serves as a counterpart to the PostConstruct mixin, allowing to define custom cleanup logic that needs to be performed before an object's lifecycle ends.

Example Usage:

class MyClass with PreDestroy {
  final String name;

  MyClass(this.name);

  @override
  void onPreDestroy() {
    // Custom cleanup logic to be executed before destruction.
    print('Instance of MyClass is about to be destroyed.');
    print('Performing cleanup for $name');
  }
}

void main() {
  // Registering an instance of MyClass
  ddi.registerSingleton<MyClass>(
     () => MyClass('Willian'),
  );
  
  // Destroying the instance (removing it from the container).
  ddi.remove<MyClass>();
  
  // Output:
  // Instance of MyClass is about to be destroyed.
  // Performing cleanup for Willian
}

Pre Dipose Mixin #

The PreDispose mixin extends the lifecycle management capabilities, allowing custom logic to be executed before an instance is disposed.

Example Usage:

class MyClass with PreDispose {
  final String name;

  MyClass(this.name);

  @override
  void onPreDispose() {
    // Custom cleanup logic to be executed before disposal.
    print('Instance of MyClass is about to be disposed.');
    print('Performing cleanup for $name');
  }
}

DDIModule Mixin #

The DDIModule mixin provides a convenient way to organize and manage your dependency injection configuration within your Dart application. By implementing this mixin in your module classes, you can easily register instances with different scopes and dependencies using the provided methods.

Example Usage:

// Define a module using the DDIModule mixin

class AppModule with DDIModule {
  @override
  void onPostConstruct() {
    // Registering instances with different scopes
    registerSingleton(() => Database('main_database'), qualifier: 'mainDatabase');
    registerApplication(() => Logger(), qualifier: 'appLogger');
    registerObject('https://api.example.com', qualifier: 'apiUrl');
    registerDependent(() => ApiService(inject.get(qualifier: 'apiUrl')), qualifier: 'dependentApiService');
  }
}

DDIInject and DDIInjectAsync Mixins #

The DDIInject and DDIInjectAsync mixins are designed to facilitate dependency injection of an instance into your classes. They provide a convenient method to obtain an instance of a specific type from the dependency injection container.

The DDIInject mixin allows for synchronous injection of an instance and DDIInjectAsync mixin allows for asynchronous injection. Both defines a instance property that will be initialized with the InjectType instance obtained.

Example Usage:

class MyController with DDIInject<MyService> {
  void businessLogic() {
    instance.runSomething();
  }
}

class MyAsyncController with DDIInjectAsync<MyService> {
  Future<void> businessLogic() async {
    final myInstance = await instance;
    myInstance.runSomething();
  }
}

DDIEventSender and DDIStreamSender Mixins #

The DDIEventSender and DDIStreamSender mixins are designed to simplify the process of sending events and stream values to listeners. They provide a convenient method fire to send the specified value to an event or stream.

The DDIEventSender mixin is used to send events to all registered listeners and the DDIStreamSender mixin is to send stream values. Both defines a fire method that takes the value as a parameter and sends it to all registered listeners.

Example Usage:

class MyEvent with DDIEventSender<String> {
  void businessLogic() {
    fire('Hello World');
  }
}

class MyStreamEvent with DDIStreamSender<int> {
  void businessLogic() {
    fire(42);
  }
}

Events #

Designed for flexibility and efficiency, this system empowers you to seamlessly manage, subscribe to, and respond to events, making it a crucial asset for building reactive and scalable Dart applications.

Creating and Managing Events #

The Events follow a straightforward flow. Functions or methods subscribe to specific events using the subscribe method of the DDIEvent class. Events are fired using the fire or fireWait methods, triggering the execution of all subscribed callbacks. Subscribed callbacks are then executed, handling the event data and performing any specified tasks. Subscriptions can be removed using the unsubscribe function.

Subscribing an Event #

When subscribing to an event, you have the option to choose from three different types of subscriptions:

  • DDIEvent.instance.subscribe It's the common type, working as a simples callback.
  • DDIEvent.instance.subscribeAsync Runs the callback as a Future.
  • DDIEvent.instance.subscribeIsolate Runs as a Isolate.

subscribe

The common subscription type, subscribe, functions as a simple callback. It allows you to respond to events in a synchronous manner, making it suitable for most scenarios.

Obs: If you register an event that uses async and await, it will not be possible to wait even using fireWait. For this scenario, use subscribeAsync.

Parameters:

  • event: The callback function to be executed when the event is fired.
  • qualifier: Optional qualifier name to distinguish between different events of the same type.
  • registerIf: A FutureOr
  • allowUnsubscribe: Indicates if the event can be unsubscribe. Ignored if autoRun is used.
  • priority: Priority of the subscription relative to other subscriptions (lower values indicate higher priority). Ignored if autoRun is used.
  • unsubscribeAfterFire: If true, the subscription will be automatically removed after the first time the event is fired. Ignored if autoRun is used.
  • lock: Indicates if the event should be locked. Running only one event simultaneously. Cannot be used in combination with autoRun.
  • onError: The callback function to be executed when an error occurs.
  • onComplete: The callback function to be executed when the event is completed. It's called even if an error occurs.
  • expirationDuration: The duration after which the subscription will be automatically removed.
  • retryInterval: Adds the ability to automatically retry the event after the interval specified.
  • defaultValue: The default value to be used when the event is fired. Required if retryInterval is used.
  • maxRetry: The maximum number of times the subscription will be automatically fired if retryInterval is used.
    • Can be used in combination with autoRun and onError.
    • If maxRetry is 0 and autoRun is true, will run forever.
    • If maxRetry is greater than 0 and autoRun is true, the subscription will be removed when the maximum number of retries is reached.
    • If maxRetry is greater than 0, autoRun is false and onError is used, the subscription will stop retrying when the maximum number is reached.
    • If expirationDuration is used, the subscription will be removed when the first rule is met, either when the expiration duration is reached or when the maximum number of retries is reached.
  • autoRun: If true, the event will run automatically when the subscription is created.
    • Only one event is allowed.
    • allowUnsubscribe is ignored.
    • unsubscribeAfterFire is ignored.
    • priority is ignored.
    • Cannot be used in combination with lock.
    • Requires the defaultValue parameter.
    • If maxRetry is 0, will run forever.
  • filter: Allows you to filter events based on their value. Only events when the filter returns true will be fired.
void myEvent(String message) {
    print('Event received: $message');
}

DDIEvent.instance.subscribe<String>(
  myEvent,
  qualifier: 'exampleEvent',
  registerIf: () => true,
  allowUnsubscribe: true,
  priority: 0
  unsubscribeAfterFire: false,
  lock: false,
  onError: (Object? error, StackTrace stacktrace, String valor){},
  onComplete: (){},
  expirationDuration: const Duration(seconds: 5),
  retryInterval: const Duration(seconds: 4),
  defaultValue: 'defaultValue',
  maxRetry: 1,
  autoRun: false,
  filter: (value) => true,
);

subscribeAsync

The subscribeAsync type runs the callback as a Future, allowing for asynchronous event handling. Making it suitable for scenarios where asynchronous execution is needed without waiting for completion. Note that it not be possible to await this type of subscription.

Obs: If you want to await for the event to be completed, fire it using fireWait.

Parameters are the same as for subscribe.

void myEvent(String message) {
    print('Event received: $message');
}

DDIEvent.instance.subscribeAsync<String>(
  myEvent,
  qualifier: 'exampleEvent',
  registerIf: () => true,
  allowUnsubscribe: true,
  unsubscribeAfterFire: false,
  lock: false,
  onError: (Object? error, StackTrace stacktrace, String valor){},
  onComplete: (){},
  expirationDuration: const Duration(seconds: 5),
  retryInterval: const Duration(seconds: 4),
  defaultValue: 'defaultValue',
  maxRetry: 1,
  autoRun: false,
  filter: (value) => true,
);

subscribeIsolate

The subscribeIsolate type runs the callback in a separate isolate, enabling concurrent event handling. This is particularly useful for scenarios where you want to execute the event in isolation, avoiding potential interference with the main application flow.

Parameters are the same as for subscribe.

void myEvent(String message) {
    print('Event received: $message');
}

DDIEvent.instance.subscribeIsolate<String>(
  myEvent,
  qualifier: 'exampleEvent',
  registerIf: () => true,
  allowUnsubscribe: true,
  unsubscribeAfterFire: false,
  lock: false,
  onError: (Object? error, StackTrace stacktrace, String valor){},
  onComplete: (){},
  expirationDuration: const Duration(seconds: 5),
  retryInterval: const Duration(seconds: 4),
  defaultValue: 'defaultValue',
  maxRetry: 1,
  autoRun: false,
  filter: (value) => true,
);

Unsubscribing an Event #

To unsubscribe from an event, use the unsubscribe function:

DDIEvent.instance.unsubscribe<String>(
  myEvent,
  qualifier: 'exampleEvent',
);

Firing an Event #

To fire an event, use the fire or fireWait function. Using fireWait makes it possible to wait for all events to complete.

DDIEvent.instance.fire('Hello, Dart DDI!', qualifier: 'exampleEvent');

await DDIEvent.instance.fireWait('Hello, Dart DDI!', qualifier: 'exampleEvent');

Events Considerations #

When using the Event System, consider the following:

Event Granularity: Design events with appropriate granularity to ensure they represent meaningful actions or states in the application.

Modularity: Keep events and their handlers modular and self-contained.

Single Responsibility: Ensure each event and its handler have a single responsibility.

Possible Problems: Be cautious of potential issues such as race conditions and excessive use of isolate-based event handling, which may impact performance.

Unnecessary Locking: Applying locks to events unnecessarily may hinder the application's responsiveness. Use locking only when essential to prevent conflicting event executions.

Event Looping: Carefully manage scenarios where events trigger further events, as this can lead to infinite loops or excessive event cascades.

See the considerations about Qualifiers.

Use Cases #

Application Lifecycle: Manage events related to the application's lifecycle.

Data Synchronization: Handle data synchronization events between local and remote data sources.

Background Task: Coordinate background tasks and events for efficient task execution.

Custom Event Bus: Build a custom event bus for inter-component communication, allowing different parts of the application to communicate without tight coupling.

Notifications: Implement notifications for updates in various parts of the application, such as new messages, alerts, or data changes.

Stream #

The DDIStream abstract class in serves as a foundation for managing streams efficiently within the application. This class provides methods for subscribing, closing, and firing events through streams. Below are the key features and usage guidelines for the DDIStream abstract class.

Subscription #

Use subscribe to register a callback function that will be invoked when the stream emits a value. This method supports optional qualifiers, conditional registration, and automatic unsubscription after the first invocation.

Subscribes to a stream of type StreamTypeT.

  • callback: A function to be invoked when the stream emits a value.
  • qualifier: An optional qualifier to distinguish between different streams of the same type.
  • registerIf: An optional function to conditionally register the subscription.
  • unsubscribeAfterFire: If true, unsubscribes the callback after it is invoked once.
void subscribe<StreamTypeT extends Object>({
  required void Function(StreamTypeT) callback,
  Object? qualifier,
  bool Function()? registerIf,
  bool unsubscribeAfterFire = false,
});

Closing Stream #

Use close to end the subscription to a specific stream, allowing for efficient resource management.

Closes the subscription to a stream of type StreamTypeT.

  • qualifier: An optional qualifier to distinguish between different streams of the same type.
void close<StreamTypeT extends Object>({Object? qualifier});

Firing Events #

Use fire to sends a value into the stream, triggering the subscribed callbacks. You can specify the target stream using the optional qualifier.

Fires a value into the stream of type StreamTypeT.

  • value: The value to be emitted into the stream.
  • qualifier: An optional qualifier to distinguish between different streams of the same type.
void fire<StreamTypeT extends Object>({
  required StreamTypeT value,
  Object? qualifier,
});

Retrieving Stream #

Use getStream to obtain a stream, providing access for further interactions. The optional qualifier allows you to retrieve a specific stream.

Retrieves a stream of type StreamTypeT.

  • qualifier: An optional qualifier to distinguish between different streams of the same type.
Stream<StreamTypeT> getStream<StreamTypeT extends Object>(
    {Object? qualifier});

API Reference #

registerSingleton #

Registers a singleton instance. The clazzRegister parameter is a factory function to create the instance. Optional parameters allow customization of the instance's behavior and lifecycle.

FutureOr<void> registerSingleton<BeanT extends Object>(
  FutureOr<BeanT> Function() clazzRegister, {
  Object? qualifier,
  void Function()? postConstruct,
  List<BeanT Function(BeanT)>? decorators,
  List<DDIInterceptor<BeanT> Function()>? interceptors,
  FutureOr<bool> Function()? registerIf,
  bool destroyable = true,
});

registerApplication

Registers an application-scoped instance. The instance is created when first used and reused afterward.

FutureOr<void> registerApplication<BeanT extends Object>(
  FutureOr<BeanT> Function() clazzRegister, {
  Object? qualifier,
  void Function()? postConstruct,
  List<BeanT Function(BeanT)>? decorators,
  List<DDIInterceptor<BeanT> Function()>? interceptors,
  FutureOr<bool> Function()? registerIf,
  bool destroyable = true,
});

registerDependent #

Registers a dependent instance. A new instance is created every time it is used.

FutureOr<void> registerDependent<BeanT extends Object>(
  FutureOr<BeanT> Function() clazzRegister, {
  Object? qualifier,
  void Function()? postConstruct,
  List<BeanT Function(BeanT)>? decorators,
  List<DDIInterceptor<BeanT> Function()>? interceptors,
  FutureOr<bool> Function()? registerIf,
  bool destroyable = true,
});

registerSession #

Registers a session-scoped instance. The instance is tied to a specific session.

FutureOr<void> registerSession<BeanT extends Object>(
  BeanT Function() clazzRegister, {
  Object? qualifier,
  void Function()? postConstruct,
  List<BeanT Function(BeanT)>? decorators,
  List<DDIInterceptor<BeanT> Function()>? interceptors,
  FutureOr<bool> Function()? registerIf,
  bool destroyable = true,
});

registerObject #

Registers an Object values as instance. The register parameter is the value shared across de application.

FutureOr<void> registerObject<BeanT extends Object>(
  BeanT register, {
  required Object qualifier,
  void Function()? postConstruct,
  List<BeanT Function(BeanT)>? decorators,
  List<DDIInterceptor<BeanT> Function()>? interceptors,
  FutureOr<bool> Function()? registerIf,
  bool destroyable = true,
});

get #

Retrieves an instance of type BeanT from the appropriate scope. You can provide a qualifier to distinguish between instances of the same type.

BeanT get<BeanT extends Object>({Object? qualifier});

getAsync #

Retrieves a Future instance of type BeanT, making possible to await to get the instances.

Future<BeanT> getAsync<BeanT extends Object>({Object? qualifier});

getByType #

Retrieves all instance identifiers of type BeanT.

List<Object> getByType<BeanT extends Object>();

call #

A shorthand for get<BeanT>(), allowing a more concise syntax for obtaining instances.

BeanT call<BeanT extends Object>();

destroy #

Destroy an instance from the container. Useful for manual cleanup.

void destroy<BeanT>({Object? qualifier});

destroyByType #

Destroy all instance with type BeanT.

void destroyByType<BeanT extends Object>();

dispose #

Disposes of an instance, invoking any cleanup logic. This is particularly useful for instances with resources that need to be released. Only applied to Application and Session Scopes

void dispose<BeanT>({Object? qualifier});

disposeByType #

Disposes all instance with type BeanT. Only applied to Application and Session Scopes

void disposeByType<BeanT extends Object>();

addDecorator #

This provides a dynamic way to enhance the behavior of registered instances by adding decorators. The addDecorator method allows you to apply additional functionality to instances managed by the library. When using the addDecorator method, keep in mind the order of execution, scope considerations, and the fact that instances already obtained remain unaffected.

void addDecorator<BeanT extends Object>(List<BeanT Function(BeanT)> decorators, {Object? qualifier});

addInterceptor #

This feature allows you to dynamically influence the instantiation, retrieval, destruction, and disposal of instances by adding custom interceptors. The addInterceptor method enables you to associate specific interceptors with particular types.

void addInterceptor<BeanT extends Object>(List<DDIInterceptor<BeanT> Function()> interceptors, {Object? qualifier});

refreshObject #

Enables the dynamic refreshing of an object within the Object Scope. Use it to update the existing object without affecting instances already obtained.

void refreshObject<BeanT extends Object>({required Object qualifier, required BeanT register,
});
0
likes
0
pub points
15%
popularity

Publisher

unverified uploader

A Dependency Injection package, with Qualifier, Decorators, Interceptors, Events and more. Inspired by Java CDI and get_it.

Repository (GitHub)
View/report issues

Topics

#dependency-injection #di #injection #java #cdi

License

unknown (license)

More

Packages that depend on dart_ddi