Documentation ¶
Overview ¶
Package ioc provides an Inversion of Control component container and lifecycle hooks.
This package provides the types that define and support Granitic component container, which allows your application's objects and Granitic's framework facilities to follow the inversion of control (IoC) pattern by having their lifecycle and dependencies managed for them. An in-depth discussion of Granitic IoC can be found at http://granitic.io/1.0/ref/ioc but a description of the core concepts follows.
Components ¶
A component is defined by Granitic as an instance of a Go struct with a name that is unique within an application. Each component in your application requires a entry in the components section of your application's component definition file like:
{ "components": { "componentName": { "type": "package.structType" } } }
e.g:
{ "components": { "createRecordLogic": { "type": "inventory.CreateRecordLogic" } } }
For complete information on defining components, refer to http://granitic.io/1.0/ref/components
Granitic's documentation will use the term component and component instance interchangeably. For example, 'component field' means 'a field on the instance of the Go struct associated with that component'.
The container ¶
When Granitic starts, it will create an instance of ioc.ComponentContainer - a structure that holds references to each of the components in your application. It is responsible for injecting dependencies and configuration into your components (see below) and managing lifecycle events (also see below). The container is also referred to as the component container or IoC container.
Framework components ¶
For each Granitic facility that you enable in your application, one or more framework components will be created and added to the container. A framework component is exactly the same as any other component - an instance of a struct with a name. Depending on the complexity of the facility, multiple components may be created.
A very simple name-spacing is used to separate the names of framework components from application components - framework components' names all start with the string grnc
You are strongly encouraged to make sure your application components' names do not start with this string.
Dependencies and configuration ¶
As part of its definition, your components can request that other components are injected into its fields. Your definition can also include configuration (actual values to be set when the component is instantiated) or configuration promises (values to be injected once all sources of configuration have been merged together).
{ "components": { "createRecordLogic": { "type": "inventory.CreateRecordLogic", "MaxTracks": 20, "ArtistMustExist": "conf:record.disableAutoArtist", "DAO": "ref:inventoryDAO" } } }
In the above example, the field CreateRecordLogic.MaxTracks is set to 20 when the struct is instantiated, ArtistMustExist is set to the config element 'record.disableAutoArtist' and DAO is set to a reference to another component's instance. Note that c: and r: can be used as shorthand for config: and ref: See http://granitic.io/1.0/ref/components for more information
Any error such as type mismatches or missing configuration will cause an error that will halt application startup.
Component templates ¶
A template mechanism exists to allow multiple components that share a type, dependencies or configuration items to only have those elements defined once. This is especially useful for web service handlers. See http://granitic.io/1.0/ref/components#templates for more details.
Binding ¶
Unlike JVM/CLR languages, Go has no runtime 'instance-for-type-name' mechanism for creating instances of a struct. As a result, unlike JVM/CLR IoC containers you may have used, the container does not instantiate the actual instances of the Go structs behind application components. Instead a 'binding' proces is used - refer to the pacakage documentation for the grnc-bind tool for more information.
Container lifecycle ¶
The process of starting the container transitions through a number of distinct phase. It is possible for your code to be explicitly invoked during some of these phases by implementing one more lifecycle interfaces.
Populate Application and framework components are stored in the container. Configure Configuration and dependencies are resolved and injected into components. Decorate Components implementing the ioc.ComponentDecorator are given access to all other components to potentially modify. Start Components implementing the ioc.Startable interface are invoked. Access Components implementing ioc.AccessibilityBlocker and ioc.Accessible are interacted with. Ready Granitic application is running.
When the container is ready, a log message similar to
grncInit Ready (startup time 6.28ms)
will be logged.
There are several other possible lifecycle phases after the container is ready:
Suspend Components implementing ioc.Suspendable have their Suspend method invoked. Resume Components implementing ioc.Suspendable have their Resume method invoked. Stop Components implementing ioc.Stoppable are allowed to stop gracefully before the application exits.
Decorators ¶
Decorators are special components implementing ioc.ComponentDecorator. Their main purpose is to inject dynamically created objects into other components (such as Loggers). Decorators are destroyed after the Decorate phase of container startup.
Stopping ¶
Components that need to perform some shutdown process before an application exits should implement the Stoppable interface. See the GoDoc for ioc.Stoppable below for more detail.
Container settings ¶
The file $GRANITIC_HOME/resource/facility-config/system.json contains configuration, that can be overridden in your application's configuration file, affecting startup, garbage collection and shutdown behaviour of the container.
More information can be found at http://granitic.io/1.0/ref/system-settings
Gaining access to the container ¶
If your application component needs direct access to the container it should implement the ioc.ContainerAccessor. A reference to the container will be injected into your component during the decorate phase.
External interaction with the container ¶
If your application enables the RuntimeCtl facility, you can interact with the container and its components by using the grnc-ctl command line utility. See the package documentation for grnc-ctl for more information.
Index ¶
- Constants
- type AccessibilityBlocker
- type Accessible
- type ByName
- type Component
- type ComponentByNameFinder
- type ComponentContainer
- func (cc *ComponentContainer) AddModifier(comp string, field string, dep string)
- func (cc *ComponentContainer) AddModifiers(mods map[string]map[string]string)
- func (cc *ComponentContainer) AddProto(proto *ProtoComponent)
- func (cc *ComponentContainer) AddProtos(protos []*ProtoComponent)
- func (cc *ComponentContainer) AllComponents() []*Component
- func (cc *ComponentContainer) ByLifecycleSupport(ls LifecycleSupport) []*Component
- func (cc *ComponentContainer) ComponentByName(name string) *Component
- func (cc *ComponentContainer) ModifierExists(comp string, field string) bool
- func (cc *ComponentContainer) Modifiers(comp string) map[string]string
- func (cc *ComponentContainer) ModifiersExist(comp string) bool
- func (cc *ComponentContainer) Populate() error
- func (cc *ComponentContainer) ProtoComponents() map[string]*ProtoComponent
- func (cc *ComponentContainer) ProtoComponentsByType(tm TypeMatcher) []*ProtoComponent
- func (cc *ComponentContainer) WrapAndAddProto(name string, instance interface{})
- type ComponentDecorator
- type ComponentNamer
- type ComponentState
- type Components
- type ContainerAccessor
- type ContainerDecorator
- type LifecycleManager
- func (lm *LifecycleManager) ResumeComponents(comps []*Component) error
- func (lm *LifecycleManager) Start(startable []*Component) error
- func (lm *LifecycleManager) StartAll() error
- func (lm *LifecycleManager) StopAll() error
- func (lm *LifecycleManager) StopComponents(comps []*Component) error
- func (lm *LifecycleManager) SuspendComponents(comps []*Component) error
- type LifecycleSupport
- type ProtoComponent
- type ProtoComponents
- type Startable
- type Stoppable
- type StructFactory
- type Suspendable
- type TypeMatcher
Constants ¶
const ( StoppedState = iota StoppingState StartingState AwaitingAccessState RunningState SuspendingState SuspendedState ResumingState )
const ( None = iota CanStart CanStop CanSuspend CanBlockStart CanBeAccessed )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AccessibilityBlocker ¶
type AccessibilityBlocker interface { // BlockAccess returns true if the component wants to prevent the application from becoming ready and accessible. An // optional error message can be returned explaining why. BlockAccess() (bool, error) }
Implemented by components that MUST be ready before an application can be made accessible. For example, a component connecting to a critical external system might implement AccessibilityBlocker to prevent an HTTP server making an API available until a connection to the critical system is established.
See http://granitic.io/1.0/ref/system-settings for information about the number of times BlockAccess is called, and how the interval between these calls can be adjusted for your application.
type Accessible ¶
type Accessible interface { // AllowAccess is called by the container as the final stage of making an application ready. AllowAccess() error }
Implemented by components that require a final phase of initialisation to make themselves outside of the application. Typically implemented by HTTP servers and message queue listeners to start listening on TCP ports.
type ByName ¶
type ByName struct{ Components }
type Component ¶
type Component struct { // A pointer to a struct Instance interface{} // A name for this component that is unique within your application Name string }
A Component is an instance of a struct with a name that is unique within your application.
func NewComponent ¶
NewComponent creates a new Component with the supplied name and instance
type ComponentByNameFinder ¶
type ComponentByNameFinder interface { // ComponentByName returns the Component with the supplied name, or nil if it does not exist. ComponentByName(string) *Component }
Implemented by components that need to be able to find other components by name.
type ComponentContainer ¶
type ComponentContainer struct { FrameworkLogger logging.Logger Lifecycle *LifecycleManager // contains filtered or unexported fields }
The Granitic IoC container. See the GoDoc for the ioc package for more information on how to interact with the container.
Most applications should never need to interact with the container programmatically.
func NewComponentContainer ¶
func NewComponentContainer(logm *logging.ComponentLoggerManager, ca *config.ConfigAccessor, sys *instance.System) *ComponentContainer
Create a new instance of a Granitic IoC container.
func (*ComponentContainer) AddModifier ¶
func (cc *ComponentContainer) AddModifier(comp string, field string, dep string)
AddModifier is used to override a dependency on a component (normally a built-in Granitic component) during the configure phase of container startup.
func (*ComponentContainer) AddModifiers ¶
func (cc *ComponentContainer) AddModifiers(mods map[string]map[string]string)
AddModifiers is used to override a dependency on set of components (normally built-in Granitic components) during the configure phase of container startup.
func (*ComponentContainer) AddProto ¶
func (cc *ComponentContainer) AddProto(proto *ProtoComponent)
AddProto registers an instantiated but un-configured proto-component.
func (*ComponentContainer) AddProtos ¶
func (cc *ComponentContainer) AddProtos(protos []*ProtoComponent)
AddProto regsiters a collection of proto-components (see AddProto)
func (*ComponentContainer) AllComponents ¶
func (cc *ComponentContainer) AllComponents() []*Component
AllComponents returns all of the components hosted by the container.
func (*ComponentContainer) ByLifecycleSupport ¶
func (cc *ComponentContainer) ByLifecycleSupport(ls LifecycleSupport) []*Component
ByLifecycleSupport returns all components hosted by the container that have specific support for a lifecycle event (i.e. implement the associated lifecycle interface
func (*ComponentContainer) ComponentByName ¶
func (cc *ComponentContainer) ComponentByName(name string) *Component
See ComponentByNameFinder.ComponentByName
func (*ComponentContainer) ModifierExists ¶
func (cc *ComponentContainer) ModifierExists(comp string, field string) bool
ModifierExists checks to see if a modifier (see AddModifier) has previously been registered for a field on a component.
func (*ComponentContainer) Modifiers ¶
func (cc *ComponentContainer) Modifiers(comp string) map[string]string
Modifiers returns all registered modifiers (see AddModifier)
func (*ComponentContainer) ModifiersExist ¶
func (cc *ComponentContainer) ModifiersExist(comp string) bool
ModifiersExist returns true if any modifiers (see AddModifier) have been registered.
func (*ComponentContainer) Populate ¶
func (cc *ComponentContainer) Populate() error
Populate converts all registered proto-components into components and populates them with configuration and dependencies.
func (*ComponentContainer) ProtoComponents ¶ added in v1.2.1
func (cc *ComponentContainer) ProtoComponents() map[string]*ProtoComponent
ProtoComponents returns all components that have been registered by the container but have not yet all their dependencies resolved. If called after the container is 'Accessible' an empty slice will be returned.
func (*ComponentContainer) ProtoComponentsByType ¶ added in v1.2.1
func (cc *ComponentContainer) ProtoComponentsByType(tm TypeMatcher) []*ProtoComponent
ProtoComponentsByType returns any ProtoComponents whose Component.Instance field matches the against the supplied TypeMatcher function. If called after the container is 'Accessible' an empty slice will be returned.
func (*ComponentContainer) WrapAndAddProto ¶
func (cc *ComponentContainer) WrapAndAddProto(name string, instance interface{})
WrapAndAddProto registers an instance and name as an un-configured proto-component.
type ComponentDecorator ¶
type ComponentDecorator interface { // OfInterest should return true if the ComponentDecorator decides that the supplied component needs to be decorated. OfInterest(subject *Component) bool // DecorateComponent modifies the subject component. DecorateComponent(subject *Component, container *ComponentContainer) }
ComponentDecorator is implemented by special temporary components that only exist while the IoC container is being populated.
A ComponentDecorator's job is to examine another component (the subject) to see if it is suitable for modification by the ComponentDecorator. Typically this will involve the ComponentDecorator injecting another object into the subject if the component implements a particular interface or has a writable field of a particular name or type.
A number of built-in decorators exist to accomplish tasks like automatically adding Loggers to components with a particular field.
type ComponentNamer ¶
type ComponentNamer interface { // ComponentName returns the name of the component ComponentName() string // SetComponentName injects the component's name SetComponentName(name string) }
Implemented by components where the component's instance needs to be aware of its own component name.
type ComponentState ¶
type ComponentState int
What state (stopped, running) or transition between states (stopping, starting) a component is currently in.
type Components ¶
type Components []*Component
Type definition for a slice of components to allow sorting.
func (Components) Len ¶
func (s Components) Len() int
func (Components) Swap ¶
func (s Components) Swap(i, j int)
type ContainerAccessor ¶
type ContainerAccessor interface { // Container accepts a reference to the Granitic IoC container. Container(container *ComponentContainer) }
An interface implemented by any component that wants direct access to the IoC container.
type ContainerDecorator ¶
type ContainerDecorator struct {
// contains filtered or unexported fields
}
ContainerDecorator injects a reference to the IoC container into any component implementing the ContainerAccessor interface.
func (*ContainerDecorator) DecorateComponent ¶
func (cd *ContainerDecorator) DecorateComponent(subject *Component, cc *ComponentContainer)
DecorateComponent injects a reference to the IoC container to a component that has alredy been determined to implement ContainerAccessor.
func (*ContainerDecorator) OfInterest ¶
func (cd *ContainerDecorator) OfInterest(subject *Component) bool
OfInterest returns true if the subject component implements ContainerAccessor
type LifecycleManager ¶
type LifecycleManager struct { FrameworkLogger logging.Logger // contains filtered or unexported fields }
Provides an interface to the components to allow lifecycle methods/events to be applied to all components or a subset of the components.
func (*LifecycleManager) ResumeComponents ¶
func (lm *LifecycleManager) ResumeComponents(comps []*Component) error
SuspendComponents invokes Resume on all of the supplied components that implement Suspendable
func (*LifecycleManager) Start ¶
func (lm *LifecycleManager) Start(startable []*Component) error
Start starts the supplied components, waits for any access-blocking components to be ready, then makes all components accessible. See GoDoc for Startable, AccessibilityBlocker and Accessible for more details.
func (*LifecycleManager) StartAll ¶
func (lm *LifecycleManager) StartAll() error
StartAll finds all Startable and Accessible components runs the Start/Block/Accessible cycle.
func (*LifecycleManager) StopAll ¶
func (lm *LifecycleManager) StopAll() error
StopAll finds all components implementing Stoppable and passes them to Stop
func (*LifecycleManager) StopComponents ¶
func (lm *LifecycleManager) StopComponents(comps []*Component) error
StopComponents invokes PrepareToStop on all components then waits for them to be ready to stop by calling ReadyToStop on each component. If one or more components are not ready, they are given x chances to become ready with y milliseconds between each check. See http://granitic.io/1.0/ref/system-settings
If all components are ready, or if x has been exceeded, Stop is called on all components.
func (*LifecycleManager) SuspendComponents ¶
func (lm *LifecycleManager) SuspendComponents(comps []*Component) error
SuspendComponents invokes Suspend on all of the supplied components that implement Suspendable
type LifecycleSupport ¶
type LifecycleSupport int
Enumeration able used to categorise types by the lifecycle events they can react to.
type ProtoComponent ¶
type ProtoComponent struct { // The name of a component and the component instance (a pointer to an instantiated struct). Component *Component // A map of fields on the component instance and the names of other components that should be injected into those fields. Dependencies map[string]string // A map of fields on the component instance and the config-path that will contain the configuration that shoud be inject into the field. ConfigPromises map[string]string }
A ProtoComponent is a partially configured component that will be hosted in the Granitic IoC container once it is fully configured. Typically ProtoComponents are created using the grnc-bind tool.
func CreateProtoComponent ¶
func CreateProtoComponent(componentInstance interface{}, componentName string) *ProtoComponent
CreateProtoComponent creates a new ProtoComponent.
func (*ProtoComponent) AddConfigPromise ¶
func (pc *ProtoComponent) AddConfigPromise(fieldName, configPath string)
AddDependency requests that the container injects the config value at the specified path into the specified field during the configure phase of container startup.
func (*ProtoComponent) AddDependency ¶
func (pc *ProtoComponent) AddDependency(fieldName, componentName string)
AddDependency requests that the container injects another component into the specified field during the configure phase of container startup
type ProtoComponents ¶
type ProtoComponents struct { // ProtoComponents to be finalised and stored in the IoC container. Components []*ProtoComponent // FrameworkDependencies are instructions to inject components into built-in Granitic components to alter their behaviour. // The structure is map[ FrameworkDependencies map[string]map[string]string //A Base64 encoded version of the JSON files found in resource/facility-confg FrameworkConfig *string }
A wrapping structure for a list of ProtoComponents and FrameworkDependencies that is required when starting Granitic. A ProtoComponents structure is built by the grnc-bind tool.
func NewProtoComponents ¶
func NewProtoComponents(pc []*ProtoComponent, fd map[string]map[string]string, ser *string) *ProtoComponents
NewProtoComponents creates a wrapping structure for a list of ProtoComponents
func (*ProtoComponents) Clear ¶
func (pc *ProtoComponents) Clear()
Clear removes the reference to the ProtoComponent objects held in this object, encouraging garbage collection.
type Startable ¶
type Startable interface { // StartComponent performs initialisation and may start listeners/servers. StartComponent() error }
Implemented by components that need to perform some initialisation before they are ready to run or use.
Components that provide services outside of the application (like HTTP servers or queue listeners) should consider implementing Accessible in addition to Startable.
type Stoppable ¶
type Stoppable interface { // PrepareToStop gives notice to the component that the application is about to halt. The implementation of this method // should cause the component to block any new requests for work. PrepareToStop() // ReadyToStop is called by the container to query whether or not the component is ready to shutdown. A component might // return false if it is still processing or running a job. If the component returns false, it may optionally return // an error to explain why it is not ready. ReadyToStop() (bool, error) // Stop is an instruction by the container to immediately terminate any running processes and release any resources. // If the component is unable to do so, it may return an error, but the application will still stop. Stop() error }
Implemented by components that need to be given the opportunity to release resources or perform shutdown activities before an application is halted.
See http://granitic.io/1.0/ref/system-settings for information about the number of times ReadyToStop is called, and how the interval between these calls, can be adjusted for your application.
type StructFactory ¶ added in v1.3.0
type StructFactory func() interface{}
A function able to return a pointer to an empty struct
type Suspendable ¶
type Suspendable interface { // Suspend causes the component to stop performing its primary function until Resume is called. Suspend() error // Resume causes the component to resume its primary function. Resume() error }
Implemented by components that are able to temporarily halt and then resume their activity at some later point in time.
type TypeMatcher ¶ added in v1.2.1
type TypeMatcher func(i interface{}) bool
TypeMatcher implementations return true if the supplied interface is (or implements) an expected type