Configuration metadata is the key point for developers to tell the Bearcat container to instantiate, configure, and assemble the objects in your application.
The $id property with its value is a string that you use to indentify the individual bean definition. The JsObject is a function defines the constructor function for this bean, which will be registered to bearcat through bearcat api (for frontend browser) or just using ‘module.exports’ (for backend nodejs).
this code will be frontend and backend compatible.
Instantiating a container
Instantiating a Bearcat IoC container is straightforward. Just pass the context.json defined paths to bearcat.createApp factory function (for backend nodejs) or use auto-generated bearcat-bootstrap.js (for frontend browser).
Using the container
When container started, you just use getBean method to retrieve instances of your beans.
A bean definition essentially is a recipe for creating one or more objects. The container looks at the recipe for a named bean when asked, and uses the configuration metadata encapsulated by that bean definition to create (or acquire) an actual object.
Instantiation with a constructor
In Bearcat, instantiation with a constructor is quite easy, with self-described configuration metadata you can specify your bean class as follows:
Instantiation using an instance factory method
To use this mechanism, add the factoryBean attribute, specify the name of a bean in the current container and the instance method that is to be invoked to create the Object. Set the name of the factory method itself with the factoryMethod attribute.
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the configuration or surrounding environment are discovered immediately, as opposed to hours or even days later. When this behavior is not desirable, you can prevent pre-instantiation of a singleton bean by marking the bean definition as lazy-initialized. A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup.
This behavior is controlled by the $lazy attribute, for example:
Dependency injection (DI) is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes, or the Service Locator pattern.
Code is cleaner with the DI principle and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies, and does not know the location or class of the dependencies. As such, your classes become easier to test, in particular when the dependencies are on interfaces or abstract base classes, which allow for stub or mock implementations to be used in unit tests.
Constructor-based dependency injection
Constructor-based DI is accomplished by the container invoking a constructor with a number of arguments, each representing a dependency.
Besides inject a bean into the constructor, you can specify to inject variable into the constructor.
inject variable example:
use the attribute with the prefix $T to specify the variable to be injected into the constructor with the argument named num
Properties-based dependency injection
Properties-based DI is accomplished by the container setting properties dynamicly.
you can also specify to inject value into the properties from configuration files for example.
inject value example:
Note: there is no need for Properties-based dependency injection to inject variable type into the properties
When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean definition. The idea that a bean definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe.
You can control not only the various dependencies and configuration values that are to be plugged into an object that is created from a particular bean definition, but also the scope of the objects created from a particular bean definition.
You can use scope attribute to specify the scope of the bean.
The singleton scope
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Bearcat container. The singleton beans will preInstantiate by default.
By default, scope is singleton
The prototype scope
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a
getBean() method call on the container. As a rule, use the prototype scope for all stateful beans and the singleton scope for stateless beans.
Customizing the nature of a bean
To interact with the container management of the bean lifecycle, you can add init and destroy method with the attribute init and destroy.
when car is requested by getBean invoke, init method will be called to do some init actions
when the container is ready to stop, beans in the container will call destroy method if setted.
Async Initialization method
In nodejs, almost everything is async, so async initialization is quite common.
When async initialization is required, use the async attribute to specify a async initialization method and in the function method, call cb callback function to end the async init action.
When multiple async initializations are required, use the order attribute to specify the order of the bean initialization.
in this example, wheel has an async initialization method and must be init before car, so besides set the async attribute to true, should set the order attribute to to smaller than the car.
Bean definition inheritance
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
In Bearcat, use the parent to specify the parent bean to inherit the bean definition.
Besides bean definition inheritance, child bean will inherit methods from parent bean prototype which it does not have
in this example, bus has a parent bean car, and it will inherit the bean definition from car, therefore, bus has the num with value of 100 which is inherited from car.
When a bean is marked as an abstract bean, it is usable only as a pure template bean definition that servers as a parent definition for child definitions. It is abstract and can not be initialized by getBean method, you can get the abstract bean constructor function by bearcat.getFunction method to handle child inherition. Similarly, the container’s internal preInstantiateSingletons() method ignores bean definitions that are defined as abstract.
bean can have
namespace, by default the namespace is null, all beans can be requested through unique
id, when some beans specify to have a
namespace, it must be requested by
the magic attribute for namespace is
context.json, specify the
namespace attribute to set up namespace, and in
beans attribute, set up which beans have the namespace
you can refer to context_namespace example for more details
you can write $ based syntax sugars as you like, so the following is also ok
a full example can be found on complex_function_annotation