WARN: Project is in early stage and API is subject to change.
Table of Contents
QDI - is ceylon cross-platform dependency injection library (not framework). It highly-use ceylon meta-model for intantiating objects. Its very lightweight: no complex container staff. Follows one way - instantiate objects without direct passing it's dependencies.
- use ceylon meta-model to intantiate objects, thus - crossplatform (jvm/js)
- fluent
registry
interface (and immutable by default) -
registry
at every step is a new immutable registry. - you can combine multiple registries
- support resolving union/intersection dependencies, type-variance dependencies
- support instantiating direct-dependeices (non-interfaces) without registration (thanks to ceylon-meta-model)
- cache instances by default
- use decorators as some sort of AOP.
TODO: organize this part
- only constructor dependency injection support
I beleive that other DI technics (setters, interfaces) bad:
- setters embrace mutability and partial construction -
- interfaces embrace coupling (when you forced to implement such interfaces only for lib),
- no any annotation support
-
- they produce coupling. If you in some moment will dislike my lib - you can remove it with a little pain as possible.
- replace library with your own code (or back) very easy.
- only one interface registration at same time.
TODO: write more or delete. PicoContainer
- Oracle/OpenJDK 8
- Ceylon SDK 1.3.3
- ant 1.9 >
git clone https://github.com/qdzo/qdi && cd qdi
ant install
import com.github.qdzo.qdi { newRegistry }
shared void run() {
value registry = newRegistry {
`MongoPersonDao`,
`HttpPersonService`,
`App`
};
value app = registry.getInstance(`App`);
app.start();
}
- newRegistry creates new immutable registry.
- discover and register interace/class hierarhy of every given classes.
getInstance
will find and instantiate given class and all its dependencies
You can extract common part in function and then use it for different configurations:
Registy commonRegistry = newRegistry {
`HttpPersonService`,
`App`
};
shared void runTest() {
value registry = commonRegistry.register(`FakePersonDao`);
value app = registry.getInstance(`App`);
app.start();
}
shared void runProd() {
value registry = commonRegistry.register(`MongoPersonDao`);
value app = registry.getInstance(`App`);
app.start();
}
You can use these methods at once - every registry is separated and creates it's own instances. They don't collide
shared void run() {
value testRegistry = commonRegistry.register(`FakePersonDao`);
value prodRegistry = commonRegistry.register(`MongoPersonDao`);
value testApp = testRegistry.getInstance(`App`);
value prodApp = prodRegistry.getInstance(`App`);
testApp.start();
prodApp.start();
}
You can also register instances, not classes
shared void run() {
value registry = newRegistry { FakePersonDao("personCollection"), `App`}
value app = registry.getInstance(`App`);
}
/QDI/ supports registering decorators for interfaces and wrap needed instances with them.
Enhancer is class which should follow 2 rules:
- Decorator should satisfy the same interface that it wrapped.
- Decorator should take at least one constructor parameter with same interface.
You can combine multiple enhancers for.
Enhancer registration-record is tuple:
[WrappedInterface, 'list of enhancers']
Simple logger enhancer:
interface MailService {
shared formal void send(Email email);
}
// main service class
class FakeMailService() satisfies MailService {
shared actual void send(Email email) {
print("FakeMailService send email \"``email``\"");
}
...
}
// logger decorator
class MailServiceLoggerDecorator(MailService service)
satisfies MailService {
shared actual void send(Email email) {
log.info("start sending email: \"``email``\"");
service.send(email);
log.info("sending email success");
}
}
shared void run() {
value registry = newRegistry {
components = { `FakeMailService` };
enhancers = { [`MailService`, `MailServiceLoggerDecorator`] };
}
value mailSender = registry.getInstance(`MailService`);
mailSender.send(Email("Hello"));
}
/* will prints:
start sending email: "HELLO"
FakeMailService send email \"HELLO\"
sending email success
*/
- described and registered
FakeMailService
class. - registered
MailServiceLoggerDecorator
enhancer for interfaceMailService
- when
MailService
requested -FakeMailService
will be created and wrapped withMailServiceLoggerDecorator
.
You can register direct parameters for classes. parameter registration-record is tuple:
[RegisteredClass, parameterName, value]
TODO add examples here
see tests for more examples
Distributed under the Apache License, Version 2.0.