The IoC containerIntroductionThis chapter covers the Spring Framework's implementation of the
Inversion of Control (IoC) See the section entitled principleThe Spring.Core assembly provides the basis for
the Spring.NET Inversion of Control container. The IObjectFactory
interface provides an advanced configuration mechanism capable of managing
objects of any nature. The IApplicationContext
interface builds on top of the IObjectFactory (it is a
sub-interface) and adds other functionality such as easier integration
with Spring.NET's Aspect Oriented Programming (AOP) features, message
resource handling (for use in internationalization), event propagation and
application layer-specific context such as
WebApplicationContext for use in web
applications.In short, the IObjectFactory provides the
configuration framework and basic functionality, while the
IApplicationContext adds more enterprise-centric
functionality to it. The IApplicationContext is a
complete superset of the IObjectFactory, and any
description of IObjectFactory capabilities and behavior
should be considered to apply to IApplicationContexts
as well.This chapter is divided into two parts, with the first part covering the basic principles
that apply to both the IObjectFactory and
IApplicationContext, with the second part covering those features
that apply only to the IApplicationContext
interface.If you are new to Spring.NET or IoC containers in general, you may
want to consider starting with , which
contains a number of introductory level examples that actually demonstrate
a lot of what is described in detail below. Don't worry if you don't
absorb everything at once... those examples serve only to paint a picture
of how Spring.NET hangs together in really broad brushstrokes. Once you
have finished with those examples, you can come back to this section which
will fill in all the fine detail.Basics - containers and objectsThe containerThe IObjectFactory is the actual representation
of the Spring IoC container that is responsible for instantiating,
configuring, and managing a number of objects.The IObjectFactory interface is the central IoC
container interface in Spring. Its responsibilities include
instantiating or sourcing application objects, configuring such objects,
and assembling the dependencies between these objects.There are a number of implementations of the
IObjectFactory interface that come supplied straight
out-of-the-box with Spring. The most commonly used
IObjectFactory implementation is the
XmlObjectFactory class. This implementation allows
you to express the objects that compose your application, and the
doubtless rich interdependencies between such objects, in terms of XML.
The XmlObjectFactory takes this XML configuration
metadata and uses it to create a fully configured system or application.
Interaction with the IObjectFactory interface is
discussed in . Additional
features offered by another implementation of
IObjectFactory, the
IApplicationContext, are discussed in section .Configuration metadataAs can be seen in the above image, the Spring IoC container
consumes some form of configuration metadata; this configuration
metadata is nothing more than how you (as an application developer)
inform the Spring container as to how to “instantiate, configure, and
assemble [the objects in your application]”. This configuration
metadata is typically supplied in a simple and intuitive XML format.
When using XML-based configuration metadata, you write object
definitions for those object that you want the Spring IoC container to
manage, and then let the container do it's stuff.XML-based metadata is by far the most commonly used form of
configuration metadata. It is not however the only form of
configuration metadata that is allowed. The Spring IoC container
itself is totally decoupled from the format in which this
configuration metadata is actually written. Attribute based metadata
will be part of an upcoming release and it is already part of the
Spring Java framework.Spring configuration consists of at least one object definition
that the container must manage, but typically there will be more than
one object definition. When using XML-based configuration metadata,
these object are configured as <object/> elements inside a
top-level <objects/> element.These object definitions correspond to the actual objects that
make up your application. Typically you will have object definitions
for your service layer objects, your data access objects (DAOs),
presentation objects such as ASP.NET page instances, infrastructure
objects such as NHibernate SessionFactories, and so forth. Typically
one does not configure fine-grained domain objects in the container,
because it is usually the responsibility of DAOs and business logic to
create/load domain objects.Find below an example of the basic structure of XML-based
configuration metadata.<objects xmlns="http://www.springframework.net">
<object id="..." type="...">
<!-- collaborators and configuration for this object go here -->
</object>
<object id="...." type="...">
<!-- collaborators and configuration for this object go here -->
</object>
<!-- more object definitions go here -->
</objects>Instantiating a containerInstantiating a Spring IoC container is straightforward.IApplicationContext context = new XmlApplicationContext(
"file://services.xml",
"assembly://MyAssembly/MyDataAccess/data-access.xml");
// an IApplicationContext is also an IObjectFactory (via inheritance)
IObjectFactory factory = context;You can also create an container by using a custom configuration
section in the standard .NET application (or web) configuration file.
Once the container has been created you may never need to explicitly
interact with it again in your code, for example when configuring
ASP.NET pages.You may be wondering what the assembly URL is all about. The above
example uses Spring.NET's IResource
abstraction. The IResource interface provides a
simple and uniform interface to a wide array of IO resources that can
represent themselves as System.IO.Stream. An example
for a file based resource, not using the URL syntax but an
implementation of the IResource interface for file is shown
below.[C#]
IResource input = new FileSystemResource ("objects.xml");
IObjectFactory factory = new XmlObjectFactory(input);These resources are most frequently files or URLs but can also be
resources that have been embedded inside a .NET assembly. A simple URI
syntax is used to describe the location of the resource, which follows
the standard conventions for files, i.e.
file://object.xml and other well known protocols such
as http.The following snippet shows the use of the URI syntax for
referring to a resource that has been embedded inside a .NET assembly,
assembly://<AssemblyName>/<NameSpace>/<ResourceName>.
The IResource abstraction is explained further in
.To create an embedded resource using Visual Studio you must set
the Build Action of the .xml configuration file to Embedded Resource
in the file property editor. Also, you will need to explicitly rebuild
the project containing the configuration file if it is the only change
you make between successive builds. If using NAnt to build, add a
<resources> section to the csc task. For example usage, look at
the Spring.Core.Tests.build file included the distribution.The preferred way to create an
IApplicationContext or
IObjectFactory is to use a custom configuration
section in the standard .NET application configuration file (one of
App.config or Web.config). A
custom configuration section that creates the same
IApplicationContext as the previous example is
<spring>
<context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
<resource uri="file://services.xml"/>
<resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/>
</context>
</spring> The context type (specified as the value of
the type attribute of the context
element) is wholly optional, and defaults to the
Spring.Context.Support.XmlApplicationContext class,
so the following XML snippet is functionally equivalent to the first.
<spring>
<context>
<resource uri="file://services.xml"/>
<resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/>
</context>
</spring> To acquire a reference to an
IApplicationContext using a custom configuration
section, one simply uses the following code; IApplicationContext ctx = ContextRegistry.GetContext();
The ContextRegistry is used to both instantiate the
application context and to perform service locator style access to other
objects. (See for more
information). The glue that makes this possible is an implementation of
the Base Class Library (BCL) provided
IConfigurationSectionHandler interface, namely the
Spring.Context.Support.ContextHandler class. The
handler class needs to be registered in the
configSections section of the .NET configuration file
as shown below. <configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
</configSections> This declaration now enables the use
of a custom context section starting at the spring
root element.In some usage scenarios, user code will not have to explicitly
instantiate an appropriate implementation of the
IObjectFactory interface, since Spring.NET code will
do it. For example, the ASP.NET web layer provides support code to load
a Spring.NET IApplicationContext automatically as
part of the normal startup process of an ASP.NET web application.
Similar support for WinForms applications is being investigated.While programmatic manipulation of
IObjectFactory instances will be described later, the
following sections will concentrate on describing the configuration of
objects managed by IObjectFactory instances.Spring.NET comes with an XSD schema to make the validation of the
XML object definitions a whole lot easier. The XSD document is
thoroughly documented so feel free to take a peek inside (see ). The XSD is currently used in the
implementation code to validate the XML document. The XSD schema serves
a dual purpose in that it also facilitates the editing of XML object
definitions inside an XSD aware editor (typically Visual Studio) by
providing validation (and Intellisense support in the case of Visual
Studio). You may wish to refer to for more
information regarding such integration.Your XML object definitions can also be defined within the
standard .NET application configuration file by registering the
Spring.Context.Support.DefaultSectionHandler class as
the configuration section handler for inline object definitions. This
allows you to completely configure one or more
IApplicationContext instances within a single
standard .NET application configuration file as shown in the following
example. <configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net">
...
</objects>
</spring>
</configuration>Other options available to structure the configuration files are
described in and
.The IApplicationContext can be configured to
register other resource handlers, custom parsers to integrate
user-contributed XML schema into the object definitions section, type
converters, and define type aliases. These features are discussed in
section Composing XML-based configuration metadataIt is often useful to split up container definitions into
multiple XML files. One way to then load an application context which
is configured from all these XML fragments is to use the application
context constructor which takes multiple resource locations. With an
object factory, an object definition reader can be used multiple times
to read definitions from each file in turn.Generally, the Spring.NET team prefers the above approach,
assembling individual files because it keeps container configuration
files unaware of the fact that they are being combined with others.
However, an alternate approach is to compose one XML object definition
file using one or more occurrences of the import
element to load definitions from other files. Any
import elements must be placed before
object elements in the file doing the importing.
Let's look at a sample:<objects xmlns="http://www.springframework.net">
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<object id="object1" type="..."/>
<object id="object2" type="..."/>
</objects>In this example, external object definitions are being loaded
from 3 files, services.xml,
messageSource.xml, and
themeSource.xml. All location paths are considered
relative to the definition file doing the importing, so
services.xml in this case must be in the same
directory as the file doing the importing, while
messageSource.xml and
themeSource.xml must be in a
resources location below the location of the
importing file. As you can see, a leading slash is actually ignored,
but given that these are considered relative paths, it is probably
better form not to use the slash at all. The contents of the files
being imported must be fully valid XML object definition files
according to the XSD, including the top level
objects element.The ObjectsA Spring IoC container manages one or more objects. these objects
are created using the configuration metadata that has been supplied to
the container (typically in the form of XML <object/>
definitions).Within the container itself, these object definitions are
represented as IObjectDefinition objects, which contain (among other
information) the following metadata: A type name: typically this is the
actual implementation class of the object being defined..Object behavioral configuration elements, which state how
the object should behave in the Spring.NET IoC container (i.e.
prototype or singleton, lifecycle callbacks, and so forth)references to other objects which are needed for the object
to do its work: these references are also called
collaborators or
dependencies.other configuration settings to set in the newly created
object. An example would be the number of threads to use in an
object that manages a worker thread pool, or the size limit of the
pool.The concepts listed above directly translate to a set of elements
the object definition consists of. These elements are listed below,
along with a link to further documentation about each of them.
Object definition explanationFeatureMore infotypeid and namesingleton or prototypeobject propertiesconstructor argumentsautowiring modedependency checking modeinitialization methoddestruction method
Besides object definitions which contain information on how to
create a specific object, certain IObjectFactory
implementations also permit the registration of existing objects that
have been created outside the factory (by user code). The
DefaultListableObjectFactory class supports this
through the RegisterSingleton(..) method. (Typical
applications solely work with objects defined through metadata object
definitions though.)Naming objectsEvery object has one or more ids (also called
identifiers, or names; these terms refer to the same thing). These
ids must be unique within the container the object
is hosted in. An object will almost always have only one id, but if an
object has more than one id, the extra ones can essentially be
considered aliases.When using XML-based configuration metadata, you use the
'id' or 'name'attributes to
specify the object identifier(s). The 'id'
attribute allows you to specify exactly one id, and as it is a real
XML element ID attribute, the XML parser is able to do some extra
validation when other elements reference the id; as such, it is the
preferred way to specify an object id. However, the XML specification
does limit the characters which are legal in XML IDs. This is usually
not a constraint, but if you have a need to use one of these special
XML characters, or want to introduce other aliases to the object, you
may also or instead specify one or more object ids,
separated by a comma (,), semicolon
(;), or whitespace in the 'name'
attribute.Please note that you are not required to supply a name for a
object. If no name is supplied explicitly, the container will generate
a unique name for that object. The motivations for not supplying a
name for a object will be discussed later (one use case is inner
objects).Aliasing objectsIn an object definition itself, you may supply more than one
name for the object, by using a combination of the id and name
attributes as discussed in .
This approach to aliasing objects has some limitations when you
would like to assemble the main application configuration file from
multiple files. This usage pattern is common when each configuration
file represents a logical layer or component within the application.
In this case you may want to refer to a common object dependency
using a name that is specific to each file. If the common object
dependency is defined in the main application configuration file
itself, then one can use the name element as an alias mechanism.
However, if the main application configuration file should not be
responsible for defining the common object dependency, since it
logically 'belongs' to one of the other layers or components, you
can not use the name attribute to achieve this goal.In this case, you can define an alias using an explicit
alias element contained in the main application
configuration file. <alias name="fromName"
alias="toName"/>This allows an object named fromName to be
referred to as toName across all application
configuration files.As a concrete example, consider the case where the
configuration file 'a.xml' (representing component A) defines a
connection object called componentA-connection. In another file,
'b.xml' (representing component B) would like to refer to the
connection as componentB-connection. And the main application,
MyApp, defines its own XML fragment to assembles the final
application configuration from all three fragments and would like to
refer to the connection as myApp-connection. This scenario can be
easily handled by adding to the MyApp XML fragment the following
standalone aliases:<alias
name="componentA-connection"
alias="componentB-connection"/> <alias name="componentA-connection"
alias="myApp-connection"/>Now each component and the main app can refer to the
connection via a name that is unique and guaranteed not to clash
with any other definition (effectively there is a namespace), yet
they refer to the same object.Object creationAn object definition essentially is a recipe for creating one or
more objects. The container looks at the recipe for a named object when
asked, and uses the configuration metadata encapsulated by that object
definition to create (or acquire) an actual object.If you are using XML-based configuration metadata, you can specify
the type of object that is to be instantiated using the
'type' attribute of the
<object/> element. This
'type' attribute (which internally eventually boils
down to being a Type property on a
IObjectDefinition instance) is normally mandatory
(see XXX “Instantiation using an instance factory method” and XXX
“Object definition inheritance” for the two exceptions) and is used for
one of two purposes. The type property specifies the type of of the
object to be constructed in the common case where the container itself
directly creates the object by calling its constructor reflectively
(somewhat equivalent to C# code using the 'new'
operator). In the less common case where the container
invokes a static, factory method
on a class to create the object, the type property specifies the actual
class containing the static factory method that is to
be invoked to create the object (the type of the object returned from
the invocation of the static factory method may be
the same type or another type entirely, it doesn't matter).Object creation via constructor invocationWhen creating an object using the constructor approach, all
normal classes are usable by and compatible with Spring. That is, the
type being created does not need to implement any specific interfaces
or be coded in a specific fashion. Just specifying the object type
should be enough. However, depending on what type of IoC you are going
to use for that specific object, you may need to create a default
constructor (i.e. a constructor that has no parameters) in the source
code definition of your class.The XmlObjectFactory implementation of the
IObjectFactory interface can consume object
definitions that have been defined in XML, for example...
<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>The mechanism for supplying arguments to the constructor (if
required), or setting properties of the object instance after it has
been constructed, is described shortly.This XML fragment describes an object definition that will be
identified by the exampleObject name, instances
of which will be of the Examples.ExampleObject type
that has been compiled into the ExamplesLibrary
assembly. Take special note of the structure of the
type attribute's value... the namespace-qualified
name of the class is specified, followed by a comma, followed by (at a
bare minimum) the name of the assembly that contains the class. In the
preceding example, the ExampleObject class is
defined in the Examples namespace, and it has been
compiled into the ExamplesLibrary assembly.The name of the assembly that contains the type
must be specified in the type
attribute. Furthermore, it is recommended that you specify the fully
qualified assembly name More information about assembly names can be found in the
Assembly Names section of the .NET Framework
Developer's Guide (installed as part of the .NET SDK), or online
at Microsoft's MSDN website, by searching for Assembly
Names. in order to guarantee that the type that Spring.NET uses
to instantiate your object (s) is indeed the one that you expect.
Usually this is only an issue if you are using classes from (strongly
named) assemblies that have been installed into the Global Assembly
Cache (GAC).If you have defined nested classes use the addition symbol, +,
to reference the nested class. For example, if the class
Examples.ExampleObject had a nested class
Person the XML declaration would be <object id="exampleObject" type="Examples.ExampleObject+Person, ExamplesLibrary"/>If you are defining classes that have been compiled into
assemblies that are available to your application (such as the
bin directory in the case of ASP.NET applications)
via the standard assembly probing mechanisms, then you can specify
simply the name of the assembly (e.g.
ExamplesLibrary.Data)... this way, when (or if) the
assemblies used by your application are updated, you won't have to
change the value of every <object/>
definition's type attribute to reflect the new
version number (if the version number has changed)... Spring.NET will
automatically locate and use the newer versions of your assemblies
(and their attendant classes) from that point forward.Object creation via a static factory methodWhen defining an object which is to be created using a static
factory method, along with the type attribute which specifies the type
containing the static factory method, another attribute named
factory-method is needed to specify the name of the factory method
itself. Spring.NET expects to be able to call this method (with an
optional list of arguments as described later) and get back a live
object, which from that point on is treated as if it had been created
normally via a constructor. One use for such an object definition is
to call static factories in legacy code.Following is an example of an object definition which specifies
that the object is to be created by calling a factory-method. Note
that the definition does not specify the type (class) of the returned
object, only the type containing the factory method. In this example,
CreateInstance must be a static method.
<object id="exampleObject"
type="Examples.ExampleObjectFactory, ExamplesLibrary"
factory-method="CreateInstance"/>The mechanism for supplying (optional) arguments to the factory
method, or setting properties of the object instance after it has been
returned from the factory, will be described shortly.Object creation via an instance factory methodIn a fashion similar to instantiation using a static factory
method, instantiation using an instance factory method is where a
non-static method of an existing object from the container is invoked
to create the new object. To use this mechanism, the
'type' attribute must be left empty, and the
'factory-object' attribute must specify the name of
an object in the current (or parent/ancestor) container that contains
the instance method that is to be invoked to create the object. The
name of the factory method itself should still be set via the
'factory-method' attribute.<!-- the factory object, which contains an instance method called 'CreateInstance' -->
<object id="exampleFactory" type="...">
<!-- inject any dependencies required by this object -->
</object>
<!-- the object that is to be created by the factory object -->
<object id="exampleObject"
factory-method="CreateInstance"
factory-object="exampleFactory"/>Although the mechanisms for setting object properties are still
to be discussed, one implication of this approach is that the factory
object itself can be managed and configured via Dependency Injection,
by the container.When the Spring documentation makes mention of a 'factory
object', this will be a reference to an object that is configured
in the Spring container that will create objects via an instance
or static factory method. When the documentation mentions a
IFactoryObject (notice the capitalization) this
is a reference to a Spring-specific
IFactoryObject .Object creation of generic typesGeneric types can also be created in much the same manner an
non-generic types.Object creation of generic types via constructor
invocationThe following examples shows the definition of simple generic
types and how they can be created in Spring's XML based configuration
file. namespace GenericsPlay
{
public class FilterableList<T>
{
private List<T> list;
private String name;
public List<T> Contents
{
get { return list; }
set { list = value; }
}
public String Name
{
get { return name; }
set { name = value; }
}
public List<T> ApplyFilter(string filterExpression)
{
/// should really apply filter to list ;)
return new List<T>();
}
}
} The XML configuration to create and configure this object
is shown below <object id="myFilteredIntList" type="GenericsPlay.FilterableList<int>, GenericsPlay">
<property name="Name" value="My Integer List"/>
</object> There are a few items to note in terms how to
specify a generic type. First, the left bracket that specifies the
generic type, i.e. <, is replaced with the
string < due to XML escape syntax for the less than symbol.
Yes, we all realize this is less than ideal from the readability point
of view. Second, the generic type arguments can not be fully assembly
qualified as the comma is used to separate generic type arguments.
Alternative characters used to overcome the two quirks can be
implemented in the future but so far, all proposals don't seem to help
clarify the text. The suggested solution to improve readability is to
use type aliases as shown below <typeAliases>
<alias name="GenericDictionary" type=" System.Collections.Generic.Dictionary<,>" />
<alias name="myDictionary" type="System.Collections.Generic.Dictionary<int,string>" />
</typeAliases>
So that instead of something like this <object id="myGenericObject"
type="GenericsPlay.ExampleGenericObject<System.Collections.Generic.Dictionary<int , string>>, GenericsPlay" />
It can be shortened to <object id="myOtherGenericObject"
type="GenericsPlay.ExampleGenericObject<GenericDictionary<int , string>>, GenericsPlay" />
or even shorter <object id="myOtherOtherGenericObject"
type="GenericsPlay.ExampleGenericObject<MyIntStringDictionary>, GenericsPlay" />
Refer to for
additional information on using type aliases.Object creation of generic types via static factory
methodThe following classes are used to demonstrate the ability to
create instances of generic types that themselves are created via a
static generic factory method. public class TestGenericObject<T, U>
{
public TestGenericObject()
{
}
private IList<T> someGenericList = new List<T>();
private IDictionary<string, U> someStringKeyedDictionary =
new Dictionary<string, U>();
public IList<T> SomeGenericList
{
get { return someGenericList; }
set { someGenericList = value; }
}
public IDictionary<string, U> SomeStringKeyedDictionary
{
get { return someStringKeyedDictionary; }
set { someStringKeyedDictionary = value; }
}
} The accompanying factory class is
public class TestGenericObjectFactory
{
public static TestGenericObject<V, W> StaticCreateInstance<V, W>()
{
return new TestGenericObject<V, W>();
}
public TestGenericObject<V, W> CreateInstance<V, W>()
{
return new TestGenericObject<V, W>();
}
}
The XML snippet to create an instance of TestGenericObject
where V is a List of integers and
W is an integer is shown below <object id="myTestGenericObject"
type="GenericsPlay.TestGenericObjectFactory, GenericsPlay"
factory-method="StaticCreateInstance<System.Collections.Generic.List<int>,int>"
/> The StaticCreateInstance method is responsible for
instantiating the object that will be associated with the id
'myTestGenericObject'.Object creation of generic types via instance factory
methodUsing the class from the previous example the XML snippet to
create an instance of a generic type via an instance factory method is
shown below <object id="exampleFactory" type="GenericsPlay.TestGenericObject<int,string>, GenericsPlay"/>
<object id="anotherTestGenericObject"
factory-object="exampleFactory"
factory-method="CreateInstance<System.Collections.Generic.List<int>,int>"/>
This creates an instance of
TestGenericObject<List<int>,int>Using the containerAn IApplicationContext is essentially nothing
more than the interface for an advanced factory capable of maintaining a
registry of different objects and their dependencies. The
IApplicationContext enables you to read object
definitions and access them. You create one and read in some object
definition in the XML format as follows:IApplicationContext context = new XmlApplicationContext("file://objects.xml");
Basically that is all there is to it. Using
GetObject(string) or the indexer
[string], you can retrieve instances of your object;
the client-side view of the IApplicationContext is
simple. The IApplicationContext interface has just a
few other methods related to finding objects in the contianer, but
ideally your application code should never use them... indeed, your
application code should have no calls to the
GetObject(string) method at all, and thus no
dependency on Spring APIs at all.DependenciesYour typical enterprise application is not made up of a single
object. Even the simplest of applications will no doubt have at least a
handful of objects that work together to present what the end-user sees as
a coherent application. This next section explains how you go from
defining a number of object definitions that stand-alone, each to
themselves, to a fully realized application where objects work (or
collaborate) together to achieve some goal (usually an application that
does what the end-user wants).Injecting dependenciesThe basic principle behind Dependency Injection (DI) is that
objects define their dependencies (that is to say the other objects they
work with) only through constructor arguments, arguments to a factory
method, or properties which are set on the object instance after it has
been constructed or returned from a factory method. Then, it is the job
of the container to actually inject those dependencies when it creates
the object. This is fundamentally the inverse, hence the name Inversion
of Control (IoC), of the object itself being in control of instantiating
or locating its dependencies on its own using direct construction of
classes, or something like the Service Locator pattern.It becomes evident upon usage that code gets much cleaner when the
DI principle is applied, and reaching a higher grade of decoupling is
much easier when objects do not look up their dependencies, but are
provided with them (and additionally do not even know where the
dependencies are located and of what concrete class they are). DI exists
in two major variants, namely Constructor Injection and Setter
Injection.Constructor InjectionConstructor-based DI is effected by invoking a constructor with
a number of arguments, each representing a dependency. Additionally,
calling a static factory method with specific arguments to construct
the object, can be considered almost equivalent, and the rest of this
text will consider arguments to a constructor and arguments to a
static factory method similarly. Find below an example of a class that
could only be dependency injected using constructor injection. Notice
that there is nothing special about this class.public class SimpleMovieLister
{
// the SimpleMovieLister has a dependency on a MovieFinder
private IMovieFinder movieFinder;
// a constructor so that the Spring container can 'inject' a MovieFinder
public MovieLister(IMovieFinder movieFinder)
{
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected IMovieFinder is omitted...
}Constructor Argument ResolutionConstructor argument resolution matching occurs using the
argument's type. If there is no potential for ambiguity in the
constructor arguments of a object definition, then the order in
which the constructor arguments are defined in a object definition
is the order in which those arguments will be supplied to the
appropriate constructor when it is being instantiated. Consider the
following class:namespace X.Y
{
public class Foo
{
public Foo(Bar bar, Baz baz)
{
// ...
}
}
}There is no potential for ambiguity here (assuming of course
that Bar and Baz classes are not related in an inheritance
hierarchy). Thus the following configuration will work just fine,
and you do not need to specify the constructor argument indexes and
/ or types explicitly.<object name="Foo" type="X.Y.Foo, Example">
<constructor-arg>
<object type="X.Y.Bar, Example"/>
</constructor-arg>
<constructor-arg>
<object type="X.Y.Baz, Example"/>
</constructor-arg>
</object>When another object is referenced, the type is known, and
matching can occur (as was the case with the preceding example).
When a simple type is used, such as
<value>true<value>, Spring cannot
determine the type of the value, and so cannot match by type without
help. Consider the following class:using System;
namespace SimpleApp
{
public class ExampleObject
{
private int years; //No. of years to the calculate the Ultimate Answer
private string ultimateAnswer; //The Answer to Life, the Universe, and Everything
public ExampleObject(int years, string ultimateAnswer)
{
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}Constructor Argument Type MatchingThe above scenario can use type
matching with simple types by explicitly specifying the type of
the constructor argument using the type
attribute. For example: <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="string" value="42"/>
</object>The type attribute specifies the
System.Type of the constructor argument, such
as System.Int32. Alias' are available to for common simple types
(and their array equivalents). These alias' are...
Constructor Argument IndexConstructor arguments can have their index specified
explicitly by use of the index attribute. For
example: <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</object>As well as solving the ambiguity problem of
multiple simple values, specifying an index also solves the
problem of ambiguity where a constructor may have two arguments of
the same type. Note that the index is 0
based.Constructor Arguments by NameConstructor arguments can also be specified by name by using
the name attribute of the
<constructor-arg> element.<object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</object>Setter InjectionSetter-based DI is realized by calling setter methods on your
objects after invoking a no-argument constructor or no-argument static
factory method to instantiate your object.Find below an example of a class that can only be dependency
injected using pure setter injection.public class MovieLister
{
private IMovieFinder movieFinder;
public IMovieFinder MovieFinder
{
set
{
movieFinder = value;
}
}
// business logic that actually 'uses' the injected IMovieFinder is omitted...
}Constructor- or Setter-based DI?The Spring team generally advocates the usage of setter
injection, since a large number of constructor arguments can get
unwieldy, especially when some properties are optional. The presence
of setter methods also makes objects of that class amenable to being
re-configured (or re-injected) at some later time (for management
purposes).Constructor-injection is favored by some purists though and
with good reason. Supplying all of an object's dependencies means
that that object is never returned to client (calling) code in a
less than totally initialized state. The flip side is that the
object becomes less amenable to re-configuration (or
re-injection).There is no hard and fast rule here. Use whatever type of DI
makes the most sense for a particular class; sometimes, when dealing
with third party classes to which you do not have the source, the
choice will already have been made for you - a legacy class may not
expose any setter methods, and so constructor injection will be the
only type of DI available to you.Since you can mix both, Constructor- and Setter-based DI, it
is a good rule of thumb to use constructor arguments for mandatory
dependencies and setters for optional dependencies.The IObjectFactory supports both of these
variants for injecting dependencies into objects it manages. (It in
fact also supports injecting setter-based dependencies after some
dependencies have already been supplied via the constructor approach.)
The configuration for the dependencies comes in the form of the
IObjectDefinition class, which is used together
with TypeConverters to know how to convert
properties from one format to another. However, most users of
Spring.NET will not be dealing with these classes directly (that is
programatically), but rather with an XML definition file which will be
converted internally into instances of these classes, and used to load
an entire Spring IoC container instance.Object dependency resolution generally happens as follows:
The IObjectFactory is created and
initialized with a configuration which describes all the
objects. Most Spring.NET users use an
IObjectFactory or
IApplicationContext variant that supports XML
format configuration files.Each object has dependencies expressed in the form of
properties, constructor arguments, or arguments to the
static-factory method when that is used instead of a normal
constructor. These dependencies will be provided to the object,
when the object is actually created.Each property or constructor argument is either an actual
definition of the value to set, or a reference to another object
in the container.Each property or constructor argument which is a value
must be able to be converted from whatever format it was
specified in, to the actual System.Type of
that property or constructor argument. By default Spring.NET can
convert a value supplied in string format to all built-in types,
such as int, long,
string, bool, etc.
Spring.NET uses TypeConverter definitions to
be able to convert string values to other, arbitrary types.
Refer to for more
information regarding type conversion, and how you can design
your classes to be convertible by Spring.NET.The Spring container validates the configuration of each object
as the container is created, including the validation that properties
which are object references are actually referring to valid object.
However, the object properties themselves are not set until the object
is actually created. For those object that defined as singletons and
set to be pre-instantiated (such as singleton object in an
IApplicationContext), creation happens at the time
that the container is created, but otherwise this is only when the
object is requested. When an object actually has to be created, this
will potentially cause a graph of other objects to be created, as its
dependencies and its dependencies' dependencies (and so on) are
created and assigned.Circular DependenciesIf you are using predominantly constructor injection it is
possible to write and configure your classes and objects such that
an unresolvable circular dependency scenario is created.Consider the scenario where you have class A, which requires
an instance of class B to be provided via constructor injection, and
class B, which requires an instance of class A to be provided via
constructor injection. If you configure object for classes A and B
to be injected into each other, the Spring IoC container will detect
this circular reference at runtime, and throw a
ObjectCurrentlyInCreationException.One possible solution to this issue is to edit the source code
of some of your classes to be configured via setters instead of via
constructors. Another solution is not to use constructor injection
and stick to setter injection only. In other words, while it should
generally be avoided in all but the rarest of circumstances, it is
possible to configure circular dependencies with setter
injection.Unlike the typical case (with no circular dependencies), a
circular dependency between object A and object B will force one of
the objects to be injected into the other prior to being fully
initialized itself (a classic chicken/egg scenario).You can generally trust Spring.NET to do the right thing. It
will detect configuration issues, such as references to non-existent
object definitions and circular dependencies, at container load-time.
It will actually set properties and resolve dependencies as late as
possible, which is when the object is actually created. This means
that a Spring container which has loaded correctly can later generate
an exception when you request an object if there is a problem creating
that object or one of its dependencies. This could happen if the
object throws an exception as a result of a missing or invalid
property, for example. This potentially delayed visibility of some
configuration issues is why IApplicationContext by
default pre-instantiates singleton objects. At the cost of some
upfront time and memory to create these objects before they are
actually needed, you find out about configuration issues when the
IApplicationContext is created, not later. If you
wish, you can still override this default behavior and set any of
these singleton objects to lazy-load (not be preinstantiated)If no circular dependencies are involved (see sidebar for a
discussion of circular dependencies), when one or more collaborating
objects are being injected into a dependent object, each collaborating
object is totally configured prior to being passed (via one of the DI
flavors) to the dependent object. This means that if object A has a
dependency on object B, the Spring IoC container will
totally configure object B prior to invoking the
setter method on object A; you can read 'totally
configure' to mean that the object will be instantiated (if
not a pre-instantiated singleton), all of its dependencies will be
set, and the relevant lifecycle methods (such as a configured init
method or the IIntializingObject callback method)
will all be invoked.Some examplesFirst, an example of using XML-based configuration metadata for
setter-based DI. Find below a smallpart of a Spring XML configuration
file specifying some object definitions. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
<!-- setter injection using the ref attribute -->
<property name="objectOne" ref="anotherExampleObject"/>
<property name="objectTwo" ref="yetAnotherObject"/>
<property name="IntegerProperty" value="1"/>
</object>
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>[C#]
public class ExampleObject
{
private AnotherObject objectOne;
private YetAnotherObject objectTwo;
private int i;
public AnotherObject ObjectOne
{
set { this.objectOne = value; }
}
public YetAnotherObject ObjectTwo
{
set { this.objectTwo = value; }
}
public int IntegerProperty
{
set { this.i = value; }
}
}As you can see, setters have been declared to match against the
properties specified in the XML file. Find below an example of using
constructor-based DI.<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
<constructor-arg name="objectOne" ref="anotherExampleObject"/>
<constructor-arg name="objectTwo" ref="yetAnotherObject"/>
<constructor-arg name="IntegerProperty" value="1"/>
</object>
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>[Visual Basic.NET]
Public Class ExampleObject
Private myObjectOne As AnotherObject
Private myObjectTwo As YetAnotherObject
Private i As Integer
Public Sub New (
anotherObject as AnotherObject,
yetAnotherObject as YetAnotherObject,
i as Integer)
myObjectOne = anotherObject
myObjectTwo = yetAnotherObject
Me.i = i
End Sub
End ClassAs you can see, the constructor arguments specified
in the object definition will be used to pass in as arguments to the
constructor of the ExampleObject.Now consider a variant of this where instead of using a
constructor, Spring is told to call a static factory method to return
an instance of the object <object id="exampleObject" type="Examples.ExampleFactoryMethodObject, ExamplesLibrary"
factory-method="CreateInstance">
<constructor-arg name="objectOne" ref="anotherExampleObject"/>
<constructor-arg name="objectTwo" ref="yetAnotherObject"/>
<constructor-arg name="intProp" value="1"/>
</object>
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>[C#]
public class ExampleFactoryMethodObject
{
private AnotherObject objectOne;
private YetAnotherObject objectTwo;
private int i;
// a private constructor
private ExampleFactoryMethodObject()
{
}
public static ExampleFactoryMethodObject CreateInstance(AnotherObject objectOne,
YetAnotherObject objectTwo,
int intProp)
{
ExampleFactoryMethodObject fmo = new ExampleFactoryMethodObject();
fmo.AnotherObject = objectOne;
fmo.YetAnotherObject = objectTwo;
fmo.IntegerProperty = intProp;
return fmo;
}
// Property definitions
} Note that arguments to the static factory method are
supplied via constructor-arg elements, exactly the same as if a
constructor had actually been used. These arguments are optional.
Also, it is important to realize that the type of the class being
returned by the factory method does not have to be of the same type as
the class which contains the static factory method, although in this
example it is. An instance (non-static) factory method, mentioned
previously, would be used in an essentially identical fashion (aside
from the use of the factory-object attribute instead of the type
attribute), so will not be detailed here.Note that Setter Injection and Constructor Injectionare not
mutually exclusive. It is perfectly reasonable to use both for a
single object definition, as can be seen in the following example:
<object id="exampleObject" type="Examples.MixedIocObject, ExamplesLibrary">
<constructor-arg name="objectOne" ref="anotherExampleObject"/>
<property name="objectTwo" ref="yetAnotherObject"/>
<property name="IntegerProperty" value="1"/>
</object>
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>[C#]
public class MixedIocObject
{
private AnotherObject objectOne;
private YetAnotherObject objectTwo;
private int i;
public MixedIocObject (AnotherObject obj)
{
this.objectOne = obj;
}
public YetAnotherObject ObjectTwo
{
set { this.objectTwo = value; }
}
public int IntegerProperty
{
set { this.i = value; }
}
}Dependencies and configuration in detailAs mentioned in the previous section, object properties and
constructor arguments can be defined as either references to other
managed objects (collaborators), or values defined inline. Spring's
XML-based configuration metadata supports a number of sub-element types
within its <property/> and
<constructor-arg/> elements for this
purpose.aStraight values (primitives, strings,
etc.)The <value/> element specifies a
property or constructor argument as a human-readable string
representation. As mentioned previously,
TypeConverter instances are used to convert these
string values from a System.String to the actual
property or argument type. Custom TypeConverter
implementations in the
Spring.Objects.TypeConverters namespace are used to
augment the functionality offered by the .NET BCL's default
TypeConverter implementations.In the following example, we use a
SqlConnection from the
System.Data.SqlClient namespace of the BCL. This
class (like many other existing classes) can easily be used in a
Spring.NET object factory, as it offers a convenient public property
for configuration of its ConnectionString
property.<objects xmlns="http://www.springframework.net">
<object id="myConnection" type="System.Data.SqlClient.SqlConnection">
<!-- results in a call to the setter of the ConnectionString property -->
<property
name="ConnectionString"
value="Integrated Security=SSPI;database=northwind;server=mySQLServer"/>
</object>
</objects>The idref elementAn idref element is simply a shorthand and error-proof way to
set a property to the String id or
name of another object in the
container.<object id="theTargetObject" type="...">
. . .
</object>
<object id="theClientObject" type="...">
<property name="targetName">
<idref object="theTargetObject"/>
</property>
</object>This is exactly equivalent at runtime to the
following fragment:<object id="theTargetObject" type="...">
. . .
</object>
<object id="theClientObject" type="...">
<property name="targetName" value="theTargetObject"/>
</object>The main reason the first form is preferable
to the second is that using the idref tag will
allow Spring.NET to validate at deployment time that the other
object actually exists. In the second variation, the class that is
having its targetName property injected is
forced to do its own validation, and that will only happen when that
class is actually instantiated by the container, possibly long after
the container is actually up and running.Additionally, if the object being referred to is in the same
actual XML file, and the object name is the object
id, the local attribute may
be used, which will allow the XML parser itself to validate the
object name even earlier, at parse time. <property name="targetName">
<idref local="theTargetObject"/>
</property>Whitespace HandlingUsually all leading and trailing whitespaces are trimmed from
a <value /> element's text. In some cases it is necessary to
maintain whitespaces exactly as they are written into the xml
element. The parser does understand the xml:space attribute in this
case:<property name="myProp">
<value xml:space="preserve"> 

	</value>
</property>The above configuration will result in the string " \n\r\t".
Note, that you don't have to explicitely specifiy the 'xml'
namespace on top of your configuration.Referring to collaborating objectsThe ref element is the final element allowed
inside a property definition element. It is used to
set the value of the specified property to be a reference to another
object managed by the container, a collaborator, so to speak. As you
saw in the previous example to set collection properties, we used the
SqlConnection instance from the initial example as
a collaborator and specified it using a <ref object/> element.
As mentioned in a previous section, the referred-to object is
considered to be a dependency of the object who's property is being
set, and will be initialized on demand as needed (if it is a singleton
object it may have already been initialized by the container) before
the property is set. All references are ultimately just a reference to
another object, but there are 3 variations on how the id/name of the
other object may be specified, which determines how scoping and
validation is handled.Specifying the target object by using the
object attribute of the ref tag
is the most general form, and will allow creating a reference to any
object in the same IObjectFactory /
IApplicationContext (whether or not in the same XML
file), or parent IObjectFactory /
IApplicationContext. The value of the
object attribute may be the same as either the
id attribute of the target object, or one of the
values in the name attribute of the target
object.<ref object="someObject"/>Specifying the target object by using the
local attribute leverages the ability of the XML
parser to validate XML id references within the same file. The value
of the local attribute must be the same as the
id attribute of the target object. The XML parser
will issue an error if no matching element is found in the same file.
As such, using the local variant is the best choice (in order to know
about errors are early as possible) if the target object is in the
same XML file.<ref local="someObject"/>Specifying the target object by using the
parent attribute allows a reference to be created
to an object that is in a parent IObjectFactory
(orIApplicationContext) of the current
IObjectFactory (or
IApplicationContext). The value of the
parent attribute may be the same as either the
id attribute of the target object, or one of the
values in the name attribute of the target object,
and the target object must be in a
parent IObjectFactory or
IApplicationContext of the current one. The main
use of this object reference variant is when there is a need to wrap
an existing object in a parent context with some sort of proxy (which
may have the same name as the parent), and needs the original object
so it may wrap it.<ref parent="someObject"/>Inline objectsAn object element inside the
property element is used to define an object value
inline, instead of referring to an object defined elsewhere in the
container. The inline object definition does not need to have any id
or name defined (indeed, if any are defined, they will be ignored).
<object id="outer" type="...">
<!-- Instead of using a reference to target, just use an inner object -->
<property name="target">
<object type="ExampleApp.Person, ExampleApp">
<property name="name" value="Tony"/>
<property name="age" value="51"/>
</object>
</property>
</object>Setting collection valuesThe list, set,
name-values and dictionary
elements allow properties and arguments of the type
IList, ISet,
NameValueCollection and
IDictionary, respectively, to be defined and set.
<objects xmlns="http://www.springframework.net">
<object id="moreComplexObject" type="Example.ComplexObject">
<!--
results in a call to the setter of the SomeList (System.Collections.IList) property
-->
<property name="SomeList">
<list>
<value>a list element followed by a reference</value>
<ref object="myConnection"/>
</list>
</property>
<!--
results in a call to the setter of the SomeDictionary (System.Collections.IDictionary) property
-->
<property name="SomeDictionary">
<dictionary>
<entry key="a string => string entry" value="just some string"/>
<entry key-ref="myKeyObject" value-ref="myConnection"/>
</dictionary>
</property>
<!--
results in a call to the setter of the SomeNameValue (System.Collections.NameValueCollection) property
-->
<property name="SomeNameValue">
<name-values>
<add key="HarryPotter" value="The magic property"/>
<add key="JerrySeinfeld" value="The funny (to Americans) property"/>
</name-values>
</property>
<!--
results in a call to the setter of the SomeSet (Spring.Collections.ISet) property
-->
<property name="someSet">
<set>
<value>just some string</value>
<ref object="myConnection"/>
</set>
</property>
</object>
</objects>Many classes in the BCL expose only read-only properties for
collection classes. When Spring.NET encounters a read-only collection,
it will configure the collection by using the getter property to
obtain a reference to the collection class and then proceed to add the
additional elements to the existing collection. This results in an
additive behavior for collection properties that are exposed in this
manner.Note that the value of a Dictionary entry, or a set
value, can also again be any of the elements:(object | ref | idref | expression | list | set | dictionary |
name-values | value | null)The shortcut forms for value and references are useful to reduce
XML verbosity when setting collection properties. See for more information.Setting generic collection valuesSpring supports setting values for classes that expose
properties based on the generic collection interfaces
IList<T> and IDictionary<TKey,
TValue>. The type parameter for these collections is
specified by using the XML attribute element-type
for IList<T> and the XML attributes
key-type and value-type for
IDictionary<TKey, TValue>. The values of the
collection are automaticaly converted from a string to the appropriate
type. If you are using your own user-defined type as a generic type
parameter you will likely need to register a custom type converter.
Refer to for more
information. The implementations of IList<T>
and IDictionary<TKey, TValue> that is created
are System.Collections.Generic.List and
System.Collections.Generic.Dictionary.The following class represents a lottery ticket and demonstrates
how to set the values of a generic IList. public class LotteryTicket {
List<int> list;
DateTime date;
public List<int> Numbers {
set { list = value; }
get { return list; }
}
public DateTime Date {
get { return date; }
set { date = value; }
}
} The XML fragment that can be used to configure this class
is shown below <object id="MyLotteryTicket" type="GenericsPlay.Lottery.LotteryTicket, GenericsPlay">
<property name="Numbers">
<list element-type="int">
<value>11</value>
<value>21</value>
<value>23</value>
<value>34</value>
<value>36</value>
<value>38</value>
</list>
</property>
<property name="Date" value="4/16/2006"/>
</object>The following shows the definition of a more complex class that
demonstrates the use of generics using the
Spring.Expressions.IExpression interface as the
generic type parameter for the IList element-type and the value-type
for IDictionary. Spring.Expressions.IExpression has
an associated type converter,
Spring.Objects.TypeConverters.ExpressionConverter
that is already pre-registered with Spring. public class GenericExpressionHolder
{
private System.Collections.Generic.IList<IExpression> expressionsList;
private System.Collections.Generic.IDictionary<string,IExpression> expressionsDictionary;
public System.Collections.Generic.IList<IExpression> ExpressionsList
{
set { this.expressionsList = value; }
}
public System.Collections.Generic.IDictionary<string, IExpression> ExpressionsDictionary
{
set { this.expressionsDictionary = value; }
}
public IExpression this[int index]
{
get
{
return this.expressionsList[index];
}
}
public IExpression this[string key]
{
get { return this.expressionsDictionary[key]; }
}
} An example XML configuration of this class is shown
below <object id="genericExpressionHolder"
type="Spring.Objects.Factory.Xml.GenericExpressionHolder,
Spring.Core.Tests">
<property name="ExpressionsList">
<list element-type="Spring.Expressions.IExpression, Spring.Core">
<value>1 + 1</value>
<value>date('1856-7-9').Month</value>
<value>'Nikola Tesla'.ToUpper()</value>
<value>DateTime.Today > date('1856-7-9')</value>
</list>
</property>
<property name="ExpressionsDictionary">
<dictionary key-type="string" value-type="Spring.Expressions.IExpression, Spring.Core">
<entry key="zero">
<value>1 + 1</value>
</entry>
<entry key="one">
<value>date('1856-7-9').Month</value>
</entry>
<entry key="two">
<value>'Nikola Tesla'.ToUpper()</value>
</entry>
<entry key="three">
<value>DateTime.Today > date('1856-7-9')</value>
</entry>
</dictionary>
</property>
</object>Setting null valuesThe <null> element is used to handle
null values. Spring.NET treats empty arguments for
properties and constructor arguments as empty
string instances. The following configuration
demonstrates this behaviour...<object type="Examples.ExampleObject, ExamplesLibrary">
<property name="email"><value></value></property>
<!-- equivalent, using value attribute as opposed to nested <value/> element...
<property name="email" value=""/>
</object>This results in the email property being set to the empty string
value (""), in much the same way as can be seen in
the following snippet of C# code... exampleObject.Email = "";
The special <null/> element may be used to
indicate a null value; to wit...<object type="Examples.ExampleObject, ExamplesLibrary">
<property name="email"><null/></property>
</object>This results in the email property being set to
null, again in much the same way as can be seen in
the following snippet of C# code... exampleObject.Email = null;Setting indexer propertiesAn indexer lets you set and get values from a collection using a
familiar bracket [] notation. Spring's XML
configuration supports the setting of indexer properties. Overloaded
indexers as well as multiparameter indexers are also supported. The
property expression parser described in
is used to perform the type conversion of the indexer name argument
from a string in the XML file to a matching target type. As an example
consider the following class public class Person
{
private IList favoriteNames = new ArrayList();
private IDictionary properties = new Hashtable();
public Person()
{
favoriteNames.Add("p1");
favoriteNames.Add("p2");
}
public string this[int index]
{
get { return (string) favoriteNames[index]; }
set { favoriteNames[index] = value; }
}
public string this[string keyName]
{
get { return (string) properties[keyName]; }
set { properties.Add(keyName, value); }
}
} The XML configuration snippet to populate this object with
data is shown below <object id="person" type="Test.Objects.Person, Test.Objects">
<property name="[0]" value="Master Shake"/>
<property name="['one']" value="uno"/>
</object>The use of the property expression parser in Release 1.0.2
changed how you configure indexer properties. The following section
describes this usage.The older style configuration uses the following syntax
<object id="objectWithIndexer" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="Item[0]" value="my string value"/>
</object> You can also change the name used to identify
the indexer by adorning your indexer method declaration with the
attribute [IndexerName("MyItemName")]. You would
then use the string MyItemName[0] to configure
the first element of that indexer.There are some limitations to be aware in the older indexer
configuration. The indexer can only be of a single parameter that is
convertible from a string to the indexer parameter type. Also,
multiple indexers are not supported. You can get around that last
limitation currently if you use the IndexerName attribute.Value and ref shortcut formsThere are also some shortcut forms that are less verbose than
using the full value and ref
elements. The property,
constructor-arg, and entry
elements all support a value attribute which may be
used instead of embedding a full value element.
Therefore, the following: <property name="myProperty">
<value>hello</value>
</property>
<constructor-arg>
<value>hello</value>
</constructor-arg>
<entry key="myKey">
<value>hello</value>
</entry> are equivalent to:<property name="myProperty" value="hello"/>
<constructor-arg value="hello"/>
<entry key="myKey" value="hello"/> In general, when
typing definitions by hand, you will probably prefer to use the less
verbose shortcut form.The property and
constructor-arg elements support a similar shortcut
ref attribute which may be used instead of a full
nested ref element. Therefore, the following...
<property name="myProperty">
<ref object="anotherObject"/>
</property>
<constructor-arg index="0">
<ref object="anotherObject"/>
</constructor-arg> is equivalent to... <property name="myProperty" ref="anotherObject"/>
<constructor-arg index="0" ref="anotherObject"/>The shortcut form is equivalent to a <ref
object="xxx"> element; there is no shortcut for either
the <ref local="xxx"> or <ref
parent="xxx"> elements. For a local or parent
ref, you must still use the long form.Finally, the entry element allows a shortcut form the specify
the key and/or value of a dictionary, in the form of key/key-ref and
value/value-ref attributes. Therefore, the following <entry>
<key>
<ref object="MyKeyObject"/>
</key>
<ref object="MyValueObject"/>
</entry> Is equivalent to: <entry key-ref="MyKeyObject" value-ref="MyValueObject"/>
As mentioned previously, the equivalence is to <ref
object="xxx"> and not the local or parent forms of object
references.Compound property names and Spring expression
referencesNote that compound or nested property names are perfectly legal
when setting object properties. Property names are interpreted using
the Spring Expression Language
(SpEL) and therefore can leverage its many features to set property
names. For example, in this object definition a simple nested property
name is configured<object id="foo" type="Spring.Foo, Spring.Foo">
<property name="bar.baz.name" value="Bingo"/>
</object>As an example of some alternative ways to declare the property
name, you can use SpEL's support for indexers to configure a
Dictionary key value pair as an alternative to the nested
<dictionary> element. More importantly, you
can use the 'expression' element to refer to a Spring expression as
the value of the property. Simple examples of this are shown
below<property name=“minValue” expression=“int.MinValue” />
<property name=“weekFromToday” expression="DateTime.Today + 7"/>Using SpEL's support for method evaluation, you can easily call
static method on various helper classes in your XML
configuraiton.Declarative Event Listener RegistrationIn C# events are built right into the language thanks to the
event keyword. Under the scenes, events are
essentially a shorthand notation for delegates with some additional
guidelines as to what the parameters to an event handler method should
be (i.e. a sender System.Object and an
System.EventArgs object).public class EventSource
public event EventHandler Click;In use, .NET events are combined with one or more event handler
methods. Each handler method is programmatically added, or removed, from
the event and corresponds to an object's method that should be invoked
when a particular event occurs. When more than one handler method is
added to an event, then each of the registered methods will be invoked
in turn when an event occurs.TestObject source = new TestObject();
TestEventHandler eventListener1 = new TestEventHandler();
TestEventHandler eventListener2 = new TestEventHandler();
source.Click += eventListener1.HandleEvent; // Adding the first event handler method to the event
source.Click += eventListener2.HandleEvent; // Adding a second event handler method to the event
source.OnClick(); // First eventListener1.HandleEvent is invoked, then eventListener2.HandleEventWhen OnClick() is invoked, the event is fired.public void OnClick()
{
if (Click != null)
{
Click(this, EventArgs.Empty); // Fire the event off to the registered handler methods
}
}One of the not so nice things about using events is that, without
employing late binding, you declare the objects that are registered with
a particular event programmatically. Spring .NET offers a way to
declaratively register your handler methods with particular events using
the <listener> element inside your
<object> elements.Declarative event handlersRather than having to specifically declare in your code that you
are adding a method to be invoked on an event, using the
<listener> element you can register a plain
object's methods with the corresponding event declaratively in your
application configuration.Using the listener element you can:
Configure a
method to be invoked when an event is fired.
Register a
collection of handler methods based on a regular
expression.
Register
a handler method against an event name that contains a regular
expression.
Configuring a method to be invoked when an event is
firedThe same event registration in the example above can be achieved
using configuration using the <listener>
element.<object id="eventListener1" type="SpringdotNETEventsExample.TestEventHandler, SpringdotNETEventsExample">
<!-- wired up to an event exposed on an instance -->
<listener event="Click" method="HandleEvent">
<ref object="source"/>
</listener>
</object>
<object id="eventListener2" type="SpringdotNETEventsExample.TestEventHandler, SpringdotNETEventsExample">
<!-- wired up to an event exposed on an instance -->
<listener event="Click" method="HandleEvent">
<ref object="source"/>
</listener>
</object>In this case the two different objects will have their
HandleEvent method invoked, as indicated explicitly
using the method attribute, when a
Click event, as specified by the
event attribute, is triggered on the object
referred to by the ref element.Registering a collection of handler methods based on a regular
expressionRegular expressions can be employed to wire up more than one
handler method to an object that contains one or more events.<object id="eventListener" type="SpringdotNETEventsExample.TestEventHandler, SpringdotNETEventsExample">
<listener method="Handle.+">
<ref object="source"/>
</listener>
</object>Here all the eventListener's handler methods
that begin with 'Handle', and that have the corresponding two
parameters of a System.Object and a
System.EventArgs, will be registered against all
events exposed by the source object.You can also use the name of the event in regular expression to
filter your handler methods based on the type of event
triggered.<object id="eventListener" type="SpringdotNETEventsExample.TestEventHandler, SpringdotNETEventsExample">
<!-- For the Click event, the HandleClick handler method will be invoked. -->
<listener method="Handle${event}">
<ref object="source"/>
</listener>
</object>Registering a handler method against an event name that
contains a regular expressionFinally, you can register an object's handler methods against a
selection of events, filtering based on their name using a regular
expression.<object id="eventListener" type="SpringdotNETEventsExample.TestEventHandler, SpringdotNETEventsExample">
<listener method="HandleEvent" event="Cl.+">
<ref object="source"/>
</listener>
</object>In this example the eventListener's
HandleEvent handler method will be invoked for any
event that begins with 'Cl'.Using depends-onFor most situations, the fact that an object is a dependency of
another is expressed by the fact that one object is set as a property of
another. This is typically accomploished with the
<ref/> element in XML-based configuration
metadata. For the relatively infrequent situations where dependencies
between objects are less direct (for example, when a static initializer
in a class needs to be triggered) the 'depends-on'
attribute may be used to explicitly force one or more objects to be
initialized before the object using this element is initialized. Find
below an example of using the 'depends-on' attribute
to express a dependency on a single object.. <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager">
<property name="manager" ref="manager"/>
</object>
<object id="manager" type="Examples.ManagerObject, ExamplesLibrary"/>If you need to express a dependency on multiple objects, you can
supply a list of object names as the value of the
'depends-on' attribute, with commas, whitespace and
semicolons all valid delimiters, like so:<object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</object>
<object id="manager" type="Examples.ManagerObject, ExamplesLibrary" />
<object id="accountDao" type="Examples.AdoAccountDao, ExamplesLibrary" />The 'depends-on' attribute and property is
used not only to specify an initialization time dependency, but also
to specify the corresponding destroy time dependency (in the case of
singleton objects only). Dependent objects that are defined in the
'depends-on' attribute will be destroyed after the relevant object
itself is destroyed. This thus allows you to control shutdown order
tooLazily-instantiated objectsThe default behavior for IApplicationContext
implementations is to eagerly pre-instantiate all singleton objects at
startup. Pre-instantiation means that an
IApplicationContext will eagerly create and configure
all of its singleton objects as part of its initialization process.
Generally this is a good thing, because it means that any errors in the
configuration or in the surrounding environment will be discovered
immediately (as opposed to possibly hours or even days down the
line).However, there are times when this behavior is not what is wanted.
If you do not want a singleton object to be pre-instantiated when using
an IApplicationContext, you can selectively control
this by marking an object definition as lazy-initialized. A
lazily-initialized object indicates to the IoC container whether or not
an object instance should be created at startup or when it is first
requested.When configuring objects via XML, this lazy loading is controlled
by the 'lazy-init'attribute on the
<object/> element; for example:<object id="lazy" type="MyCompany.ExpensiveToCreateObject, MyApp" lazy-init="true"/>
<object name="not.lazy" type="MyCompany.AnotherObject, MyApp"/>When the above configuration is consumed by an
IApplicationContext, the object named
'lazy' will not be eagerly pre-instantiated when the
IApplicationContext is starting up, whereas the
'not.lazy' object will be eagerly pre-instantiated.One thing to understand about lazy-initialization is that even
though an object definition may be marked up as being lazy-initialized,
if the lazy-initialized object is the dependency of a singleton object
that is not lazy-initialized, when the
IApplicationContext is eagerly pre-instantiating the
singleton, it will have to satisfy all of the singletons dependencies,
one of which will be the lazy-initialized object! So don't be confused
if the IoC container creates one of the objects that you have explicitly
configured as lazy-initialized at startup; all that means is that the
lazy-initialized object is being injected into a non-lazy-initialized
singleton object elsewhere.It is also possible to control lazy-initialization at the
container level by using the
'default-lazy-init'attribute on the <objects/>
element; for example:<objects default-lazy-init="true">
<!-- no objects will be pre-instantiated... -->
</objects>Autowiring collaboratorsThe Spring container is able to autowire relationships between
collaborating objects. This means that it is possible to automatically
let Spring resolve collaborators (other objects) for your object by
inspecting the contents of the IoC container.. The autowiring
functionality has five modes. Autowiring is specified per object and can
thus be enabled for some object, while other objects will not be
autowired. Using autowiring, it is possible to reduce or eliminate the
need to specify properties or constructor arguments, thus saving a
significant amount of typing. When using XML-based configuration
metadata, the autowire mode for an object definition is specified by
using the autowire attribute of the <object/> element. The
following values are allowed:
Autowiring modesModeExplanationnoNo autowiring at all. This is the default value and you
are encouraged not to change this for large applications,
since specifying your collaborators explicitly gives you a
feeling for what you're actually doing (always a bonus) and is
a great way of somewhat documenting the structure of your
system.byNameThis option will inspect the objects within the
container, and look for an object named exactly the same as
the property which needs to be autowired. For example, if you
have an object definition that is set to autowire by name, and
it contains a Master property, Spring.NET
will look for an object definition named
Master, and use it as the value of the
Master property on your object
definition.byTypeThis option gives you the ability to resolve
collaborators by type instead of by name. Supposing you have
an IObjectDefinition with a collaborator
typed SqlConnection, Spring.NET will search
the entire object factory for an object definition of type
SqlConnection and use it as the
collaborator. If 0 (zero) or more than 1 (one)
object definitions of the desired type exist in the container,
a failure will be reported and you won't be able to use
autowiring for that specific object.constructorThis is analogous to byType, but
applies to constructor arguments. If there isn't exactly one
object of the constructor argument type in the object factory,
a fatal error is raised.autodetectChooses constructor or
byType through introspection of the
object class. If a default constructor is found,
byType gets applied.
Note that explicit dependencies in property and constructor-arg
settings always override autowiring. Please also note that it is not
currently possible to autowire so-called simple properties such as
primitives, Strings, and Types (and arrays of such simple properties).
(This is by-design and should be considered a feature.) When using
either the byType or constructor autowiring mode, it is possible to wire
arrays and typed-collections. In such cases all autowire candidates
within the container that match the expected type will be provided to
satisfy the dependency. Strongly-typed IDictionaries can even be
autowired if the expected key type is string. An autowired IDictionary
values will consist of all object instances that match the expected
type, and the IDictionary's keys will contain the corresponding object
names.Autowire behavior can be combined with dependency checking, which
will be performed after all autowiring has been completed. It is
important to understand the various advantages and disadvantages of
autowiring. Some advantages of autowiring include:Autowiring can significantly reduce the volume of
configuration required. However, mechanisms such as the use of a
object template (discussed elsewhere in this chapter) are also
valuable in this regard.Autowiring can cause configuration to keep itself up to date
as your objects evolve. For example, if you need to add an
additional dependency to a class, that dependency can be satisfied
automatically without the need to modify configuration. Thus there
may be a strong case for autowiring during development, without
ruling out the option of switching to explicit wiring when the code
base becomes more stable.Some disadvantages of autowiring:Autowiring is more magical than explicit wiring. Although, as
noted in the above table, Spring is careful to avoid guessing in
case of ambiguity which might have unexpected results, the
relationships between your Spring-managed objects are no longer
documented explicitly.Wiring information may not be available to tools that may
generate documentation from a Spring container.Another issue to consider when autowiring by type is that multiple
object definitions within the container may match the type specified by
the setter method or constructor argument to be autowired. For arrays,
collections, or IDictionary, this is not necessarily a problem. However
for dependencies that expect a single value, this ambiguity will not be
arbitrarily resolved. Instead, if no unique object definition is
available, an Exception will be thrown.When deciding whether to use autowiring, there is no wrong or
right answer in all cases. A degree of consistency across a project is
best though; for example, if autowiring is not used in general, it might
be confusing to developers to use it just to wire one or two object
definitions.Checking for dependenciesSpring.NET has the ability to try to check for the existence of
unresolved dependencies of an object deployed into the container. These
are properties of the object, which do not have actual values set for
them in the object definition, or alternately provided automatically by
the autowiring feature.This feature is sometimes useful when you want to ensure that all
properties (or all properties of a certain type) are set on an object.
Of course, in many cases an object class will have default values for
many properties, or some properties do not apply to all usage scenarios,
so this feature is of limited use. Dependency checking can also be
enabled and disabled per object, just as with the autowiring
functionality. The default dependency checking mode is to
not check dependencies. Dependency checking can be
handled in several different modes. In XML-based configuration, this is
specified via the dependency-check attribute in an
object definition, which may have the following values.
Dependency checking modesModeExplanationnoneNo dependency checking. Properties of the object which
have no value specified for them are simply not set.simpleDependency checking is done for primitive types and
collections (this means everything except
collaborators).objectDependency checking is done for collaborators
only.allDependency checking is done for collaborators,
primitive types and collections.
Method InjectionFor most users, the majority of the objects in the container will
be singletons. When a singleton object needs to collaborate with (use)
another singleton object, or a non-singleton object needs to collaborate
with another non-singleton object, the typical and common approach of
handling this dependency (by defining one object to be a property of the
other) is quite adequate. There is however a problem when the object
lifecycles are different. Consider a singleton object A which needs to
use a non-singleton (prototype) object B, perhaps on each method
invocation on A. The container will only create the singleton object A
once, and thus only get the opportunity to set its properties once.
There is no opportunity for the container to provide object A with a new
instance of object B every time one is needed.One solution to this problem is to forego some inversion of
control. Object A can be made aware of the
container by implementing the
IObjectFactoryAware interface, and use programmatic means to ask
the container via a GetObject("B") call for (a
typically new) object B every time it needs it. Find below an admittedly
somewhat contrived example of this approachusing System.Collections;
using Spring.Objects.Factory;
namespace Fiona.Apple
{
public class CommandManager : IObjectFactoryAware
{
private IObjectFactory objectFactory;
public object Process(IDictionary commandState)
{
// grab a new instance of the appropriate Command
Command command = CreateCommand();
// set the state on the (hopefully brand new) Command instance
command.State = commandState;
return command.Execute();
}
// the Command returned here could be an implementation that executes asynchronously, or whatever
protected Command CreateCommand()
{
return (Command) objectFactory.GetObject("command"); // notice the Spring API dependency
}
public IObjectFactory ObjectFactory
{
set { objectFactory = value; }
}
}
}The above example is generally not a desirable solution since the
business code is then aware of and coupled to the Spring Framework.
Method Injection, a somewhat advanced feature of the Spring IoC
container, allows this use case to be handled in a clean fashion.Lookup Method InjectionLookup method injection refers to the ability of the container
to override abstract or concrete methods on
container managed objects, to return the result
of looking up another named object in the container. The lookup will
typically be of a prototype object as in the scenario described above.
The Spring framework implements this method injection by a dynamically
generating a subclass overriding the method using the classes in the
System.Reflection.Emit namespace. You can read more
about the motivation for Method Injection in this blog
entry.So if you look at the code from the previous code snipped (the
CommandManager class), the Spring container is
going to dynamically override the implementation of the
CreateCommand() method. Your
CommandManager class is not going to have any
Spring dependencies, as can be seen in this reworked example
below:using System.Collections;
namespace Fiona.Apple
{
public abstract class CommandManager
{
public object Process(IDictionary commandState)
{
Command command = CreateCommand();
command.State = commandState;
return command.Execute();
}
// okay... but where is the implementation of this method?
protected abstract Command CreateCommand();
}
}In the client class containing the method to be injected (the
CommandManager in this case) the method definition must observe the
following form:<public|protected> [abstract] <return-type> TheMethodName(no-arguments);If the method is abstract, the
dynamically-generated subclass will implement the method. Otherwise,
the dynamically-generated subclass will override the concrete method
defined in the original class. Let's look at an example:<!-- a stateful object deployed as a prototype (non-singleton) -->
<object id="command" class="Fiona.Apple.AsyncCommand, Fiona" singleton="false">
<!-- inject dependencies here as required -->
</object>
<!-- commandProcessor uses a statefulCommandHelpder -->
<object id="commandManager" type="Fiona.Apple.CommandManager, Fiona">
<lookup-method name="CreateCommand" object="command"/>
</object>The object identified as commandManager will
call its own method CreateCommand whenever it needs
a new instance of the command object. It is
important to note that the person deploying the objects must be
careful to deploy the command object as prototype
(if that is actually what is needed). If it is deployed as a singleton the same
instance of singleShotHelper will be returned each
time!Note that lookup method injection can be combined with
Constructor Injection (supplying optional constructor arguments to the
object being constructed), and also with Setter Injection (settings
properties on the object being constructed).Arbitrary method replacementA less commonly useful form of method injection than Lookup
Method Injection is the ability to replace arbitrary methods in a
managed object with another method implementation. Users may safely
skip the rest of this section (which describes this somewhat advanced
feature), until this functionality is actually needed.In an XmlObjectFactory, the
replaced-method element may be used to replace an
existing method implementation with another. Consider the following
class, with a method ComputeValue, which we want to
override:public class MyValueCalculator {
public virtual string ComputeValue(string input) {
// ... some real code
}
// ... some other methods
}A class implementing the
Spring.Objects.Factory.Support.IMethodReplacer
interface is needed to provide the new (injected) method
definition./// <summary>
/// Meant to be used to override the existing ComputeValue(string)
/// implementation in MyValueCalculator.
/// </summary>
public class ReplacementComputeValue : IMethodReplacer
{
public object Implement(object target, MethodInfo method, object[] arguments)
{
// get the input value, work with it, and return a computed result...
string value = (string) arguments[0];
// compute...
return result;
}
}The object definition to deploy the original class and specify
the method override would look like this:<object id="myValueCalculator" type="Examples.MyValueCalculator, ExampleAssembly">
<!-- arbitrary method replacement -->
<replaced-method name="ComputeValue" replacer="replacementComputeValue">
<arg-type match="String"/>
</replaced-method>
</object>
<object id="replacementComputeValue" type="Examples.ReplacementComputeValue, ExampleAssembly"/>One or more contained arg-type elements
within the replaced-method element may be used to
indicate the method signature of the method being overridden. Note
that the signature for the arguments is actually only needed in the
case that the method is actually overloaded and there are multiple
variants within the class. For convenience, the type string for an
argument may be a substring of the fully qualified type name. For
example, all the following would match
System.String. System.String
String
StrSince the number of arguments is often enough to distinguish
between each possible choice, this shortcut can save a lot of typing,
by just using the shortest string which will match an argument.Setting a reference using the members of other objects and
classes.This section details those configuration scenarios that involve
the setting of properties and constructor arguments using the members of
other objects and classes. This kind of scenario is quite common,
especially when dealing with legacy classes that you cannot (or won't)
change to accommodate some of Spring.NET's conventions... consider the
case of a class that has a constructor argument that can only be
calculated by going to say, a database. The
MethodInvokingFactoryObject handles exactly this
scenario ... it will allow you to inject the result of an arbitrary
method invocation into a constructor (as an argument) or as the value of
a property setter. Similarly,
PropertyRetrievingFactoryObject and
FieldRetrievingFactoryObject allow you to retrieve
values from another object's property or field value. These classes
implement the IFactoryObject interface which
indicates to Spring.NET that this object is itself a factory and the
factories product, not the factory itself, is what will be associated
with the object id. Factory objects are discussed further in Setting a reference to the value of property.The PropertyRetrievingFactoryObject is an
IFactoryObject that addresses the scenario of
setting one of the properties and / or constructor arguments of an
object to the value of a property exposed on another object or class.
One can use it to get the value of any public property exposed on either an instance
or a class (in the case of a property exposed on a class, the property
must obviously be static).In the case of a property exposed on an instance, the target
object that a PropertyRetrievingFactoryObject will
evaluate can be either an object instance specified directly inline or
a reference to another arbitrary object. In the case of a static
property exposed on a class, the target object will be the class (the
.NET System.Type) exposing the property.The result of evaluating the property lookup may then be used in
another object definition as a property value or constructor argument.
Note that nested properties are supported for both instance and class
property lookups. The IFactoryObject is discussed
more generally in .Here's an example where a property path is used against another
object instance. In this case, an inner object definition is used and
the property path is nested, i.e. spouse.age. <object name="person" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="age" value="20"/>
<property name="spouse">
<object type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="age" value="21"/>
</object>
</property>
</object>
// will result in 21, which is the value of property 'spouse.age' of object 'person'
<object name="theAge" type="Spring.Objects.Factory.Config.PropertyRetrievingFactoryObject, Spring.Core">
<property name="TargetObject" ref="person"/>
<property name="TargetProperty" value="spouse.age"/>
</object>An example of using a
PropertyRetrievingFactoryObject to evaluate a
static property is shown below.<object id="cultureAware"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="culture" ref="cultureFactory"/>
</object>
<object id="cultureFactory"
type="Spring.Objects.Factory.Config.PropertyRetrievingFactoryObject, Spring.Core">
<property name="StaticProperty">
<value>System.Globalization.CultureInfo.CurrentUICulture, Mscorlib</value>
</property>
</object>Similarly, an example showing the use of an instance property is
shown below.<object id="instancePropertyCultureAware"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="Culture" ref="instancePropertyCultureFactory"/>
</object>
<object id="instancePropertyCultureFactory"
type="Spring.Objects.Factory.Config.PropertyRetrievingFactoryObject, Spring.Core">
<property name="TargetObject" ref="instancePropertyCultureAwareSource"/>
<property name="TargetProperty" value="MyDefaultCulture"/>
</object>
<object id="instancePropertyCultureAwareSource"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests"/>
Setting a reference to the value of field.The FieldRetrievingFactoryObject class
addresses much the same area of concern as the
PropertyRetrievingFactoryObject described in the
previous section. However, as its name might suggest, the
FieldRetrievingFactoryObject class is concerned
with looking up the value of a public
field exposed on either an instance or a class (and similarly, in the
case of a field exposed on a class, the field must obviously be
static).The following example demonstrates using a
FieldRetrievingFactoryObject to look up the value
of a (public, static) field exposed on a class<object id="withTypesField"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="Types" ref="emptyTypesFactory"/>
</object>
<object id="emptyTypesFactory"
type="Spring.Objects.Factory.Config.FieldRetrievingFactoryObject, Spring.Core">
<property name="TargetType" value="System.Type, Mscorlib"/>
<property name="TargetField" value="EmPTytypeS"/>
</object>
The example in the next section demonstrates the look up of a
(public) field exposed on an object instance.<object id="instanceCultureAware"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="Culture" ref="instanceCultureFactory"/>
</object>
<object id="instanceCultureFactory"
type="Spring.Objects.Factory.Config.FieldRetrievingFactoryObject, Spring.Core">
<property name="TargetObject" ref="instanceCultureAwareSource"/>
<property name="TargetField" value="Default"/>
</object>
<object id="instanceCultureAwareSource"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests"/>
Setting a property or constructor argument to the return value
of a method invocation.The MethodInvokingFactoryObject rounds out
the trio of classes that permit the setting of properties and
constructor arguments using the members of other objects and classes.
Whereas the PropertyRetrievingFactoryObject and
FieldRetrievingFactoryObject classes dealt with
simply looking up and returning the value of property or field on an
object or class, the MethodInvokingFactoryObject
allows one to set a constructor or property to the return value of an
arbitrary method invocation,The MethodInvokingFactoryObject class handles
both the case of invoking an (instance) method on another object in
the container, and the case of a static method call on an arbitrary
class. Additionally, it is sometimes necessary to invoke a method just
to perform some sort of initialization.... while the mechanisms for
handling object initialization have yet to be introduced (see ), these
mechanisms do not permit any arguments to be passed to any
initialization method, and are confined to invoking an initialization
method on the object that has just been instantiated by the container.
The MethodInvokingFactoryObject allows one to
invoke pretty much any method on any
object (or class in the case of a static method).The following example (in an XML based
IObjectFactory definition) uses the
MethodInvokingFactoryObject class to force a call
to a static factory method prior to the instantiation of the
object...<object id="force-init"
type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="StaticMethod">
<value>ExampleNamespace.ExampleInitializerClass.Initialize</value>
</property>
</object>
<object id="myService" depends-on="force-init"/> Note
that the definition for the myService object has
used the depends-on attribute to refer to the
force-init object, which will force the
initialization of the force-init object first (and
thus the calling of its configured StaticMethod
static initializer method, when myService is first
initialized. Please note that in order to effect this initialization,
the MethodInvokingFactoryObject object must be operating in
singleton mode (the default.. see the next
paragraph).Note that since this class is expected to be used primarily for
accessing factory methods, this factory defaults to operating in
singleton mode. As such, as soon as all of the
properties for a MethodInvokingFactoryObject object
have been set, and if the
MethodInvokingFactoryObject object is still in
singleton mode, the method will be invoked
immediately and the return value cached for later access. The first
request by the container for the factory to produce an object will
cause the factory to return the cached return value for the current
request (and all subsequent requests). The
IsSingleton property may be set to false, to
cause this factory to invoke the target method each time it is asked
for an object (in this case there is obviously no caching of the
return value).A static target method may be specified by setting the
targetMethod property to a string
representing the static method name, with
TargetType specifying the
Type that the static method is defined on.
Alternatively, a target instance method may be specified, by setting
the TargetObject property to the name of
another Spring.NET managed object definition (the target object), and
the TargetMethod property to the name of the
method to call on that target object.Arguments for the method invocation may be specified in two ways
(or even a mixture of both)... the first involves setting the
Arguments property to the list of arguments
for the method that is to be invoked. Note that the ordering of these
arguments is significant... the order of the values passed to the
Arguments property must be the same as the
order of the arguments defined on the method signature, including the
argument Type. This is shown in the example below
<object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetType" value="Whatever.MyClassFactory, MyAssembly"/>
<property name="TargetMethod" value="GetInstance"/>
<!-- the ordering of arguments is significant -->
<property name="Arguments">
<list>
<value>1st</value>
<value>2nd</value>
<value>and 3rd arguments</value>
<!-- automatic Type-conversion will be performed prior to invoking the method -->
</list>
</property>
</object>The second way involves passing an arguments dictionary to the
NamedArguments property... this dictionary
maps argument names (Strings) to argument values
(any object). The argument names are not case-sensitive, and order is
(obviously) not significant (since dictionaries by definition do not
have an order). This is shown in the example below <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetObject">
<object type="Whatever.MyClassFactory, MyAssembly"/>
</property>
<property name="TargetMethod" value="Execute"/>
<!-- the ordering of named arguments is not significant -->
<property name="NamedArguments">
<dictionary>
<entry key="argumentName"><value>1st</value></entry>
<entry key="finalArgumentName"><value>and 3rd arguments</value></entry>
<entry key="anotherArgumentName"><value>2nd</value></entry>
</dictionary>
</property>
</object>The following example shows how use
MethodInvokingFactoryObject to call an instance
method.<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
<object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetObject" ref="myMethodObject"/>
<property name="TargetMethod" value="Execute"/>
</object> The above example could also have been
written using an anonymous inner object definition... if the object on
which the method is to be invoked is not going to be used outside of
the factory object definition, then this is the preferred idiom
because it limits the scope of the object on which the method is to be
invoked to the surrounding factory object.Finally, if you want to use
MethodInvokingFactoryObject in conjunction with a
method that has a variable length argument list, then please note that
the variable arguments need to be passed (and configured) as a
list. Let us consider the following method
definition that uses the params keyword (in C#),
and its attendant (XML) configuration... [C#]
public class MyClassFactory
{
public object CreateObject(Type objectType, params string[] arguments)
{
return ... // implementation elided for clarity...
}
}<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
<object id="paramsMethodObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetObject" ref="myMethodObject"/>
<property name="TargetMethod" value="CreateObject"/>
<property name="Arguments">
<list>
<value>System.String</value>
<!-- here is the 'params string[] arguments' -->
<list>
<value>1st</value>
<value>2nd</value>
</list>
</list>
</object>Provided IFactoryObject implementationsIn addition to PropertyRetrievingFactoryObject,
MethodInvokingFactoryObject, and
FieldRetrievingFactoryObject Spring.NET comes with
other useful implementations of the IFactoryObject
interface. These are discussed below.Common loggingThe LogFactoryObject is useful when you would
like to share a Common.Logging log object across a number of classes
instead of creating a logging instance per class or class hierarchy.
Information on the Common.Logging project can be found here. In the
example shown below the same logging instance, with a logging category
name of "DAOLogger", is used in both the SimpleAccountDao and
SimpleProductDao data access objects. <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd" >
<object name="daoLogger" type="Spring.Objects.Factory.Config.LogFactoryObject, Spring.Core">
<property name="logName" value="DAOLogger"/>
</object>
<object name="productDao" type="PropPlayApp.SimpleProductDao, PropPlayApp ">
<property name="maxResults" value="100"/>
<property name="dbConnection" ref="myConnection"/>
<property name="log" ref="daoLogger"/>
</object>
<object name="accountDao" type="PropPlayApp.SimpleAccountDao, PropPlayApp ">
<property name="maxResults" value="100"/>
<property name="dbConnection" ref="myConnection"/>
<property name="log" ref="daoLogger"/>
</object>
<object name="myConnection" type="System.Data.Odbc.OdbcConnection, System.Data">
<property name="connectionstring" value="dsn=MyDSN;uid=sa;pwd=myPassword;"/>
</object>
</objects>Object ScopesWhen you create a object definition what you are actually creating
is a recipe for creating actual instances of the class defined by that
object definition. The idea that a object definition is a recipe is
important, because it means that, just like a class, you can potentially
have many object instances created 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 object definition, but also the scope of the objects created
from a particular object definition. This approach is very powerful and
gives you the flexibility to choose the scope of the objects you create
through configuration instead of having to 'bake in' the scope of an
object at the .NET class level. Objects can be defined to be deployed in
one of a number of scopes: out of the box, the Spring Framework supports
exactly five scopes (of which three are available only if you are using a
web-aware ApplicationContext).The scopes supported out of the box are listed below:
Object ScopesScopeDescriptionsingletonScopes a single object definition to a single object
instance per Spring IoC container.prototypeScopes a single object definition to any number of object
instances.requestScopes a single object definition to the lifecycle of a
single HTTP request; that is each and every HTTP request will have
its own instance of an object created off the back of a single
object definition. Only valid in the context of a web-aware Spring
ApplicationContext.sessionScopes a single object definition to the lifecycle of a
HTTP Session. Only valid in the context of a web-aware Spring
ApplicationContext.applicationScopes a single object definition to the lifecycle of a web
application. Only valid in the context of a web-aware Spring
ApplicationContext.
The singleton scopeWhen an object is a singleton, only one shared instance of the
object will be managed, and all requests for objects with an id or ids
matching that object definition will result in that one specific object
instance being returned by the Spring container.To put it another way, when you define an object definition and it
is scoped as a singleton, then the Spring IoC container will create
exactly one instance of the object defined by that object definition.
This single instance will be stored in a cache of such singleton object,
and all subsequent requests and references for that named object will
result in the cached object being returned.Please be aware that Spring's concept of a singleton object is
quite different from the Singleton pattern as defined in the seminal
Gang of Four (GoF) patterns book. The GoF Singleton hard codes the scope
of an object such that one and only one instance of a particular class
will ever be created per ApplicationDomain. The scope of the Spring
singleton is best described as per container and per object. This means
that if you define one object for a particular class in a single Spring
container, then the Spring container will create one and only one
instance of the class defined by that object definition. The singleton
scope is the default scope in Spring. To define an object as a singleton
in XML, you would write configuration like so:<object id="accountService" type="MyApp.DefaultAccountService, MyApp"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<object id="accountService" type="MyApp.DefaultAccountService, MyApp" singleton="true"/>
The prototype scopeThe non-singleton, prototype scope of object deployment results in
the creation of a new object instance every time a request for that
specific object is made (that is, it is injected into another object or
it is requested via a programmatic GetObject() method call on the
container). As a rule of thumb, you should use the prototype scope for
all objects that are stateful, while the singleton scope should be used
for stateless objects.To define an object as a prototype in XML, you would write
configuration like so:<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary" singleton="false"/>There is one quite important thing to be aware of when deploying
an object in the prototype scope, in that the lifecycle of the object
changes slightly. Spring does not manage the complete lifecycle of a
prototype object: the container instantiates, configures, decorates and
otherwise assembles a prototype object, hands it to the client and then
has no further knowledge of that prototype instance. This means that
while initialization lifecycle callback methods
will be called on all objects regardless of scope, in the case of
prototypes, any configured destruction lifecycle
callbacks will not be called. It is the
responsibility of the client code to clean up prototype scoped objects
and release any expensive resources that the prototype object(s) are
holding onto. (One possible way to get the Spring container to release
resources used by singleton-scoped objects is through the use of a
custom object post processor which would hold a reference to the objects
that need to be cleaned up.)In some respects, you can think of the Spring containers role when
talking about a prototype-scoped object as somewhat of a replacement for
the C# 'new' operator. All lifecycle aspects past that point have to be
handled by the client. (The lifecycle of a object in the Spring
container is further described in the section entitled “Lifecycle
callbacks”.)Singleton objecgts with prototype-object dependenciesWhen using singleton-scoped objects that have dependencies on
objects that are scoped as prototypes, please be aware that dependencies
are resolved at instantiation time. This means that if you dependency
inject a prototype-scoped object into a singleton-scoped object, a brand
new prototype object will be instantiated and then dependency injected
into the singleton object... but that is all. That exact same prototype
instance will be the sole instance that is ever supplied to the
singleton-scoped object, which is fine if that is what you want.However, sometimes what you actually want is for the
singleton-scoped object to be able to acquire a brand new instance of
the prototype-scoped object again and again and again at runtime. In
that case it is no use just dependency injecting a prototype-scoped
object into your singleton object, because as explained above, that only
happens once when the Spring container is instantiating the singleton
object and resolving and injecting its dependencies. If you are in the
scenario where you need to get a brand new instance of a (prototype)
object again and again and again at runtime, you are referred to the
section entitled “Method Injection”.The other scopesThe other scopes, namely request, session, and application are for
use only in web-based applications. Please refer to the web documentation on object scopes for
more information.Type conversionType converters are responsible for converting objects from one type
to another. When using the XML based file to configure the IoC container,
string based property values are converted to the target property type.
Spring will rely on the standard .NET support for type conversion unless
an alternative TypeConverter is registered for a given
type. How to register custom TypeConverters will be described shortly. As
a reminder, the standard .NET type converter support works by associating
a TypeConverter attribute with the class definition by
passing the type of the converter as an attribute argument. More information about creating custom
TypeConverter implementations can be found online
at Microsoft's MSDN website, by searching for Implementing a
Type Converter. For example, an abbreviated class definition for the BCL
type Font is shown below. [Serializable, TypeConverter(typeof(FontConverter)), ...]
public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDisposable
{
// Methods
... etc ..
}Type Conversion for EnumerationsThe default type converter for enumerations is the
System.ComponentModel.EnumConverter class. To specify
the value for an enumerated property, simply use the name of the
property. For example the TestObject class has a
property of the enumerated type FileMode. One of the
values for this enumeration is named Create. The
following XML fragment shows how to configure this property<object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="name" value="Rod"/>
<property name="FileMode" value="Create"/>
</object>Built-in TypeConvertersSpring.NET pre-registers a number of custom
TypeConverter instances (for example, to convert a
type expressed as a string into a real System.Type
object). Each of those is listed below and they are all located in the
Spring.Objects.TypeConverters namespace of the
Spring.Core library.
Built-in TypeConvertersTypeExplanationRuntimeTypeConverterParses strings representing
System.Types to actual
System.Types and the other way
around.FileInfoConverterCapable of resolving strings to a
System.IO.FileInfo object.StringArrayConverterCapable of resolving a comma-delimited list of strings
to a string-array and vice versa.UriConverterCapable of resolving a string representation of a Uri
to an actual Uri-object.CredentialConverterCapable of resolving a string representation of a
credential for Web client authentication into an instance of
System.Net.ICredentialsStreamConverterCapable of resolving Spring IResource Uri (string) to
its corresponding
InputStream-object.ResourceConverterCapable of resolving Spring IResource Uri (string) to
an IResource object.ResourceManagerConverterCapable of resolving a two part string (resource name,
assembly name) to a
System.Resources.ResourceManager
object.RgbColorConverterCapable of resolving a comma separated list of Red,
Green, Blue integer values to a
System.Drawing.Color structure.ExpressionConverterCapable of resolving a string into an instance of an
object that implements the IExpression
interface.NameValueConverterCapable of resolving an XML formatted string to a
Specialized.NameValueCollectionRegexConverterCapable of resolving a string into an instance of
RegexRegistryKeyConverterCapable of resolving a string into a
Microsoft.Win32.RegistryKey object.
Spring.NET uses the standard .NET mechanisms for the resolution of
System.Types, including, but not limited to checking
any configuration files associated with your application, checking the
Global Assembly Cache (GAC), and assembly probing.Custom Type ConversionThere are a few ways to register custom type converters. The
fundamental storage area in Spring for custom type converters is the
TypeConverterRegistry class. The most
convenient way if using an XML based implementation of
IObjectFactory or
IApplicationContext is to use the custom
configuration section handler
TypeConverterSectionHandler This is demonstrated in
section An alternate approach, present for legacy reasons in the port of
Spring.NET from the Java code base, is to use the object factory
post-processor
Spring.Objects.Factory.Config.CustomConverterConfigurer.
This is described in the next section.If you are constructing your IoC container Programatically then
you should use the RegisterCustomConverter(Type requiredType,
TypeConverter converter) method of the
ConfigurableObjectFactory interface.Using CustomConverterConfigurerThis section shows in detail how to define a custom type
converter that does not use the .NET TypeConverter
attribute. The type converter class is standalone and inherits from
the TypeConverter class. It uses the legacy factory
post-processor approach.Consider a user class ExoticType, and
another class DependsOnExoticType which needs
ExoticType set as a property:public class ExoticType
{
private string name;
public ExoticType(string name)
{
this.name = name;
}
public string Name
{
get { return this.name; }
}
} and public class DependsOnExoticType
{
public DependsOnExoticType() {}
private ExoticType exoticType;
public ExoticType ExoticType
{
get { return this.exoticType; }
set { this.exoticType = value; }
}
public override string ToString()
{
return exoticType.Name;
}
} When things are properly set up, we want to be able to
assign the type property as a string, which a TypeConverter will
convert into a real ExoticType object behind the scenes:
<object name="sample" type="SimpleApp.DependsOnExoticType, SimpleApp">
<property name="exoticType" value="aNameForExoticType"/>
</object> The TypeConverter looks like this:
public class ExoticTypeConverter : TypeConverter
{
public ExoticTypeConverter()
{
}
public override bool CanConvertFrom (
ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof (string))
{
return true;
}
return base.CanConvertFrom (context, sourceType);
}
public override object ConvertFrom (
ITypeDescriptorContext context,
CultureInfo culture, object value)
{
string s = value as string;
if (s != null)
{
return new ExoticType(s.ToUpper());
}
return base.ConvertFrom (context, culture, value);
}
} Finally, we use the
CustomConverterConfigurer to register the new
TypeConverter with the
IApplicationContext, which will then be able to use
it as needed: <object id="customConverterConfigurer"
type="Spring.Objects.Factory.Config.CustomConverterConfigurer, Spring.Core">
<property name="CustomConverters">
<dictionary>
<entry key="SimpleApp.ExoticType">
<object type="SimpleApp.ExoticTypeConverter"/>
</entry>
</dictionary>
</property>
</object>Customizing the nature of an objectLifecycle interfacesSpring.NET uses several marker interfaces to change the behaviour
of your object in the container, namely the Spring.NET specific
IInitializingObject interface and the standard
System.IDisposable interfaces. Implementing either of
the aforementioned interfaces will result in the container calling the
AfterPropertiesSet() method for the former and the
Dispose() method for the latter, thus allowing you to
do things upon the initialization and destruction of your
objects.Internally, Spring.NET uses implementations of the
IObjectPostProcessor interface to process any marker
interfaces it can find and call the appropriate methods. If you need
custom features or other lifecycle behavior Spring.NET doesn't offer
out-of-the-box, you can implement an
IObjectPostProcessor yourself. More information about
this can be found in .All the different lifecycle marker interfaces are described
below.IInitializingObject / init-methodThe
Spring.Objects.Factory.IInitializingObject
interface gives you the ability to perform initialization work after
all the necessary properties on an object are set by the container.
The IInitializingObject interface specifies exactly
one method: void AfterPropertiesSet(): called
after all properties have been set by the container. This method
enables you to do checking to see if all necessary properties
have been set correctly, or to perform further initialization
work. You can throw anyException to indicate misconfiguration,
initialization failures, etc.Generally, the use of the
IInitializingObject can be avoided. The
Spring.Core library provides support for a
generic init-method, given to the object definition in the object
configuration store (be it XML, or a database, etc).<object id="exampleInitObject" type="Examples.ExampleObject" init-method="init"/>
[C#]
public class ExampleObject
{
public void Init()
{
// do some initialization work
}
} Is exactly the same as... <object id="exampleInitObject" type="Examples.AnotherExampleObject"/>
[C#]
public class AnotherExampleObject : IInitializingObject
{
public void AfterPropertiesSet()
{
// do some initialization work
}
} but does not couple the code to Spring.NET.When deploying an object in prototype mode,
the lifecycle of the object changes slightly. By definition,
Spring.NET cannot manage the complete lifecycle of a non-singleton /
prototype object, since after it is created, it
is given to the client and the container no longer keeps a reference
to the object. You can think of Spring.NET's role when talking about
a non-singleton ( prototype ) object as a
replacement for the new operator. Any lifecycle
aspects past that point have to be handled by the client.IDisposable / destroy-methodThe System.IDisposable interface provides you
with the ability to get a callback when an
IObjectFactory is destroyed. The
IDisposable interface specifies exactly one method:
void Dispose(): and is called on
destruction of the container. This allows you to release any
resources you are keeping in this object (such as database
connections). You can throw anyException here... however, any such
Exception will not stop the destruction of
the container - it will only get logged.Note: If you choose you can avoid having your class
implement IDisposable since the
Spring.Core library provides support for a
generic destroy-method, given to the object definition in the object
configuration store (be it XML, or a database,
etc).<object id="exampleInitObject" type="Examples.ExampleObject" destroy-method="cleanup"/>
[C#]
public class ExampleObject
{
public void cleanup()
{
// do some destruction work (such as closing any open connection (s))
}
} is exactly the same as: <object id="exampleInitObject" type="Examples.AnotherExampleObject"/>
[C#]
public class AnotherExampleObject : IDisposable
{
public void Dispose()
{
// do some destruction work
}
}Knowing who you areIObjectFactoryAwareA class which implements the
Spring.Objects.Factory.IObjectFactoryAware
interface is provided with a reference to the
IObjectFactory that created it. The interface
specifies one (write-only) property: IObjectFactory ObjectFactory: the
property that will be set after the initialization
methods (AfterPropertiesSet and
the init-method).This allows objects to manipulate the
IObjectFactory that created them Programatically,
through the IObjectFactory interface, or by casting
the reference to a known subclass of this which exposes additional
functionality. Primarily this would consist of programmatic retrieval
of other objects. While there are cases when this capability is
useful, it should generally be avoided, since it couples the code to
Spring.NET, and does not follow the Inversion of Control style, where
collaborators are provided to objects as properties.IObjectNameAwareThe Spring.Objects.Factory.IObjectNameAware
interface gives you the ability to let the container set the name of
the object definition on the object instance itself. In those cases
where your object needs to know what its name is, implement this
interface. string ObjectName: the property that
will be set to let the object know what its name is.Object definition inheritanceAn object definition potentially contains a large amount of
configuration information, including container specific information (i.e.
initialization method, static factory method name, etc.) and constructor
arguments and property values. A child object definition is an object
definition that inherits configuration data from a parent definition. It
is then able to override some values, or add others, as needed. Using
parent and child object definitions can potentially save a lot of typing.
Effectively, this is a form of templating.When working with an IObjectFactory
Programatically, child object definitions are represented by the
ChildObjectDefinition class. Most users will never work
with them on this level, instead configuring object definitions
declaratively in something like the XmlObjectFactory.
In an XmlObjectFactory object definition, a child
object definition is indicated simply by using the parent attribute,
specifying the parent object definition as the value of this
attribute.<object id="inheritedTestObject" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</object>
<object id="inheritsWithDifferentClass" type="Spring.Objects.DerivedTestObject, Spring.Core.Tests"
parent="inheritedTestObject" init-method="Initialize">
<property name="name" value="override"/>
<!-- age will inherit value of 1 from parent -->
</object>A child object definition will use the object class from the parent
definition if none is specified, but can also override it. In the latter
case, the child object class must be compatible with the parent, i.e. it
must accept the parent's property values.A child object definition will inherit constructor argument values,
property values and method overrides from the parent, with the option to
add new values. If init method, destroy method and/or static factory
method are specified, they will override the corresponding parent
settings.The remaining settings will always be taken from the child
definition: depends on, autowire
mode, dependency check,
singleton, lazy init.In the case where the parent definition does not specify a
class...<object id="inheritedTestObjectWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</object>
<object id="inheritsWithClass" type="Spring.Objects.DerivedTestObject, Spring.Core.Tests"
parent="inheritedTestObjectWithoutClass" init-method="Initialize">
<property name="name" value="override"/>
<!-- age will inherit value of 1 from parent -->
</object>... the parent object cannot be instantiated on its own since it
incomplete, and it is also explicitly marked as abstract. When a
definition is defined to be abstract like this, it is usable only as a
pure template object definition that will serve as a parent definition for
child definitions. Trying to use such an abstract parent object on its own
(by referring to it as a ref property of another object, or doing an
explicit GetObject() with the parent object id),
will result in an error. The container's internal
PreInstantiateSingletons method will completely
ignore object definitions that are considered abstract.Application contexts (but not simple object factories) will by
default pre-instantiate all singletons. Therefore it is important (at
least for singleton objects) that if you have a (parent) object
definition which you intend to use only as a template, and this
definition specifies a class, you must make sure to set the
abstract attribute to true ,
otherwise the application context will actually (attempt to)
pre-instantiate the abstract object.Interacting with the containerThe Spring container is essentially nothing more than an advanced
factory capable of maintaining a registry of different objects and their
dependencies. The IObjectFactory enables you to read
object definitions and access them using the object factory. When using
just the IObjectFactory you would create an instance of
one and then read in some object definitions in the XML format as follows:
[C#]
IResource input = new FileSystemResource ("objects.xml");
XmlObjectFactory factory = new XmlObjectFactory(input);That is pretty much it. Using GetObject(string)
(or the more concise indexer method factory ["string"])
you can retrieve instances of your objects... [C#]
object foo = factory.GetObject ("foo"); // gets the object defined as 'foo'
object bar = factory ["bar"]; // same thing, just using the indexer
You'll get a reference to the same object if you defined it as a
singleton (the default) or you'll get a new instance each time if you set
the singleton property of your object definition to
false. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>
<object id="anotherObject" type="Examples.ExampleObject, ExamplesLibrary" singleton="false"/>[C#]
object one = factory ["exampleObject"]; // gets the object defined as 'exampleObject'
object two = factory ["exampleObject"];
Console.WriteLine (one == two) // prints 'true'
object three = factory ["anotherObject"]; // gets the object defined as 'anotherObject'
object four = factory ["anotherObject"];
Console.WriteLine (three == four); // prints 'false'
The client-side view of the IObjectFactory is
surprisingly simple. The IObjectFactory interface has
only seven methods (and the aforementioned indexer) for clients to call:
bool ContainsObject(string): returns true
if the IObjectFactory contains an object
definition that matches the given name.object GetObject(string): returns an
instance of the object registered under the given name. Depending on
how the object was configured by the
IObjectFactory configuration, either a singleton
(and thus shared) instance or a newly created object will be
returned. An ObjectsException will be thrown when
either the object could not be found (in which case it'll be a
NoSuchObjectDefinitionException), or an exception
occurred while instantiated and preparing the object.Object this [string]: this is the indexer
for the IObjectFactory interface. It functions in
all other respects in exactly the same way as the
GetObject(string) method. The rest of this
documentation will always refer to the
GetObject(string) method, but be aware that you
can use the indexer anywhere that you can use the
GetObject(string) method.Object GetObject(string, Type): returns an
object, registered under the given name. The object returned will be
cast to the given Type. If the object could not
be cast, corresponding exceptions will be thrown
(ObjectNotOfRequiredTypeException). Furthermore,
all rules of the GetObject(string) method apply
(see above).bool IsSingleton(string): determines
whether or not the object definition registered under the given name
is a singleton or a prototype. If the object definition
corresponding to the given name could not be found, an exception
will be thrown
(NoSuchObjectDefinitionException)string[] GetAliases(string): returns the
aliases for the given object name, if any were defined in the
IObjectDefinition.void ConfigureObject(object target):
Injects dependencies into the supplied target instance. The name of
the abstract object definition is the
System.Type.FullName of the target instance. This
method is typically used when objects are instantiated outside the
control of a developer, for example when ASP.NET instantiates web
controls and when a WinForms application creates
UserControls.void ConfigureObject(object target, string
name): Offers the same functionality as the previously
listed Configure method but uses a named object definition instead
of using the type's full name.A sub-interface of IObjectFactory,
IConfigurableObjectFactory adds some convenient methods
such asvoid RegisterSingleton(string name, object
objectInstance) : Register the given existing object as
singleton in the object factory under the given object name.void RegisterAlias(string name, string
theAlias); Given an object name, create an alias.Check the SDK docs for additional details on
IConfigurableObjectFactory methods and properties and the full
IObjectFactory class hierarchy.Obtaining an IFactoryObject, not its
productSometimes there is a need to ask an
IObjectFactory for an actual
IFactoryObject instance itself, not the object it
produces. This may be done by prepending the object id with
& when calling the
GetObject method of the
IObjectFactory and
IApplicationContext interfaces. So for a given
IFactoryObject with an id
myObject, invoking
GetObject("myObject") on the
IObjectFactory will return the product of the
IFactoryObject, but invoking
GetObject("&myObject") will return the
IFactoryObject instance itself.Container extension pointsThe IoC component of the Spring Framework has been designed for
extension. There is typically no need for an application developer to
subclass any of the various IObjectFactory or
IApplicationContext implementation classes. The Spring
IoC container can be infinitely extended by plugging in implementations of
special integration interfaces. The next few sections are devoted to
detailing all of these various integration interfaces.Customizing objects with
IObjectPostProcessorsThe first extension point that we will look at is the
Spring.Objects.Factory.Config.IObjectPostProcessor
interface. This interface defines a number of callback methods that you
as an application developer can implement in order to provide your own
(or override the containers default) instantiation logic,
dependency-resolution logic, and so forth. If you want to do some custom
logic after the Spring container has finished instantiating, configuring
and otherwise initializing an object, you can plug in one or more
IObjectPostProcessor implementations.You can configure multiple
IObjectPostProcessors if you wish. You can control
the order in which these IObjectPostProcessor execute
by setting the 'Order' property (you can only set this property if the
IObjectPostProcessor implements the
IOrdered interface; if you write your own
IObjectPostProcessor you should consider implementing
the IOrdered interface too); consult the SDK docs for
the IObjectPostProcessor and
IOrdered interfaces for more details.IObjectPostProcessor operate on object
instances; that is to say, the Spring IoC container will have
instantiated a object instance for you, and then
IObjectPostProcessors get a chance to do their
stuff. If you want to change the actual object definition (that is the
recipe that defines the object), then you rather need to use a
IObjectFactoryPostProcessor (described below in the
section entitled Customizing
configuration metadata with
IObjectFactoryPostProcessors.Also, IObjectPostProcessors are scoped
per-container. This is only relevant if you are using container
hierarchies. If you define a IObjectPostProcessor
in one container, it will only do its stuff on the objects in that
container. Objects that are defined in another container will not be
post-processed by IObjectPostProcessors in another
container, even if both containers are part of the same
hierarchy.The
Spring.Objects.Factory.Config.IObjectPostProcessor
interface, which consists of two callback methods shown below.
object PostProcessBeforeInitialization(object instance, string name);
object PostProcessAfterInitialization(object instance, string name);When
such a class is registered as a post-processor with the container, for
each object instance that is created by the container,(see below for how
this registration is effected), for each object instance that is created
by the container, the post-processor will get a callback from the
container both before any initialization methods
(such as the AfterPropertiesSet method of the
IInitializingObject interface and any declared init
method) are called, and also afterwards. The post-processor is free to
do what it wishes with the object, including ignoring the callback
completely. An object post-processor will typically check for marker
interfaces, or do something such as wrap an object with a proxy. Some
Spring.NET AOP infrastructure classes are implemented as object
post-processors as they do this proxy-wrapping logic.Other extensions to the IObjectPostProcessors
interface are IInstantiationAwareObjectPostProcessor
and IDestructionAwareObjectPostProcessor defined
below public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor
{
object PostProcessBeforeInstantiation(Type objectType, string objectName);
bool PostProcessAfterInstantiation(object objectInstance, string objectName);
IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, PropertyInfo[] pis, object objectInstance, string objectName);
}
public interface IDestructionAwareObjectPostProcessor : IObjectPostProcessor
{
void PostProcessBeforeDestruction (object instance, string name);
} The PostProcessBeforeInstantiation
callback method is called right before the container creates the object.
If the object returned by this method is not null then the default
instantiation behavior of the container is short circuited. The returned
object is the one registered with the container and no other
IObjectPostProcessor callbacks will be invoked on it.
This mechanism is useful if you would like to expose a proxy to the
object instead of the actual target object. The
PostProcessAfterInstantiation callback method is
called after the object has been instantiated but before Spring performs
property population based on explicit properties or autowiring. A return
value of false would short circuit the standard Spring based property
population. The callback method
PostProcessPropertyValues is called after Spring
collects all the property values to apply to the object, but before they
are applied. This gives you the opportunity to perform additional
processing such as making sure that a property is set to a value if it
contains a [Required] attribute or to perform
attribute based wiring, i.e. adding the attribute
[Inject("objectName")] on a property. Both of these
features are scheduled to be included in Spring .12.The IDestructionAwareObjectPostProcessor
callback contains a single method,
PostProcessBeforeDestruction, which is called before
a singleton's destroy method is invoked.It is important to know that the IObjectFactory
treats object post-processors slightly differently than the
IApplicationContext. An
IApplicationContext will automatically detect any
objects which are deployed into it that implement the
IObjectPostProcessor interface, and register them as
post-processors, to be then called appropriately by the factory on
object creation. Nothing else needs to be done other than deploying the
post-processor in a similar fashion to any other object. On the other
hand, when using plain IObjectFactories, object
post-processors have to manually be explicitly registered, with a code
sequence such as... ConfigurableObjectFactory factory = new .....; // create an IObjectFactory
... // now register some objects
// now register any needed IObjectPostProcessors
MyObjectPostProcessor pp = new MyObjectPostProcessor();
factory.AddObjectPostProcessor(pp);
// now start using the factory
...This explicit registration step is not convenient, and this is one
of the reasons why the various IApplicationContext
implementations are preferred above plain
IObjectFactory implementations in the vast majority
of Spring-backed applications, especially when using
IObjectPostProcessors.IObjectPostProcessors and AOP auto-proxyingClasses that implement the
IObjectPostProcessor interface are special, and so
they are treated differently by the container. All
IObjectPostProcessors and their directly referenced
object will be instantiated on startup, as part of the special startup
phase of the IApplicationContext, then all those
IObjectPostProcessors will be registered in a
sorted fashion - and applied to all further objects. Since AOP
auto-proxying is implemented as a
IObjectPostProcessor itself, no
IObjectPostProcessors or directly referenced
objects are eligible for auto-proxying (and thus will not have aspects
'woven' into them). For any such object, you should see an info log
message: “Object 'foo' is not eligible for getting processed by all
IObjectPostProcessors (for example: not eligible
for auto-proxying)”.Example: Hello World, IObjectPostProcessor-styleThis first example is hardly compelling, but serves to
illustrate basic usage. All we are going to do is code a custom
IObjectPostProcessor implementation that simply invokes the ToString()
method of each object as it is created by the container and prints the
resulting string to the system console. Yes, it is not hugely useful,
but serves to get the basic concepts across before we move into the
second example which is actually useful. The basis of the example is
the MovieFinder quickstart that is included with the Spring.NET
distribution.Find below the custom IObjectPostProcessor implementation class
definitionusing System;
using Spring.Objects.Factory.Config;
namespace Spring.IocQuickStart.MovieFinder
{
public class TracingObjectPostProcessor : IObjectPostProcessor
{
public object PostProcessBeforeInitialization(object instance, string name)
{
return instance;
}
public object PostProcessAfterInitialization(object instance, string name)
{
Console.WriteLine("Object '" + name + "' created : " + instance.ToString());
return instance;
}
}
}And the following configuration<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" >
<description>An example that demonstrates simple IoC features.</description>
<object id="MyMovieLister"
type="Spring.IocQuickStart.MovieFinder.MovieLister, Spring.IocQuickStart.MovieFinder">
<property name="movieFinder" ref="MyMovieFinder"/>
</object>
<object id="MyMovieFinder"
type="Spring.IocQuickStart.MovieFinder.SimpleMovieFinder, Spring.IocQuickStart.MovieFinder"/>
<!-- when the above objects are instantiated, this custom IObjectPostProcessor implementation
will output the fact to the system console -->
<object type="Spring.IocQuickStart.MovieFinder.TracingObjectPostProcessor, Spring.IocQuickStart.MovieFinder"/>
</objects>Notice how the TracingObjectPostProcessor is simply defined; it
doesn't even have a name, and because it is a object it can be
dependency injected just like any other object.Find below a small driver script to exercise the above code and
configuration;IApplicationContext ctx =
new XmlApplicationContext(
"assembly://Spring.IocQuickStart.MovieFinder/Spring.IocQuickStart.MovieFinder/AppContext.xml");
MovieLister lister = (MovieLister) ctx.GetObject("MyMovieLister");
Movie[] movies = lister.MoviesDirectedBy("Roberto Benigni");
LOG.Debug("Searching for movie...");
foreach (Movie movie in movies)
{
LOG.Debug(string.Format("Movie Title = '{0}', Director = '{1}'.", movie.Title, movie.Director));
}
LOG.Debug("MovieApp Done.");The output of executing the above
program will be:INFO - Object 'Spring.IocQuickStart.MovieFinder.TracingObjectPostProcessor' is not eligible for being processed by all IObjectPostProcessors
(for example: not eligible for auto-proxying).
Object 'MyMovieFinder' created : Spring.IocQuickStart.MovieFinder.SimpleMovieFinder
Object 'MyMovieLister' created : Spring.IocQuickStart.MovieFinder.MovieLister
DEBUG - Searching for movie...
DEBUG - Movie Title = 'La vita e bella', Director = 'Roberto Benigni'.
DEBUG - MovieApp Done.Example: the RequiredAttributeObjectPostProcessorUsing callback interfaces or annotations in conjunction with a
custom IObjectPostProcessor implementation is a common means of
extending the Spring IoC container. The [Required]
attribute in the Spring.Objects.Factory.Attributes
namespace can be used to mark a property as
being 'required-to-be-set' (i.e. an setter
property with this attribute applied must be configured to be
dependency injected with a value), else an
ObjectInitializationException will be thrown by the
container at runtime.The best way to illustrate the usage of this attribute is with
an example.public class MovieLister
{
// the MovieLister has a dependency on the MovieFinder
private IMovieFinder _movieFinder;
// a setter property so that the Spring container can 'inject' a MovieFinder
[Required]
public IMovieFinder MovieFinder
{
set { _movieFinder = value; }
}
// business logic that actually 'uses' the injected MovieFinder is omitted...
}Hopefully the above class definition reads easy on the eye. Any
and all IObjectDefinitions for the
MovieLister class must be provided with a
value.Let's look at an example of some XML configuraiton that will not
pass validation.<object id="MyMovieLister"
type="Spring.IocQuickStart.MovieFinder.MovieLister, Spring.IocQuickStart.MovieFinder">
<!-- whoops, no MovieFinder is set (and this property is [Required]) -->
</object>At runtime the following message will be generated by the Spring
containerError creating context 'spring.root': Property 'MovieFinder' required for object 'MyMovieLister'There is one last little piece of Spring configuration that is
required to actually 'switch on' this behavior. Simply annotating the
'setter' properties of your classes is not enough to get this
behavior. You need to enable a component that is aware of the
[Required] attribute and that can process it
appropriately.This component is the
RequiredAttributeObjectPostProcessor class. This is
a special IObjectPostProcessor implementation that
is [Required]-aware and actually provides the 'blow
up if this required property has not been set' logic. It is very easy
to configure; simply drop the following object definition into your
Spring XML configuration.<object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core"/>Finally, one can configure an instance of the
RequiredAttributeObjectPostProcessor class to look
for another Attribute type. This is great if you
already have your own [Required]-style attribute.
Simply plug it into the definition of a
RequiredAttributeObjectPostProcessor and you are
good to go. By way of an example, let's suppose you (or your
organization / team) have defined an attribute called [Mandatory]. You
can make a RequiredAttributeObjectPostProcessor
instance [Mandatory]-aware like so:<object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core">
<property name="RequiredAttributeType" value="MyApp.Attributes.MandatoryAttribute, MyApp"/>
</object>Customizing configuration metadata with
ObjectFactoryPostProcessorsThe next extension point that we will look at is the
Spring.Objects.Factory.Config.IObjectFactoryPostProcessor.
The semantics of this interface are similar to the
IObjectPostProcessor, with one major difference.
IObjectFactoryPostProcessors operate on; that is to
say, the Spring IoC container will allow
IObjectFactoryPostProcessors to read the
configuration metadata and potentially change it before the container
has actually instantiated any other objects. By implementing this
interface, you will receive a callback after the all the object
definitions have been loaded into the IoC container but before they have
been instantiated. The signature of the interface is shown below
public interface IObjectFactoryPostProcessor
{
void PostProcessObjectFactory (IConfigurableListableObjectFactory factory);
}
You can configure multiple
IObjectFactoryPostProcessors if you wish. You can
control the order in which these
IObjectFactoryPostProcessors execute by setting the
'Order' property (you can only set this property if the
IObjectFactoryPostProcessors implements the
IOrdered interface; if you write your own
IObjectFactoryPostProcessors you should consider
implementing the IOrdered interface too); consult the
SDK docs for the IObjectFactoryPostProcessors and
IOrdered interfaces for more details.If you want to change the actual object instances (the objects
that are created from the configuration metadata), then you rather
need to use a IObjectObjectPostProcessor (described
above in the section entitled Customizing objects with
IObjectPostProcessors.Also, IObjectFactoryPostProcessors are scoped
per-container. This is only relevant if you are using container
hierarchies. If you define a
IObjectFactoryPostProcessors in one container, it
will only do its stuff on the object definitions in that container.
Object definitions in another container will not be post-processed by
IObjectFactoryPostProcessors in another container,
even if both containers are part of the same hierarchy.An object factory post-processor is executed manually (in the case
of a IObjectFactory) or automatically (in the case of an
IApplicationContext) to apply changes of some sort to the configuration
metadata that defines a container. Spring.NET includes a number of
pre-existing object factory post-processors, such as
PropertyResourceConfigurer and
PropertyPlaceHolderConfigurer, both described below
and ObjectNameAutoProxyCreator, which is very useful for wrapping other
objects transactionally or with any other kind of proxy, as described
later in this manual.In an IObjectFactory, the process of applying
an IObjectFactoryPostProcessor is manual, and will be
similar to this:XmlObjectFactory factory = new XmlObjectFactory(new FileSystemResource("objects.xml"));
// create placeholderconfigurer to bring in some property
// values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("ado.properties"));
// now actually do the replacement
cfg.PostProcessObjectFactory(factory);This
explicit registration step is not convenient, and this is one of the
reasons why the various IApplicationContext
implementations are preferred above plain
IObjectFactory implementations in the vast majority
of Spring-backed applications, especially when using
IObjectFactoryPostProcessors.An IApplicationContext will detect any objects
which are deployed into it that implement the
ObjectFactoryPostProcessor interface, and
automatically use them as object factory post-processors, at the
appropriate time. Nothing else needs to be done other than deploying
these post-processor in a similar fashion to any other object.Just as in the case of IObjectPostProcessors,
you typically don't want to have
IObjectFactoryPostProcessors marked as being
lazily-initialized. If they are marked as such, then the Spring
container will never instantiate them, and thus they won't get a
chance to apply their custom logic. If you are using the
'default-lazy-init' attribute on the declaration of your
<objects/> element, be sure to mark your various
IObjectFactoryPostProcessor object definitions with
'lazy-init="false"'.Example: The
PropertyPlaceholderConfigurerThe PropertyPlaceholderConfigurer is an
excellent solution when you want to externalize a few properties from
a file containing object definitions. This is useful to allow the
person deploying an application to customize environment specific
properties (for example database configuration strings, usernames, and
passwords), without the complexity or risk of modifying the main XML
definition file or files for the container.Variable substitution is performed on simple property values,
lists, dictionaries, sets, constructor values, object type name, and
object names in runtime object references. Furthermore, placeholder
values can also cross-reference other placeholders.Note that IApplicationContexts are able to
automatically recognize and apply objects deployed in them that
implement the IObjectFactoryPostProcessor
interface. This means that as described here, applying a
PropertyPlaceholderConfigurer is much more
convenient when using an IApplicationContext. For
this reason, it is recommended that users wishing to use this or other
object factory postprocessors use an
IApplicationContext instead of an
IObjectFactory.In the example below a data access object needs to be configured
with a database connection and also a value for the maximum number of
results to return in a query. Instead of hard coding the values into
the main Spring.NET configuration file we use place holders, in the
NAnt style of ${variableName}, and obtain their values from
NameValueSections in the standard .NET application configuration file.
The Spring.NET configuration file looks like: <configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
<section name="DaoConfiguration" type="System.Configuration.NameValueSectionHandler"/>
<section name="DatabaseConfiguration" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<DaoConfiguration>
<add key="maxResults" value="1000"/>
</DaoConfiguration>
<DatabaseConfiguration>
<add key="connection.string" value="dsn=MyDSN;uid=sa;pwd=myPassword;"/>
</DatabaseConfiguration>
<spring>
<context>
<resource uri="assembly://DaoApp/DaoApp/objects.xml"/>
</context>
</spring>
</configuration>Notice the presence of two NameValueSections in the
configuration file. These name value pairs will be referred to in the
Spring.NET configuration file. In this example we are using an
embedded assembly resource for the location of the Spring.NET
configuration file so as to reduce the chance of accidental tampering
in deployment. This Spring.NET configuration file is shown
below.<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd" >
<object name="productDao" type="DaoApp.SimpleProductDao, DaoApp ">
<property name="maxResults" value="${maxResults}"/>
<property name="dbConnection" ref="myConnection"/>
</object>
<object name="myConnection" type="System.Data.Odbc.OdbcConnection, System.Data">
<property name="connectionstring" value="${connection.string}"/>
</object>
<object name="appConfigPropertyHolder"
type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="configSections">
<value>DaoConfiguration,DatabaseConfiguration</value>
</property>
</object>
</objects>The values of ${maxResults} and
${connection.string} match the key names used in
the two NameValueSectionHandlers DaoConfiguration
and DatabaseConfiguration. The
PropertyPlaceholderConfigurer refers to these two
sections via a comma delimited list of section names in the
configSections property. If you are using section
groups, prefix the section group name, for example
myConfigSection/DaoConfiguraiton.The PropertyPlaceholderConfigurer class also
supports retrieving name value pairs from other
IResource locations. These can be specified using
the Location and Locations
properties of the PropertyPlaceHolderConfigurer
class.If there are properties with the same name in different resource
locations the default behavior is that the last property processed
overrides the previous values. This is behavior is controlled by the
LastLocationOverrides property. True enables
overriding while false will append the values as one would normally
expect using NameValueCollection.Add.In an ASP.NET environment you must specify the full, four-part
name of the assembly when using a
NameValueFileSectionHandler
<section name="hibernateConfiguration"
type="System.Configuration.NameValueFileSectionHandler, System,
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
Type, Ref, and Expression substitutionThe PropertyPlaceholderConfigurer can be used to substitute
type names, which is sometimes useful when you have to pick a
particular implementation class at runtime. For example:<object id="MyMovieFinder" type="${custom.moviefinder.type}"/>If the class is unable to be resolved at runtime to a valid
type, resolution of the object will fail once it is about to be
created (which is during the PreInstantiateSingletons() phase of an
ApplicationContext for a non-lazy-init object.)Similarly you can replace 'ref' and 'expression' metadata, as
shown below<object id="TestObject" type="Simple.TestObject, MyAssembly">
<property name="age" expression="${ageExpression}"/>
<property name="spouse" ref="${spouse-ref}"/>
</object>Replacement with Environment VariablesYou may also use the value environment variables to replace
property placeholders. The use of environment variables is
controlled via the property
EnvironmentVariableMode. This property is an
enumeration of the type EnvironmentVariablesMode
and has three values, Never, Fallback, and Override.
Fallback is the default value and will resolve a
property placeholder if it was not already done so via a value from
a resource location. Override will apply
environment variables before applying values defined from a resource
location. Never will, quite appropriately,
disable environment variable substitution. An example of how the
PropertyPlaceholderConfigurer XML is modified to
enable override usage is shown below <object name="appConfigPropertyHolder"
type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="configSections" value="DaoConfiguration,DatabaseConfiguration"/>
<property name="EnvironmentVariableMode" value="Override"/>
</object>
</objects>Example: The
PropertyOverrideConfigurerThe PropertyOverrideConfigurer, another
object factory post-processor, is similar to the
PropertyPlaceholderConfigurer, but in contrast to
the latter, the original definitions can have default values or no
values at all for object properties. If an overriding configuration
file does not have an entry for a certain object property, the default
context definition is used.Note that the object factory definition is
not aware of being overridden, so it is not
immediately obvious when looking at the XML definition file that the
override configurer is being used. In case that there are multiple
PropertyOverrideConfigurer instances that define
different values for the same object property, the last one will win
(due to the overriding mechanism).The example usage is similar to when using
PropertyPlaceHolderConfigurer except that the key
name refers to the name given to the object in the Spring.NET
configuration file and is suffixed via 'dot' notation with the name of
the property For example, if the application configuration file is
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
<section name="DaoConfigurationOverride" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<DaoConfigurationOverride>
<add key="productDao.maxResults" value="1000"/>
</DaoConfigurationOverride>
<spring>
<context>
<resource uri="assembly://DaoApp/DaoApp/objects.xml"/>
</context>
</spring>
</configuration> Then the value of 1000 will be used to
overlay the value of 2000 set in the Spring.NET configuration file
shown below <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd" >
<object name="productDao" type="PropPlayApp.SimpleProductDao, PropPlayApp " >
<property name="maxResults" value="2000"/>
<property name="dbConnection" ref="myConnection"/>
<property name="log" ref="daoLog"/>
</object>
<object name="daoLog" type="Spring.Objects.Factory.Config.LogFactoryObject, Spring.Core">
<property name="logName" value="DAOLogger"/>
</object>
<object name="myConnection" type="System.Data.Odbc.OdbcConnection, System.Data">
<property name="connectionstring">
<value>dsn=MyDSN;uid=sa;pwd=myPassword;</value>
</property>
</object>
<object name="appConfigPropertyOverride" type="Spring.Objects.Factory.Config.PropertyOverrideConfigurer, Spring.Core">
<property name="configSections">
<value>DaoConfigurationOverride</value>
</property>
</object>
</objects>IVariableSourceThe IVariableSource is the base interface for providing the
ability to get the value of property placeholders (name-value) pairs
from a variety of sources. Out of the box, Spring.NET supports a
number of variable sources that allow users to obtain variable values
from .NET config files, java-style property files, environment
variables, command line arguments and the registry and the new
connection strings configuration section in .NET 2.0. The list of
implementing classes is listed below. Please refer to the SDK
documentation for more information.ConfigSectionVariableSourcePropertyFileVariableSourceEnvironmentVariableSourceCommandLineArgsVariableSourceRegistryVariableSourceSpecialFolderVariableSourceConnectionStringsVariableSourceYou use this by defining an instance of
Spring.Objects.Factory.Config.VariablePlaceholderConfigurer
in your configuration and set the property
VariableSource to a single
IVariableSource instance or the list property
VariableSources to a list of
IVariableSource instances. In the case of the same
property defined in multiple IVariableSource
implementations, the first one in the list that contains the property
value will be used. <object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
<property name="VariableSources">
<list>
<object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core">
<property name="SectionNames" value="CryptedConfiguration" />
</object>
</list>
</property>
</object>
The IVariableSource interface is shown belowpublic interface IVariableSource
{
string ResolveVariable(string name);
}This is a simple contract to implement if you should decide to
create your own custom implemention. Look at the source code of the
current implementations for some inspiration if you go that route. To
register your own custom implemenation, simply configure
VariablePlaceholderConfigurer to refer to your class.Customizing instantiation logic using
IFactoryObjectsThe Spring.Objects.Factory.IFactoryObject
interface is to be implemented by objects that are themselves
factories.The IFactoryObject interface is a point of
pluggability into the Spring IoC containers instantiation logic. If you
have some complex initialization code that is better expressed in C# as
opposed to a (potentially) verbose amount of XML, you can create your
own IFactoryObject, write the complex initialization
inside that class, and then plug your custom
IFactoryObject into the container.The IFactoryObject interface provides one
method and two (read-only) properties: object GetObject(): has to return an
instance of the object this factory creates. The instance can
possibly be shared (depending on whether this factory provides
singletons or prototypes).bool IsSingleton: has to return
true if this IFactoryObject returns singletons,
false otherwise.Type ObjectType: has to return either the
object type returned by the GetObject()
method or null if the type isn't known in
advance.IFactoryObjectThe IFactoryObject concept and interface is used in a number of
places within the Spring Framework. Some examples of its use is
described in for the
PropertyRetrievingFactoryObject and
FieldRetrievingFactoryObject. An additional use of
creating an custom IFactoryObject implementation is to retrieve an
object from an embedded resource file and use it to set another objects
dependency. An example of this is provided here.Finally, there is sometimes a need to ask a container for an
actual IFactoryObject instance itself, not the object
it produces. This may be achieved by prepending the object id with
'&' (sans quotes) when calling the
GetObject method of the
IObjectFactory (including
IApplicationContext). So for a given
IFactoryObject with an id of
'myObject', invoking
GetObject("myObject") on the container will return
the product of the IFactoryObject, but invoking
GetObject("&myObject") will return the
IFactoryObject instance itself.IConfigurableFactoryObjectThe
Spring.Objects.Factory.IConfigurableFactoryObject
interface inherits from IFactoryObject interface
and adds the following property. IObjectDefinition ProductTemplate :
Gets the template object definition that should be used to
configure the instance of the object managed by this
factory.IConfigurableFactoryObject implementions you
already have examples of in are
WebServiceProxyFactory.The IApplicationContextWhile the Spring.Objects namespace provides basic
functionality for managing and manipulating objects, often in a
programmatic way, the Spring.Context namespace
introduces the IApplicationContext interface, which
enhances the functionality provided by the
IObjectFactory interface in a more
framework-oriented style. Many users will use
ApplicationContext in a completely declarative fashion, not even having to
create it manually, but instead relying on support classes such as the
.NET configuration section handlers such as ContextHandler and
WebContextHandler together to declaratively define the ApplicationContext
and retrieve it though a ContextRegistry. (Of course it is still possible
to create an IApplicationContext
Programatically).The basis for the context module is the
IApplicationContext interface, located in the
Spring.Context namespace. Deriving from the
IObjectFactory interface, it provides all the
functionality of the IObjectFactory. To be able to work
in a more framework-oriented fashion, using layering and hierarchical
contexts, the Spring.Context namespace also provides
the following functionalityLoading of multiple (hierarchical)
contexts, allowing some of them to be focused and used on
one particular layer, for example the web layer of an
application.Access to localized resources at the
application level by implementing
IMessageSource.Uniform access to resources that can be
read in as an InputStream, such as URLs and files by implementing
IResourceLoaderLoosely Coupled Event Propagation.
Publishers and subscribers of events do not have to be directly
aware of each other as they register their interest indirectly
through the application context.IObjectFactory or IApplicationContext?Short version: use an
IApplicationContext unless you
have a really good reason for not doing so. For those of you that are
looking for slightly more depth as to the 'but why' of the above
recommendation, keep reading.As the IApplicationContext includes all the
functionality the object factory via its inheritance of the
IObjectFactory interface, it is generally recommended
to be used over the IObjectFactory except for a few
limited situations where memory consumption might be critical. This may
become more important if the .NET Compact Framework is supported. The
history of IObjectFactory comes from the Spring Java
framework, where the use of Spring in Applets was a concern to reduce
memory consumption. However, for most 'typical' enterprise applications
and systems, the IApplicationContext is what you will
want to use. Spring generally makes heavy use of the
IObjectPostProcessor extension point (to effect
proxying and suchlike), and if you are using just a plain
IObjectFactory then a fair amount of support such as
transactions and AOP will not take effect (at least not without some
extra steps on your part), which could be confusing because nothing will
actually be wrong with the configuration.Find below a feature matrix that lists what features are provided
by the IObjectFactory and
IApplicationContext interfaces (and attendant
implementations). The following sections describe functionality that
IApplicationContext adds to the basic
IObjectFactory capabilities in a lot more depth than
the said feature matrix.)
Feature MatrixFeatureIObjectFactoryIApplicationContextObject instantiation/wiringYesYesAutomatic IObjectPostProcessor
registrationNoYesAutomatic
IObjectFactoryPostProcessor
registrationNoYesConvenient IMessageSource
accessNoYesApplicationEvent
publicationNoYesSingleton service locator style accessNoYesDeclarative registration of custom resource protocol
handler, XML Parsers for object definitions, and type
aliasesNoYes
Configuration of IApplicationContextWell known locations in the .NET application configuration file are
used to register resource handlers, custom parsers, type alias, and custom
type converts in addition to the context and objects sections mentioned
previously. A sample .NET application configuration file showing all these
features is shown below. Each section requires the use of a custom
configuration section handler. Note that the types shown for resource
handlers and parsers are fictional. <configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
<section name="resources" type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
<section name="typeAliases" type="Spring.Context.Support.TypeAliasesSectionHandler, Spring.Core"/>
<section name="typeConverters" type="Spring.Context.Support.TypeConvertersSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
<parsers>
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
</parsers>
<resources>
<handler protocol="db" type="MyCompany.MyApp.Resources.MyDbResource"/>
</resources>
<context caseSensitive="false">
<resource uri="config://spring/objects"/>
<resource uri="db://user:pass@dbName/MyDefinitionsTable"/>
</context>
<typeAliases>
<alias name="WebServiceExporter" type="Spring.Web.Services.WebServiceExporter, Spring.Web"/>
<alias name="DefaultPointcutAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop"/>
<alias name="AttributePointcut" type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop"/>
<alias name="CacheAttribute" type="Spring.Attributes.CacheAttribute, Spring.Core"/>
<alias name="MyType" type="MyCompany.MyProject.MyNamespace.MyType, MyAssembly"/>
</typeAliases>
<typeConverters>
<converter for="Spring.Expressions.IExpression, Spring.Core" type="Spring.Objects.TypeConverters.ExpressionConverter, Spring.Core"/>
<converter for="MyTypeAlias" type="MyCompany.MyProject.Converters.MyTypeConverter, MyAssembly"/>
</typeConverters>
<objects xmlns="http://www.springframework.net">
...
</objects>
</spring>
</configuration>
The new sections are described below. The attribute
caseSensitive allows the for both
IObjectFactory and
IApplicationContext implementations to not pay
attention to the case of the object names. This is important in web
applications so that ASP.NET pages can be resolved in a case independent
manner. The default value is true.Registering custom parsersInstead of using the default XML schema that is generic in nature
to define an object's properties and dependencies, you can create your
own XML schema specific to an application domain. This has the benefit
of being easier to type and getting XML intellisense for the schema
being used. The downside is that you need to write code that will
transform this XML into Spring object definitions. One would typically
implement a custom parser by deriving from the class
ObjectsNamespaceParser and overriding the methods
int ParseRootElement(XmlElement root, XmlResourceReader
reader) and int ParseElement(XmlElement element,
XmlResourceReader reader). Registering custom parsers outside
of App.config will be addressed in a future release.To register a custom parser register a section handler of the type
Spring.Context.Support.NamespaceParsersSectionHandler
in the configSecitons section of App.config. The parser configuration
section contains one or more <parser> elements each with a type
attribute. Below is an example that registers all the namespaces
provided in Spring.As of Spring.NET 1.2.0 it is no longer necessary to explicitly
configure the namespace parsers that come with Spring via a custom
section in App.config. You will still need to register custom
namespace parsers if you are writing your own.<configuration>
<configSections>
<sectionGroup name="spring">
<!-- other configuration section handler defined here -->
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
<parsers>
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
<parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />
<parser type="Spring.Validation.Config.ValidationNamespaceParser, Spring.Core" />
<parser type="Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services" />
</parsers>
</spring>
</configuration>You can also register custom parser programmatically using the
NamespaceParserRegistry. Here is an example taken from the code used in
the Transactions Quickstart application.NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
IApplicationContext context =
new XmlApplicationContext("assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/system-test-local-config.xml");Registering custom resource handlersCreating a custom resource handler means implementing the
IResource interface. The base class
AbstractResource is a useful starting point. Look at
the Spring source for classes such as
FileSystemResource or
AssemblyResource for implementation tips. You can
register your custom resource handler either within App.config, as shown
in the program listing at the start of this section using a
.ResourceHandlersSectionHandler or define an object
of the type
Spring.Objects.Factory.Config.ResourceHandlerConfigurer
as you would any other Spring managed object. An example of the latter
is shown below:<object id="myResourceHandlers" type="Spring.Objects.Factory.Config.ResourceHandlersSectionHandler, Spring.Core">
<property name="ResourceHandlers">
<dictionary>
<entry key="db" value="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/>
</dictionary>
</property>
</object>Registering Type AliasesType aliases allow you to simplify Spring configuration file by
replacing fully qualified type name with an alias for frequently used
types. Aliases can be registered both within a config file and
programatically and can be used anywhere in the context config file
where a fully qualified type name is expected. Type aliases can also be
defined for generic types.One way to configure a type alias is to define them in a custom
config section in the Web/App.config file for your application, as well
as the custom configuration section handler. See the previous XML
configuration listing for an example that makes an alias for the
WebServiceExporter type. Once you have aliases defined, you can simply
use them anywhere where you would normally specify a fully qualified
type name:<object id="MyWebService" type="WebServiceExporter">
...
</object>
<object id="cacheAspect" type="DefaultPointcutAdvisor">
<property name="Pointcut">
<object type="AttributePointcut">
<property name="Attribute" value="CacheAttribute"/>
</object>
</property>
<property name="Advice" ref="aspNetCacheAdvice"/>
</object>To register a type alias register a section handler of the type
Spring.Context.Support.TypeAliasesSectionHandler in
the configSecitons section of App.config. The type alias configuration
section contains one or more <alias> elements each with a name and
a type attribute. Below is an example that registers the alias for
WebServiceExporter<configuration>
<configSections>
<sectionGroup name="spring">
<!-- other configuration section handler defined here -->
<section name="parsers" type="Spring.Context.Support.TypeAliasesSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
<typeAliases>
<alias name="WebServiceExporter" type="Spring.Web.Services.WebServiceExporter, Spring.Web"/>
</typeAliases>
</spring>
</configuration>For an example showing type aliases for generic types see .Another way is to define an object of the type
Spring.Objects.Factory.Config.TypeAliasConfigurer
within the regular <objects> section of any standard Spring
configuration file. This approach allows for more modularity in defining
type aliases, for example if you can't access App.config/Web.config. An
example of registration using a TypeAliasConfigurer
is shown below<object id="myTypeAlias" type="Spring.Objects.Factory.Config.TypeAliasConfigurer, Spring.Core">
<property name="TypeAliases">
<dictionary>
<entry key="WebServiceExporter" value="Spring.Web.Services.WebServiceExporter, Spring.Web"/>
<entry key="DefaultPointcutAdvisor" value="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop"/>
<entry key="MyType" value="MyCompany.MyProject.MyNamespace.MyType, MyAssembly"/>
</dictionary>
</property>
</object>Registering Type ConvertersThe standard .NET mechanism for specifying a type converter is to
add a TypeConverter attribute to a type definition to
specify the type of the Converter. This is the preferred way of defining
type converters if you control the source code for the type that you
want to define a converter for. However, this configuration section
allows you to specify converters for the types that you don't control,
and it also allows you to override some of the standard type converters,
such as the ones that are defined for some of the types in the .NET Base
Class Library.You can specify the type converters in App.config by using
Spring.Context.Support.TypeConvertersSectionHandler as shown before or
define an object of the type
Spring.Objects.Factory.Config.CustomConverterConfigurer.
An example of registration using a
CustomConverterConfigurer is shown below<object id="myTypeConverters" type="Spring.Objects.Factory.Config.CustomConverterConfigurer, Spring.Core">
<property name="CustomConverters">
<dictionary>
<entry key="System.Date" value="MyCompany.MyProject.MyNamespace.MyCustomDateConverter, MyAssembly"/>
</dictionary>
</property>
</object>Added functionality of the
IApplicationContextAs already stated in the previous section, the
IApplicationContext has a couple of features that
distinguish it from the IObjectFactory. Let us review
them one-by-one.Context HierarchiesYou can structure the configuration information of application
context into hierarchies that naturally reflect the internal layering of
your application. As an example, abstract object definitions may appear
in a parent application context configuration file, possibly as an
embedded assembly resource so as not to invite accidental changes.
<spring>
<context>
<resource uri="assembly://MyAssembly/MyProject/root-objects.xml"/>
<context name="mySubContext">
<resource uri="file://objects.xml"/>
</context>
</context>
</spring> The nesting of context
elements reflects the parent-child hierarchy you are creating. The
nesting can be to any level though it is unlikely one would need a deep
application hierarchy. The xml file must contain the
<objects> as the root name. Another example of
a hierarchy, but using sections in the application configuration file is
shown below. <configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<sectionGroup name="child">
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</sectionGroup>
</configSections>
<spring>
<context name="ParentContext">
<resource uri="config://spring/objects"/>
<context name="ChildContext">
<resource uri="config://spring/child/objects"/>
</context>
</context>
<objects xmlns="http://www.springframework.net">
...
</objects>
<child>
<objects xmlns="http://www.springframework.net">
...
</objects>
</child>
</spring>As a reminder, the type attribute of the
context tag is optional and defaults to
Spring.Context.Support.XmlApplicationContext. The
name of the context can be used in conjunction with the service locator
class, ContextRegistry, discussed in Using IMessageSourceThe IApplicationContext interface extends an
interface called IMessageSource and provides
localization (i18n or internationalization) services for text messages
and other resource data types such as images. This functionality makes
it easier to use .NET's localization features at an application level
and also offers some performance enhancements due to caching of
retrieved resources. Together with the
NestingMessageSource, capable of hierarchical message
resolving, these are the basic interfaces Spring.NET provides for
localization. Let's quickly review the methods defined there:
string GetMessage(string name): retrieves
a message from the IMessageSource and using
CurrentUICulture.string GetMessage(string name, CultureInfo
cultureInfo): retrieves a message from the
IMessageSource using a specified
culture.string GetMessage(string name, params object[]
args): retrieves a message from the
IMessageSource using a variable list of
arguments as replacement values in the message. The
CurrentUICulture is used to resolve the message.string GetMessage(string name, CultureInfo
cultureInfo, params object[] args): retrieves a message
from the IMessageSource using a variable list
of arguments as replacement values in the message. The specified
culture is used to resolve the message.string GetMessage(string name, string
defaultMessage, CultureInfo culture, params object[]
arguments): retrieves a message from the
IMessageSource using a variable list of
arguments as replacement values in the message. The specified
culture is used to resolve the message. If no message can be
resolved, the default message is used.string GetMessage(IMessageSourceResolvable
resolvable, CultureInfo culture) : all properties used
in the methods above are also wrapped in a class - the
MessageSourceResolvable, which you can use in
this method.object GetResourceObject(string name):Get
a localized resource object, i.e. Icon, Image, etc. given the
resource name. The CurrentUICulture is used to resolve the
resource object.object GetResourceObject(string name, CultureInfo
cultureInfo):Get a localized resource object, i.e. Icon,
Image, etc. given the resource name. The specified culture is used
to resolve the resource object.void ApplyResources(object value, string
objectName, CultureInfo cultureInfo): Uses a
ComponentResourceManager to apply resources to all object
properties that have a matching key name. Resource key names are
of the form objectName.propertyNameWhen an IApplicationContext gets loaded, it
automatically searches for an IMessageSource object
defined in the context. The object has to have the name
messageSource. If such an object is found, all calls
to the methods described above will be delegated to the message source
that was found. If no message source was found, the
IApplicationContext checks to see if it has a parent
containing a similar object, with a similar name. If so, it uses that
object as the IMessageSource. If it can't find any
source for messages, an empty StaticMessageSource
will be instantiated in order to be able to accept calls to the methods
defined above.Fallback behaviorThe fallback rules for localized resources seem to have a bug
that is fixed by applying Service Pack 1 for .NET 1.1. This affects
the use of IMessageSource.GetMessage methods that specify CultureInfo.
The core of the issue in the .NET BCL is the method
ResourceManager.GetObject that accepts CultureInfo.Spring.NET provides two IMessageSource
implementations. These are ResourceSetMessageSource
and StaticMessageSource. Both implement
IHierarchicalMessageSource to resolve messages
hierarchically. The StaticMessageSource is hardly
ever used but provides programmatic ways to add messages to the source.
The ResourceSetMessageSource is more interesting and
an example is provided for in the distribution and discussed more
extensively in the section. The
ResourceSetMessageSource is configured by providing a
list of ResourceManagers. When a message code is to
be resolved, the list of ResourceManagers is searched to resolve the
code. For each ResourceManager a
ResourceSet is retrieved and asked to resolve the
code. Note that this search does not replace the standard hub-and-spoke
search for localized resources. The ResourceManagers list specifies the
multiple 'hubs' where the standard search starts. <object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core">
<property name="resourceManagers">
<list>
<value>Spring.Examples.AppContext.MyResource, Spring.Examples.AppContext</value>
</list>
</property>
</object>You can specify the arguments to construct a ResourceManager as a
two part string value containing the base name of the resource and the
assembly name. This will be converted to a ResourceManager via the
ResourceManagerConverter TypeConverter. This
converter can be similarly used to set a property on any object that is
of the type ResourceManager. You may also specify an
instance of the ResourceManager to use via an object
reference. The convenience class
Spring.Objects.Factory.Config.ResourceManagerFactoryObject
can be used to conveniently create an instance of a ResourceManager.
<object name="myResourceManager" type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject, Spring.Core">
<property name="baseName">
<value>Spring.Examples.AppContext.MyResource</value>
</property>
<property name="assemblyName">
<value>Spring.Examples.AppContext</value>
</property>
</object>In application code, a call to GetMessage will
retrieve a properly localized message string based on a code value. Any
arguments present in the retrieved string are replaced using
String.Format semantics. The ResourceManagers,
ResourceSets and retrieved strings are cached to provide quicker lookup
performance. The key 'HelloMessage' is contained in the resource file
with a value of Hello {0} {1}. The following call on
the application context will return the string Hello Mr.
Anderson. Note that the caching of
ResourceSets is via the concatenation of the ResourceManager base name
and the CultureInfo string. This combination must be unique.
string msg = ctx.GetMessage("HelloMessage",
new object[] {"Mr.", "Anderson"},
CultureInfo.CurrentCulture );
It is possible to chain the resolution of messages by passing
arguments that are themselves messages to be resolved giving you greater
flexibility in how you can structure your message resolution. This is
achieved by passing as an argument a class that implements
IMessageResolvable instead of a string literal. The
convenience class DefaultMessageResolvable is
available for this purpose. As an example if the resource file contains
a key name error.required that has the value
'{0} is required {1}' and another key name
field.firstname with the value 'First
name'. The following code will create the string
'First name is required dude!' string[] codes = {"field.firstname"};
DefaultMessageResolvable dmr = new DefaultMessageResolvable(codes, null);
ctx.GetMessage("error.required",
new object[] { dmr, "dude!" },
CultureInfo.CurrentCulture ));
The examples directory in the distribution contains an example
program, Spring.Examples.AppContext, that
demonstrates usage of these features.The IMessageSourceAware interface can also be
used to acquire a reference to any IMessageSource
that has been defined. Any object that is defined in an
IApplicationContext that implements the
IMessageSourceAware interface will be injected with
the application context's IMessageSource when it (the
object) is being created and configured.Using resources within Spring.NETA lot of applications need to access resources. Resources here,
might mean files, but also news feeds from the Internet or normal web
pages. Spring.NET provides a clean and transparent way of accessing
resources in a protocol independent way. The
IApplicationContext has a method
(GetResource(string)) to take care of this. Refer to
for more information on the string
format to use and the IResource abstraction in
general.Loosely coupled eventsThe Eventing Registry allows developers to utilize a loosely
coupled event wiring mechanism. By decoupling the event publication and
the event subscription, most of the mundane event wiring is handled by
the IoC container. Event publishers can publish their event to a central
registry, either all of their events or a subset based on criteria such
as delegate type, name, return value, etc... Event subscribers can
choose to subscribe to any number of published events. Subscribers can
subscriber to events based on the type of object exposing them, allowing
one subscriber to handle all events of a certain type without regards to
how many different instances of that type are created.The Spring.Objects.Events.IEventRegistry
interface represents the central registry and defines publish and
subscribe methods. void PublishEvents( object sourceObject
): publishes all events of the source object to
subscribers that implement the correct handler methods.void Subscribe(object subscriber ): The
subscriber receives all events from the source object for which it
has matching handler methods.void Subscribe(object subscriber, Type
targetSourceType ): The subscriber receives all events
from a source object of a particular type for which it has
matching handler methods.void Unsubscribe(object subscriber ):
Unsubscribe all events from the source object for which it has
matching handler methods.void Unsubscribe(object subscriber, Type
targetSourceType ): Unsubscribe all events from a source
object of a particular type for which it has matching handler
methods.IApplicationContext implements this
interface and delegates the implementation to an instance of
Spring.Objects.Events.Support.EventRegistry. You are
free to create and use as many EventRegistries as you like but since it
is common to use only one in an application,
IApplicationContext provides convenient access to a
single instance.Within the
example/Spring/Spring.Examples.EventRegistry
directory you will find an example on how to use this functionality.
When you open up the project, the most interesting file is the
EventRegistryApp.cs file. This application loads a set of object
definitions from the application configuration file into an
IApplicationContext instance. From there, three
objects are loaded up: one publisher and two subscribers. The publisher
publishes its events to the IApplicationContext
instance: // Create the Application context using configuration file
IApplicationContext ctx = ContextRegistry.GetContext();
// Gets the publisher from the application context
MyEventPublisher publisher = (MyEventPublisher)ctx.GetObject("MyEventPublisher");
// Publishes events to the context.
ctx.PublishEvents( publisher );
One of the two subscribers subscribes to all events
published to the IApplicationContext instance, using
the publisher type as the filter criteria.// Gets first instance of subscriber
MyEventSubscriber subscriber = (MyEventSubscriber)ctx.GetObject("MyEventSubscriber");
// Gets second instance of subscriber
MyEventSubscriber subscriber2 = (MyEventSubscriber)ctx.GetObject("MyEventSubscriber");
// Subscribes the first instance to the any events published by the type MyEventPublisher
ctx.Subscribe( subscriber, typeof(MyEventPublisher) ); This
will wire the first subscriber to the original event publisher. Anytime
the event publisher fires an event,
(publisher.ClientMethodThatTriggersEvent1();) the
first subscriber will handle the event, but the second subscriber will
not. This allows for selective subscription, regardless of the original
prototype definition.Event notification from
IApplicationContextEvent handling in the IApplicationContext is
provided through the IApplicationListener interface
that contains the single method void OnApplicationEvent( object
source, ApplicationEventArgs applicationEventArgs ). Classes
that implement the IApplicationListener interface are
automatically registered as a listener with the
IApplicationContext. Publishing an event is done via
the context's PublishEvent( ApplicationEventArgs eventArgs
) method. This implementation is based on the traditional
Observer design pattern.The event argument type, ApplicationEventArgs,
adds the time of the event firing as a property. The derived class
ContextEventArgs is used to notify observers on the
lifecycle events of the application context. It contains a property
ContextEvent Event that returns the enumeration
Refreshed or Closed.. The
Refreshed enumeration value indicated that the
IApplicationContext was either initialized or
refreshed. Initialized here means that all objects are loaded,
singletons are pre-instantiated and the
IApplicationContext is ready for use. The
Closed is published when the
IApplicationContext is closed using the
Dispose() method on the
IConfigurableApplicationContext interface. Closed
here means that singletons are destroyed.Implementing custom events can be done as well. Simply call the
PublishEvent method on the
IApplicationContext, specifying a parameter which is
an instance of your custom event argument subclass.Let's have a look at an example. First, the
IApplicationContext: <object id="emailer" type="Example.EmailObject">
<property name="blackList">
<list>
<value>black@list.org</value>
<value>white@list.org</value>
<value>john@doe.org</value>
</list>
</property>
</object>
<object id="blackListListener" type="Example.BlackListNotifier">
<property name="notificationAddress">
<value>spam@list.org</value>
</property>
</object> and then, the actual objects: public class EmailObject : IApplicationContextAware {
// the blacklist
private IList blackList;
public IList BlackList
{
set { this.blackList = value; }
}
public IApplicationContext ApplicationContext
{
set { this.ctx = value; }
}
public void SendEmail(string address, string text) {
if (blackList.contains(address))
{
BlackListEvent evt = new BlackListEvent(address, text);
ctx.publishEvent(evt);
return;
}
// send email...
}
}
public class BlackListNotifier : IApplicationListener
{
// notification address
private string notificationAddress;
public string NotificationAddress
{
set { this.notificationAddress = value; }
}
public void OnApplicationEvent(ApplicationEvent evt)
{
if (evt instanceof BlackListEvent)
{
// notify appropriate person
}
}
}Customized behavior in the ApplicationContextThe IObjectFactory already offers a number of
mechanisms to control the lifecycle of objects deployed in it (such as
marker interfaces like IInitializingObject and
System.IDisposable, their configuration only
equivalents such as init-method and
destroy-method) attributes in an XmlObjectFactory
configuration, and object post-processors. In an
IApplicationContext, all of these still work, but
additional mechanisms are added for customizing behavior of objects and
the container.The IApplicationContextAware marker
interfaceAll marker interfaces available with ObjectFactories still work.
The IApplicationContext does add one extra marker
interface which objects may implement,
IApplicationContextAware. An object which implements
this interface and is deployed into the context will be called back on
creation of the object, using the interface's
ApplicationContext property, and provided with a
reference to the context, which may be stored for later interaction with
the context.The IObjectPostProcessorObject post-processors are classes which implement the
Spring.Objects.Factory.Config.IObjectPostProcessor
interface, have already been mentioned. It
is worth mentioning again here though, that post-processors are much
more convenient to use in IApplicationContexts than
in plain IObjectFactory instances. In an
IApplicationContext, any deployed object which
implements the above marker interface is automatically detected and
registered as an object post-processor, to be called appropriately at
creation time for each object in the factory.The IObjectFactoryPostProcessorObject factory post-processors are classes which implement the
Spring.Objects.Factory.Config.IObjectFactoryPostProcessor
interface, have already
been mentioned. It is worth mentioning again here though, that object
factory post-processors are much more convenient to use in
IApplicationContexts. In an
IApplicationContext, any deployed object which
implements the above marker interface is automatically detected as an
object factory post-processor, to be called at the appropriate
time.The PropertyPlaceholderConfigurerThe PropertyPlaceholderConfigurer has already been
described in the context of its use within an
IObjectFactory. It is worth mentioning here though,
that it is generally more convenient to use it with an
IApplicationContext, since the context will
automatically recognize and apply any object factory post-processors,
such as this one, when they are simply deployed into it like any other
object. There is no need for a manual step to execute it.Configuration of ApplicationContext without using XMLThe class GenericApplicationContext can be used as a basis for
creating an IApplicationContext implementation that read the container
metadata from sources other than XML. This could be by scanning objects in
a .DLL for known attributes or a scripting language that leverages a DSL
to create terse IObjectDefinitions. There is a class,
Spring.Objects.Factory.Support.ObjectDefinitionBuilder offers some
convenience methods for creating an IObjectDefinition in a less verbose
manner than using the RootObjectDefinition API. The following shows how to
configure the GenericApplicationContext to read from XML, just so show
familiar API usageGenericApplicationContext ctx = new GenericApplicationContext();
XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(ctx);
reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml");
reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml");
reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextA.xml");
ctx.Refresh();The implementation of IObjectDefinitionReader is responsible for
creating the configuration metadata, i.e., implementations of
RootObjectDefinition, etc. Note a web version of this application class
has not yet been implemented.An example, with a yet to be created DLL
scanner, that would get configuration metadata from the .dll named
MyAssembly.dll located in the runtime path, would look something like
thisGenericApplicationContext ctx = new GenericApplicationContext();
ObjectDefinitionScanner scanner = new ObjectDefinitionScanner(ctx);
scanner.scan("MyAssembly.dll");
ctx.refresh();Refer to the Spring API documentation for more information.Service Locator accessThe majority of the code inside an application is best written in a
Dependency Injection (Inversion of Control) style, where that code is
served out of an IObjectFactory or
IApplicationContext container, has its own dependencies
supplied by the container when it is created, and is completely unaware of
the container. However, there is sometimes a need for singleton (or
quasi-singleton) style access to an IObjectFactory or
IApplicationContext. For example, third party code may
try to construct a new object directly without the ability to force it to
get these objects out of the IObjectFactory. Similarly, nested user
control components in a WinForms application are created inside the
generated code in InitializeComponent. If this user control would like to
obtain references to objects contained in the container it can use the
service locator style approach and 'reach out' from inside the code to
obtain the object it requires. (Note support for DI in WinForms is under
development.)The Spring.Context.Support.ContextRegistry class
allows you to obtain a reference to an
IApplicationContext via a static locator method. The
ContextRegistry is initialized when creating an
IApplicationContext through use of the
ContextHandler discussed previously. The simple static
method GetContext() can then be used to retrieve the
context. Alternatively, if you create an
IApplicationContext though other means you can register
it with the ContextRegistry via the method
void RegisterContext(IApplicationContext context) in
the start-up code of your application. Hierarchical context retrieval is
also supported though the use of the GetContext(string
name) method, for example:IApplicationContex ctx = ContextRegistry.GetContext("mySubContext");
This would retrieve the nested context for the context configuration shown
previously.<spring>
<context>
<resource uri="assembly://MyAssembly/MyProject/root-objects.xml"/>
<context name="mySubContext">
<resource uri="file://objects.xml"/>
</context>
</context>
</spring>Do not call ContextRegistry.GetContext within a constructor as it
will result in and endless recursion. (This is scheduled to be fixed in
1.1.1) In this case it is quite likely you can use the
IApplicationContextAware interface and then retrieve other objects in a
service locator style inside an initialization method.The ContextRegistry.Clear() method will remove
all contexts. On .NET 2.0, this will also call the ConfigurationManager's
RefreshSection method so that the Spring context configuration section
will be reread from disk when it is retrieved again. Note that in a web
application RefeshSection will not work as advertised and you will need to
touch the web.config files to reload a configuration.Stereotype attributesBeginning with Spring 1.2, the [Repository] attribute was introduced
as a marker for any class that fulfills the role or stereotype of a
repository (a.k.a. Data Access Object or DAO). Among the possibilities for
leveraging such a marker is the automatic translation of exceptions as
described in Exception
Translation.Spring 1.2 introduces further stereotype annotations: [Component]
and [Service]. [Component] serves as a generic stereotype for any
Spring-managed component; whereas, [Repository] and [Service] serve as
specializations of [Component] for more specific use cases (e.g., in the
persistence and service layers, respectively). The ASP.NET MVC
[Controller] attribute will serve this purpose for the controller layer.
What this means is that you can annotate your component classes with
[Component], but by annotating them with [Repository] or [Service] your
classes are more properly suited for processing by tools or associating
with aspects. For example, these stereotype annotations make ideal targets
for pointcuts. Of course, it is also possible that [Repository] and
[Service] may carry additional semantics in future releases of the Spring
Framework. Thus, if you are making a decision between using [Component] or
[Service] for your service layer, [Service] is clearly the better choice.
Similarly, as stated above, [Repository] is already supported as a marker
for automatic exception translation in your persistence layer. The next
version of Spring will use the [Component] attribute to perform attribute
based autowiring by-type as in the Spring Java Framework.