Where and when does the injector begin construction?

Arthur's Avatar

Arthur

06 Feb, 2015 10:32 AM

I am reading the book ActionScript Developers guide to robotlegs.
There are example files here for a Mosaic tool:

http://examples.oreilly.com/9781449308902-files/

I don't understand where does the injector construct all these models and services?
It says, if an object has an [inject]ed dependency you have to create it using the injector (I get this).

In here:
https://github.com/robotlegs/robotlegs-framework/wiki/Robotlegs-Internals

It says you can use the syntax injector.getInstance(...);

I am working to learn from the books Mosaic tool example but I don't see or understand where the construction done by the injector normally happens. The examples show the mapping but I don't get where the actual construction is occurring.

I could use some pointers. :)

  1. 1 Posted by Arthur on 06 Feb, 2015 03:54 PM

    Arthur's Avatar

    To clarify:

    In code where I don't use a framework, I would do something like this:

    var someController = new SomeController(someDependency, someOtherDependency);

    Now with Robotlegs I do something like:

    mapSingletonOf(IDependency, SomeDependency);
    mapSingletonOf(IOtherDependency, SomeOtherDependency);

    Now obviously, if I do:
    var controller = new SomeController(); // The "magic" injection does not happen

    In the code example I've seen (Mosaic):

    override public function startup():void
            {
                new BootstrapConfigValues(injector); // Used to define defaults for several values
                new BootstrapModels(injector); // Used to structure the data that is manipulated by the application
                new BootstrapServices(injector); // Mainly used to save and load files - can be used to communicate with a database and/or a server
                new BootstrapCommands(commandMap); // These are one liners that do things when events happen
                new BootstrapTileSupplyCommands(commandMap);
                new BootstrapClasses(injector);
                new BootstrapViewMediators(mediatorMap);

                addRootView();
                // and we're done
                super.startup();
            }

    Inside BootstrapModels(injector);

            public function BootstrapModels(injector:IInjector)
            {
                injector.mapSingletonOf(IConfigModel, ConfigModel);
                injector.mapSingletonOf(IMosaicDesignModel, MosaicDesignModel);
                injector.mapSingletonOf(ITileSuppliesModel, TileSuppliesModel);
                injector.mapSingletonOf(IMosaicSpecModel, MosaicSpecModel);
                injector.mapSingletonOf(IAutoIncrementor, AutoIncrementor);
            }

    So this is where the injection is setup.

    But when and where and why are the models constructed?
    I don't understand how the part that tell the injector to construct all these models gets invoked.

    Thanks,

    Arthur

  2. Support Staff 2 Posted by Ondina D.F. on 09 Feb, 2015 05:32 PM

    Ondina D.F.'s Avatar

    Hi Arthur,

    I just got home from a week-long conference and I'm pretty tired. I'll try to answer your questions in the next days, if no one else will :)

    Ondina

  3. Support Staff 3 Posted by Ondina D.F. on 10 Feb, 2015 06:10 PM

    Ondina D.F.'s Avatar

    In code where I don't use a framework, I would do something like this: var someController = new SomeController(someDependency, someOtherDependency);

    Right. And it reads like this: Arthur is instantiating SomeController and is 'injecting' its dependencies using the constructor. Arthur knows about SomeController and what it needs to do its work, i.e. someDependency, someOtherDependency. If someDependency and someOtherDependency are not optional and Arthur forgets to pass them as arguments when he is constructing SomeController, something bad will happen ;)
    If SomeController is needed in more than one class, Arthur needs to instantiate it every time and to provide its dependencies.

    It says, if an object has an [inject]ed dependency you have to create it using the injector (I get this).

    That's indeed the first step in understanding how injection works. If the Injector is the one who has to provide a class with its dependencies, it has to instantiate that class itself, or to know in some way that that class needs injection (see below) !

    Now with Robotlegs I do something like: mapSingletonOf(IDependency, SomeDependency);
    mapSingletonOf(IOtherDependency, SomeOtherDependency);
    Now obviously, if I do:
    var controller = new SomeController(); // The "magic" injection does not happen

    Yes, because the Injector won't inspect every class in our code to see if there is a need for a dependency. The Injector will only look inside classes that are known to it.

    When and how does the Injector find out that a class/object needs injection?
    The moment it (the Injector) instantiates the class or if you explicitly tell it to injectInto that class (see further down).

    How? By looking at the injection points . The most used injection point is in form of property injection. If the Injector finds a property annotated with an [Inject] metatag inside of a class, it tries to instantiate that object/class.

    So, if you had
    [Inject] public var someDependency:IDependency; inside of SomeController, the Injector is unaware of its existence, because it doesn't even know that SomeController is there.

    When does the Injector instantiate a class?
    The keyword is ON DEMAND.
    The Injector instantiates classes only on request.

    The request can be explicit like in:

    injector.instantiate(SomeController);
    

    or

    injector.mapSingleton(SomeController);
    injector.getInstance(SomeController);
    
    • "instantiate" is used to create an instance of a given class, regardless of whether or not there is a rule for such a class in the container. As such, it must be handed a class, not an interface, and it will always create a new instance. It is used by the CommandMap to create new command instances.

    • "getInstance", on the other hand, can be handed a class, abstract class, or interface, and it will return an instance based on a previously mapped rule. As such, a rule must exist or an error will be thrown. Also, multiple calls to "getInstance" might return the same instance, whereas "instantiate" will always return a new instance.

    However, you can tell the Injector to inject IDependency and IOtherDependency into an instance of SomeController that you created yourself like so:

    mapSingletonOf(IDependency, SomeDependency); 
    mapSingletonOf(IOtherDependency, SomeOtherDependency);
    
    var controller = new SomeController();
    injector.injectInto(controller);
    

    But when and where and why are the models constructed? I don't understand how the part that tell the injector to construct all these models gets invoked.

    By now, you know that the Injector is constructing classes only on request. The request can be
    getInstance() or the [Inject] metatag.
    When the Injector encounters an [Inject] the following happens (simplified):

    I hope that's the right order in which things happen there. You could follow the flow yourself by putting a few trace statements inside those methods.

    What triggers the construction/creation/instantiation of classes? That depends on the class and on the flow you defined for your application.
    As you know, mediators are created when views are added to the stage.
    The creation of commands is triggered by events. Models are usually injected into commands and services. So, if a model is injected into a command, the moment that command is created, the Injector will instantiate the model.
    So, if the first thing happening in your application is the creation of a Mediator for the contextView, for example , the MediatorMap will tell the injector to instantiate the Mediator:

    public function createMediator(viewComponent:Object):IMediator
    {
        var mediator:IMediator = mediatorByView[viewComponent];
        if (mediator == null)
        {
            var viewClassName:String = getQualifiedClassName(viewComponent);
            var config:MappingConfig = mappingConfigByViewClassName[viewClassName];
            if (config)
            {
                injector.mapValue(config.typedViewClass, viewComponent);
                mediator = injector.instantiate(config.mediatorClass);
                injector.unmap(config.typedViewClass);
                registerMediator(viewComponent, mediator);
            }
        }
        return mediator;
    }
    

    A command class is instantiated inside of the CommandMap. routeEventToCommand()
    var command:Object = injector.instantiate(commandClass);

    But when and where and why are the models constructed?

    I hope that I answered the when and where. I don't know anything about the why :P You tell me. Or, did you mean why the models were constructed in the mosaictool example?

    You could also take a look at these discussions:

    http://knowledge.robotlegs.org/discussions/robotlegs-2/5766-automag...

    http://knowledge.robotlegs.org/discussions/robotlegs-2/8182-the-nec...

    Let me know whether I answered your questions or not.

    Ondina

  4. Ondina D.F. closed this discussion on 11 May, 2015 11:32 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac