mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Split off extensive examples in README.md to a separate tutorial
This commit is contained in:
parent
71ac539f2a
commit
9abd329fba
233
README.md
233
README.md
|
@ -1,167 +1,66 @@
|
||||||
Poodinis Dependency Injection Framework
|
Poodinis Dependency Injection Framework
|
||||||
=======================================
|
=======================================
|
||||||
Version 2.1.0
|
Version 2.1.0
|
||||||
Copyright 2014-2015 Mike Bierlee
|
Copyright 2014-2015 Mike Bierlee
|
||||||
Licensed under the terms of the MIT license - See [LICENSE.txt](LICENSE.txt)
|
Licensed under the terms of the MIT license - See [LICENSE.txt](LICENSE.txt)
|
||||||
|
|
||||||
[![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png)](https://travis-ci.org/mbierlee/poodinis)
|
[![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png)](https://travis-ci.org/mbierlee/poodinis)
|
||||||
|
|
||||||
Poodinis is a dependency injection framework for the D programming language. It is inspired by the [Spring Framework] and [Hypodermic] IoC container for C++. Poodinis supports registering and resolving classes either by concrete type or interface. Automatic injection of dependencies is supported through the use of UDAs (Referred to as autowiring).
|
Poodinis is a dependency injection framework for the D programming language. It is inspired by the [Spring Framework] and [Hypodermic] IoC container for C++. Poodinis supports registering and resolving classes either by concrete type or interface. Automatic injection of dependencies is supported through the use of UDAs (Referred to as autowiring).
|
||||||
|
|
||||||
Developed for D 2.067.1
|
Developed for D 2.067.1
|
||||||
Uses the Phobos standard library.
|
Uses the Phobos standard library.
|
||||||
Can be built with DUB 0.9.22.
|
Can be built with DUB 0.9.22.
|
||||||
|
|
||||||
History
|
History
|
||||||
-------
|
-------
|
||||||
For a full overview of changes, see [CHANGES.md](CHANGES.md)
|
For a full overview of changes, see [CHANGES.md](CHANGES.md)
|
||||||
|
|
||||||
Getting started
|
Getting started
|
||||||
---------------
|
---------------
|
||||||
###DUB Dependency
|
###DUB Dependency
|
||||||
See the Poodinis [DUB project page] for instructions on how to include Poodinis into your project.
|
See the Poodinis [DUB project page] for instructions on how to include Poodinis into your project.
|
||||||
|
|
||||||
###Quickstart
|
###Quickstart
|
||||||
The following example shows the typical usage of Poodinis:
|
The following example shows the typical usage of Poodinis:
|
||||||
```d
|
```d
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
interface Database{};
|
interface Database{};
|
||||||
class RelationalDatabase : Database {}
|
class RelationalDatabase : Database {}
|
||||||
|
|
||||||
class DataWriter {
|
class DataWriter {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Database database; // Automatically injected when class is resolved
|
public Database database; // Automatically injected when class is resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
auto dependencies = DependencyContainer.getInstance();
|
auto dependencies = DependencyContainer.getInstance();
|
||||||
dependencies.register!DataWriter;
|
dependencies.register!DataWriter;
|
||||||
dependencies.register!(Database, RelationalDatabase);
|
dependencies.register!(Database, RelationalDatabase);
|
||||||
|
|
||||||
auto writer = dependencies.resolve!DataWriter;
|
auto writer = dependencies.resolve!DataWriter;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
For more examples, see the [examples](example) directory.
|
For more examples, see the [examples](example) directory.
|
||||||
|
|
||||||
### The container
|
###Tutorial
|
||||||
To register a class, a new dependency container must be instantiated:
|
For an extended tutorial walking you through all functionality offered by Poodinis, see [TUTORIAL.md](TUTORIAL.md)
|
||||||
```d
|
|
||||||
// Register a private container
|
Documentation
|
||||||
auto dependencies = new DependencyContainer();
|
-------------
|
||||||
// Or use the singleton container
|
You can generate Public API documentation from the source code using DUB:
|
||||||
dependencies = DependencyContainer.getInstance();
|
```
|
||||||
```
|
dub build --build=ddox
|
||||||
###Registering dependencies
|
```
|
||||||
To make dependencies available, they have to be registered:
|
The documentation can then be found in docs/
|
||||||
```d
|
|
||||||
// Register concrete class
|
Future Work
|
||||||
dependencies.register!ExampleClass;
|
-----------
|
||||||
// Register by interface
|
* Component scan (auto-registration)
|
||||||
dependencies.register!(ExampleInterface, ExampleClass);
|
|
||||||
```
|
[Spring Framework]: http://projects.spring.io/spring-framework/
|
||||||
In the above example, dependencies on the concrete class and interface will resolve an instance of class ExampleClass. Registering a class by interface does not automatically register by concrete type.
|
[Hypodermic]: https://github.com/ybainier/hypodermic/
|
||||||
|
[DUB]: http://code.dlang.org/
|
||||||
###Resolving dependencies
|
[DUB project page]: http://code.dlang.org/packages/poodinis
|
||||||
To manually resolve a dependency, all you have to do is resolve the dependency's type using the container in which it is registered:
|
[Github issue tracker]: https://github.com/mbierlee/poodinis/issues
|
||||||
```d
|
|
||||||
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
|
||||||
```
|
|
||||||
If the class is registered by interface and not by concrete type, you cannot resolve the class by concrete type. Registration of both a concrete type and interface type will resolve different registrations, returning different instances:
|
|
||||||
|
|
||||||
```d
|
|
||||||
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
|
||||||
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
|
||||||
assert(exampleClassInstance !is exampleClassInstance2);
|
|
||||||
```
|
|
||||||
You can solve this by adding the ADD_CONCRETE_TYPE_REGISTRATION option when registering:
|
|
||||||
```d
|
|
||||||
dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION);
|
|
||||||
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
|
||||||
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
|
||||||
assert(exampleClassInstance is exampleClassInstance2);
|
|
||||||
```
|
|
||||||
|
|
||||||
###Dependency scopes
|
|
||||||
With dependency scopes, you can control how a dependency is resolved. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available:
|
|
||||||
|
|
||||||
* Resolve a dependency using a single instance (default):
|
|
||||||
|
|
||||||
```d
|
|
||||||
dependencies.register!(ExampleClass).singleInstance();
|
|
||||||
```
|
|
||||||
* Resolve a dependency with a new instance each time it is resolved:
|
|
||||||
|
|
||||||
```d
|
|
||||||
dependencies.register!(ExampleClass).newInstance();
|
|
||||||
```
|
|
||||||
* Resolve a dependency using a pre-existing instance
|
|
||||||
|
|
||||||
```d
|
|
||||||
auto preExistingInstance = new ExampleClass();
|
|
||||||
dependencies.register!(ExampleClass).existingInstance(preExistingInstance);
|
|
||||||
```
|
|
||||||
|
|
||||||
###Autowiring
|
|
||||||
The real value of any dependency injection framework comes from its ability to autowire dependencies. Poodinis supports autowiring by simply applying the **@Autowire** UDA to a member of a class:
|
|
||||||
```d
|
|
||||||
class ExampleClassA {}
|
|
||||||
|
|
||||||
class ExampleClassB {
|
|
||||||
@Autowire
|
|
||||||
public ExampleClassA dependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies.register!ExampleClassA;
|
|
||||||
auto exampleInstance = new ExampleClassB();
|
|
||||||
dependencies.autowire(exampleInstance);
|
|
||||||
assert(exampleInstance.dependency !is null);
|
|
||||||
```
|
|
||||||
At the moment, it is only possible to autowire public members or properties.
|
|
||||||
|
|
||||||
Dependencies are automatically autowired when a class is resolved. So when you register ExampleClassB, its member, *dependency*, is automatically autowired:
|
|
||||||
```d
|
|
||||||
dependencies.register!ExampleClassA;
|
|
||||||
dependencies.register!ExampleClassB;
|
|
||||||
auto instance = dependencies.resolve!ExampleClassB;
|
|
||||||
assert(instance.dependency !is null);
|
|
||||||
```
|
|
||||||
If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired.
|
|
||||||
|
|
||||||
###Circular dependencies
|
|
||||||
Poodinis can autowire circular dependencies when they are registered with singleInstance or existingInstance registration scopes. Circular dependencies in registrations with newInstance scopes will not be autowired, as this would cause an endless loop.
|
|
||||||
|
|
||||||
###Registering and resolving using qualifiers
|
|
||||||
You can register multiple concrete types to a super type. When doing so, you will need to specify a qualifier when resolving that type:
|
|
||||||
```d
|
|
||||||
// Color is an interface, Blue and Red are classes implementing that interface
|
|
||||||
dependencies.register!(Color, Blue);
|
|
||||||
dependencies.register!(Color, Red);
|
|
||||||
auto blueInstance = dependencies.resolve!(Color, Blue);
|
|
||||||
```
|
|
||||||
If you want to autowire a type registered to multiple concrete types, specify a qualified type as template argument:
|
|
||||||
```d
|
|
||||||
class BluePaint {
|
|
||||||
@Autowire!Blue
|
|
||||||
public Color color;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
If you registered multiple concrete types to the same supertype and you do not resolve using a qualifier, a ResolveException is thrown stating that there are multiple candidates for the type to be resolved.
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
You can generate Public API documentation from the source code using DUB:
|
|
||||||
```
|
|
||||||
dub build --build=ddox
|
|
||||||
```
|
|
||||||
The documentation can then be found in docs/
|
|
||||||
|
|
||||||
Future Work
|
|
||||||
-----------
|
|
||||||
* Component scan (auto-registration)
|
|
||||||
|
|
||||||
[Spring Framework]: http://projects.spring.io/spring-framework/
|
|
||||||
[Hypodermic]: https://github.com/ybainier/hypodermic/
|
|
||||||
[DUB]: http://code.dlang.org/
|
|
||||||
[DUB project page]: http://code.dlang.org/packages/poodinis
|
|
||||||
[Github issue tracker]: https://github.com/mbierlee/poodinis/issues
|
|
||||||
|
|
113
TUTORIAL.md
Normal file
113
TUTORIAL.md
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
Poodinis Tutorial
|
||||||
|
=================
|
||||||
|
This tutorial will give you an overview of all functionality offered by Poodinis and how to use them.
|
||||||
|
|
||||||
|
The container
|
||||||
|
-------------
|
||||||
|
To register a class, a new dependency container must be instantiated:
|
||||||
|
```d
|
||||||
|
// Register a private container
|
||||||
|
auto dependencies = new DependencyContainer();
|
||||||
|
// Or use the singleton container
|
||||||
|
dependencies = DependencyContainer.getInstance();
|
||||||
|
```
|
||||||
|
###Registering dependencies
|
||||||
|
To make dependencies available, they have to be registered:
|
||||||
|
```d
|
||||||
|
// Register concrete class
|
||||||
|
dependencies.register!ExampleClass;
|
||||||
|
// Register by interface
|
||||||
|
dependencies.register!(ExampleInterface, ExampleClass);
|
||||||
|
```
|
||||||
|
In the above example, dependencies on the concrete class and interface will resolve an instance of class ExampleClass. Registering a class by interface does not automatically register by concrete type.
|
||||||
|
|
||||||
|
Resolving dependencies
|
||||||
|
----------------------
|
||||||
|
To manually resolve a dependency, all you have to do is resolve the dependency's type using the container in which it is registered:
|
||||||
|
```d
|
||||||
|
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
||||||
|
```
|
||||||
|
If the class is registered by interface and not by concrete type, you cannot resolve the class by concrete type. Registration of both a concrete type and interface type will resolve different registrations, returning different instances:
|
||||||
|
|
||||||
|
```d
|
||||||
|
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
||||||
|
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
||||||
|
assert(exampleClassInstance !is exampleClassInstance2);
|
||||||
|
```
|
||||||
|
You can solve this by adding the ADD_CONCRETE_TYPE_REGISTRATION option when registering:
|
||||||
|
```d
|
||||||
|
dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION);
|
||||||
|
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
||||||
|
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
||||||
|
assert(exampleClassInstance is exampleClassInstance2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependency scopes
|
||||||
|
-----------------
|
||||||
|
With dependency scopes, you can control how a dependency is resolved. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available:
|
||||||
|
|
||||||
|
* Resolve a dependency using a single instance (default):
|
||||||
|
|
||||||
|
```d
|
||||||
|
dependencies.register!(ExampleClass).singleInstance();
|
||||||
|
```
|
||||||
|
* Resolve a dependency with a new instance each time it is resolved:
|
||||||
|
|
||||||
|
```d
|
||||||
|
dependencies.register!(ExampleClass).newInstance();
|
||||||
|
```
|
||||||
|
* Resolve a dependency using a pre-existing instance
|
||||||
|
|
||||||
|
```d
|
||||||
|
auto preExistingInstance = new ExampleClass();
|
||||||
|
dependencies.register!(ExampleClass).existingInstance(preExistingInstance);
|
||||||
|
```
|
||||||
|
|
||||||
|
Autowiring
|
||||||
|
----------
|
||||||
|
The real value of any dependency injection framework comes from its ability to autowire dependencies. Poodinis supports autowiring by simply applying the **@Autowire** UDA to a member of a class:
|
||||||
|
```d
|
||||||
|
class ExampleClassA {}
|
||||||
|
|
||||||
|
class ExampleClassB {
|
||||||
|
@Autowire
|
||||||
|
public ExampleClassA dependency;
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies.register!ExampleClassA;
|
||||||
|
auto exampleInstance = new ExampleClassB();
|
||||||
|
dependencies.autowire(exampleInstance);
|
||||||
|
assert(exampleInstance.dependency !is null);
|
||||||
|
```
|
||||||
|
At the moment, it is only possible to autowire public members or properties.
|
||||||
|
|
||||||
|
Dependencies are automatically autowired when a class is resolved. So when you register ExampleClassB, its member, *dependency*, is automatically autowired:
|
||||||
|
```d
|
||||||
|
dependencies.register!ExampleClassA;
|
||||||
|
dependencies.register!ExampleClassB;
|
||||||
|
auto instance = dependencies.resolve!ExampleClassB;
|
||||||
|
assert(instance.dependency !is null);
|
||||||
|
```
|
||||||
|
If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired.
|
||||||
|
|
||||||
|
Circular dependencies
|
||||||
|
---------------------
|
||||||
|
Poodinis can autowire circular dependencies when they are registered with singleInstance or existingInstance registration scopes. Circular dependencies in registrations with newInstance scopes will not be autowired, as this would cause an endless loop.
|
||||||
|
|
||||||
|
Registering and resolving using qualifiers
|
||||||
|
------------------------------------------
|
||||||
|
You can register multiple concrete types to a super type. When doing so, you will need to specify a qualifier when resolving that type:
|
||||||
|
```d
|
||||||
|
// Color is an interface, Blue and Red are classes implementing that interface
|
||||||
|
dependencies.register!(Color, Blue);
|
||||||
|
dependencies.register!(Color, Red);
|
||||||
|
auto blueInstance = dependencies.resolve!(Color, Blue);
|
||||||
|
```
|
||||||
|
If you want to autowire a type registered to multiple concrete types, specify a qualified type as template argument:
|
||||||
|
```d
|
||||||
|
class BluePaint {
|
||||||
|
@Autowire!Blue
|
||||||
|
public Color color;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
If you registered multiple concrete types to the same supertype and you do not resolve using a qualifier, a ResolveException is thrown stating that there are multiple candidates for the type to be resolved.
|
Loading…
Reference in a new issue