Dependency Injection
Last updated
Last updated
Dependency injection is the art of making work come home to you. Dhanji R. Prasanna
In BoxLang, WireBox is the standard when it comes to Dependency Injection and Aspect Oriented Programming (AOP).
WireBox alleviates the need for custom object factories or manual object creation in your BoxLang applications. It provides a standardized approach to object construction and assembling that will make your code easier to adapt to changes, easier to test, mock and extend.
You can read all about WireBox here: https://wirebox.ortusbooks.com/
As software developers we are always challenged with maintenance and one ever occurring annoyance, change. Therefore, the more sustainable and maintainable our software, the more we can concentrate on real problems and make our lives more productive. WireBox leverages an array of metadata annotations to make your object assembling, storage and creation easy as pie! We have leveraged the power of event driven architecture via object listeners or interceptors so you can extend not only WireBox but the way objects are analyzed, created, wired and much more. To the extent that our AOP capabilities are all driven by our AOP listener which decouples itself from WireBox code and makes it extremely flexible.
We have released one of our chapters from our CBOX202: Dependency Injection course that deals with getting started with Dependency Injection, the problem, the benefits and the solutions. We encourage you to download it, print it, share it, digest it and learn it: http://ortus-public.s3.amazonaws.com/cbox202-unit1-3.pdf
If you require any training please contact us.
Compared to manual Dependency Injection (DI), using WireBox can lead to the following advantages:
You will write less boilerplate code.
By giving WireBox DI responsibilities, you will stop creating objects manually or using custom object factories.
You can leverage object persistence scopes for performance and scalability. Even create time persisted objects.
You will not have any object creation or wiring code in your application, but have it abstracted via WireBox. Which will lead to more cohesive code that is not plagued with boilerplate code or factory code.
Objects will become more testable and easier to mock, which in turn can accelerate your development by using a TDD (Test Driven Development), BDD (Behavior Driven Development) approach.
Once WireBox leverages your objects you can take advantage of AOP or other event life cycle processes to really get funky with Object Orientation.
Here are a simple listing of features WireBox brings to the table:
Annotation driven dependency injection
0 configuration mode or a programmatic binder configuration approach via BoxLang (No XML!)
Creation and Wiring of or by:
BoxLang Classes
Java Classes
RSS Feeds
WebService objects
Constant values
DSL string building
Factory Methods
Providers
Multiple Injection Styles: Property, Setter, Method, Constructor
Automatic Package/Directory object scanning and registration
Multiple object life cycle persistence scopes:
No Scope (Transients)
Singletons
Request Scoped
Session Scoped
Application Scoped
Server Scoped
CacheBox Scoped
Integrated caching via CacheBox, scale your objects and metadata
Integrated logging via LogBox, never try to figure out what in the world the DI engine is doing
Parent Factories
Factory Method Object Creations
Object life cycle events via WireBox Listeners/Interceptors
Customizable injection DSL
WireBox object providers to avoid scope-widening issues on time/volatile persisted objects
There are three ways that DI frameworks can inject dependencies into object references:
Constructor Arguments
Setter Methods
Property Injections
Each has it's own set of pros and cons. However, the important aspect of the injection types is the order it happens. Please refer back to the list above for order reference. Here is a class leveraging all three styles, what similarities do you notice in all of them?
All the injection styles have a marker called inject
which can contain a value, this value is called the Injection DSL. This basically tells WireBox what alias to inject into the class. The value of the injection DSL can mean different things to WireBox depending on the environment, registered custom dsl's and so much more. However, at the end of the day, it means, inject something here!!
Please note that we have shown you the easiest approach to DI by leveraging annotations. If you do not like annotating your code and prefer a configuration approach; No Problem. WireBox offers a configuration Binder where you can declare all your objects explicitly with all their dependencies and persistence.
Let's digest a few examples:
The inject="UserService"
will look for an object with that alias if it doesn't find it with the alias, it treats is like a class path and tries to create, inject and return that object.
This inject DSL is spaced by colons (:) and tells WireBox the following:
Look for the logbox
DSL
Ask for a logger
Map it to {this}
class
As you are starting to see, the injection DSL can be very powerful.
The @myservice.inject
annotation for the constructor argument tells WireBox to look for the id
of MyAwesomeService
and pass it as the argument. Again, the colon is the separator of choice for DSLs.
WireBox by default treats all objects it creates as transient objects. Meaning it will create it, inject it and return it. After usage it get's destroyed automatically by the JVM. If you want longer persistence for the objects you can annotate them with a scope or shortcut annotations like the singleton
annotation.
Available scopes are:
NOSCOPE
: Transient objects
PROTOTYPE
: Transient objects
SINGLETON
: Objects constructed only once and stored in the injector
SESSION
: BoxLang session scoped based objects
APPLICATION
: BoxLang application scope based objects
REQUEST
: BoxLang request scope based objects
SERVER
: BoxLang server scope based objects
CACHEBOX
: CacheBox scoped objects
Ok, we have seen how to construct our objects according to DI principles, but how do we now use them? There are two modes of operation:
Standalone
ColdBox Application
WireBox is part of the ColdBox HMVC framework, so you can leverage DI/AOP out of the box with no configuration or startup code. If you are NOT using ColdBox then you can use WireBox in standalone mode like shown below:
Please note that by default the WireBox injector once initialized it will be scoped into application scope automatically for you as: application.wirebox
The main method to retrieve objects is called getInstance()
and you can see the signature below:
That's it! You can now start rolling with dependency injection in your applications. We highly encourage you to visit our ColdBox documentation or the standalone WireBox documentation for more in-depth analysis of dependency injection. We have only touched the surface.