poodinis/README.md

154 lines
5.6 KiB
Markdown
Raw Permalink Normal View History

2014-06-08 17:40:21 +02:00
Poodinis Dependency Injection Framework
=======================================
2014-07-13 17:34:44 +02:00
Version 0.1.3
2014-07-05 00:22:04 +02:00
Copyright 2014 Mike Bierlee
2014-06-08 17:40:21 +02:00
Licensed under the terms of the MIT license - See [LICENSE.txt](LICENSE.txt)
2014-06-14 15:47:24 +02:00
[![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png)](https://travis-ci.org/mbierlee/poodinis)
2014-06-08 17:40:21 +02:00
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).
Uses D 2.065.0 and Phobos.
History
-------
For a full overview of changes, see [CHANGES.md](CHANGES.md)
Getting started
---------------
###DUB Dependency
See the Poodinis [DUB project page] for instructions on how to include Poodinis into your project.
###Quickstart
The following example shows the typical usage of Poodinis:
```d
import poodinis.container; // The only import needed for now
interface Database{};
class RelationalDatabase : Database {}
class DataWriter {
@Autowire
public Database database; // Automatically injected when class is resolved
}
void main() {
auto container = Container.getInstance();
container.register!DataWriter;
container.register!(Database, RelationalDatabase);
auto writer = container.resolve!DataWriter;
}
```
### The container
To register a class, a new dependency container must be instantiated:
```d
// Register a private container
auto container = new Container();
// Or use the singleton container
container = Container.getInstance();
```
###Registering dependencies
They make dependencies available, they have to be registered:
```d
// Register concrete class
container.register!ExampleClass;
// Register by interface
container.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 = container.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 = container.resolve!ExampleClass;
auto exampleClassInstance2 = container.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
container.register!(ExampleClass).singleInstance();
```
* Resolve a dependency with a new instance each time it is resolved:
```d
container.register!(ExampleClass).newInstance();
```
* Resolve a dependency using a pre-existing instance
```d
auto preExistingInstance = new ExampleClass();
container.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;
}
container.register!ExampleClassA;
auto exampleInstance = new ExampleClassB();
2014-07-10 01:09:36 +02:00
container.autowire(exampleInstance);
2014-06-08 17:40:21 +02:00
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:
2014-06-08 17:40:21 +02:00
```d
container.register!ExampleClassA;
container.register!ExampleClassB;
auto instance = container.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. See Known issues for the limitations on newInstance scopes.
Known issues
------------
2014-06-22 16:35:08 +02:00
* Resolving a class registered by supertype or interface will only autowire the members inherited from its supertypes and in the case of interfaces none at all. A workaround for this issue is to autowire members in the constructor of a class:
```d
2014-06-22 17:16:07 +02:00
import poodinis.autowire;
2014-06-22 16:35:08 +02:00
class ComponentF {
@Autowire
public ComponentA componentA;
public this() {
2014-07-10 01:09:36 +02:00
globalAutowire(this);
2014-06-22 16:35:08 +02:00
}
2014-06-22 17:16:07 +02:00
// or use:
// mixin AutowireConstructor;
// which adds the constructor above
2014-06-22 16:35:08 +02:00
}
```
2014-06-08 17:40:21 +02:00
Future Work
-----------
* Thread safety
* Component scan (auto-registration)
* Registering multiple concrete classes to the same interface
[Spring Framework]: http://projects.spring.io/spring-framework/
[Hypodermic]: https://code.google.com/p/hypodermic/
[DUB]: http://code.dlang.org/
[DUB project page]: http://code.dlang.org/packages/poodinis