![]() |
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) [1] principle The In short, the If you are new to Spring.NET or IoC containers in general, you may want to consider starting with Chapter 37, IoC Quickstarts, 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. The interface IApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling many of the objects in your application. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata is represented in XML. The configuration metadata allows you to express the objects that compose your application and the rich interdependencies between such objects.
Several implementations of the IApplicationContext interface are supplied out-of-the-box with Spring. In standalone applications it is common to create an instance of an XmlApplicationContext either programmatically or declaratively in your applications App.config file. In web applications Spring provides a WebApplicationContext implementation which is configured by adding a custom HTTP module and HTTP handler to your Web.config file. See the section on Web Configuration for more details. The following diagram is a high-level view of how Spring works. Your application classes are combined with configuration metadata so that after the ApplicationContext is created and initialized, you have a fully configured and executable system or application. ![]() As the preceding diagram shows, the Spring IoC container consumes a form of configuration metadata; this configuration metadata represents how you as an application developer tell the Spring container to instantiate, configure, and assemble the objects in your application. Configuration metadata is supplied in a simple and intuitive XML format
Spring configuration consists of at least one and typically more
than one object definition that the container must manage. XML- based
configuration shows these objects as These object definitions correspond to the actual objects that
make up your application. Typically you define service layer objects,
data access objects (DAOs), presentation objects such as ASP.NET page
instances, infrastructure objects such as NHibernate
The following example shows 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> The 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 Appendix D, Spring.NET's spring-objects.xsd). 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 Chapter 36, Visual Studio.NET Integration for more information regarding such integration. Instantiating a Spring IoC container is straightforward. The location path or paths suppied to an IApplicationContext constructor are actually resource strings that allow the container to load configuration metadata from a variety of external resources such as the local file system, embedded assembly resources, and so on. IApplicationContext context = new XmlApplicationContext("services.xml", "data-access.xml"); The following example shows the service layer objects
<objects xmlns="http://www.springframework.net"> <object id="PetStore" type="PetStore.Services.PetStoreService, PetStore"> <property name="AccountDao" ref="AccountDao"/> <property name="ItemDao" ref="ItemDao"/> <!-- additional collaborators and configuration for this object go here --> </object> <!-- more object definitions for services go here --> </objects> The following example shows the data access
objects <objects xmlns="http://www.springframework.net"> <object id="AccountDao" type="Petstore.Dao.HibernateAccountDao, PetStore"> <!-- additional collaborators and configuration for this object go here --> </object> <object id="ItemDao" type="Petstore.Dao.HibernateItemDao, PetStore"> <!-- additional collaborators and configuration for this object go here --> </object> <!-- more object definitions for data access objects go here --> </objects> In the preceeding example, the service layer consists of the class PetStoreService, and two data access objects of the type HibernateAccountDao and HibernateItemDao are based on the NHibernate Object/Relational mapping framework. The property name element refers to the name of the class's property, and the ref element refers to the name of another object definition. This linkage between id and ref elements expresses the dependency between collaborating objects. For details of configuring an object's dependencies, see Dependencies. In the previous example the configuration resources are assumed to be located in the bin\Debug directory. You can use Spring's IResource abstraction to load resources from other locations. The following example shows how to create an IoC container referring to resources located in the root directory of the filesystem an as an embedded assembly resource. IApplicationContext context = new XmlApplicationContext( "file:///services.xml", "assembly://MyAssembly/MyDataAccess/data-access.xml"); The above example uses Spring.NET's IResource
abstraction. The
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.
The following snippet shows the use of the URI syntax for
referring to a resource that has been embedded inside a .NET assembly,
You can also create a container by using a custom configuration
section in the standard .NET application configuration file (one of
<spring> <context> <resource uri="file://services.xml"/> <resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/> </context> </spring> The context type (specified as the value of
the <spring> <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core"> <resource uri="file:///services.xml"/> <resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/> </context> </spring> To acquire a reference to an
IApplicationContext ctx = ContextRegistry.GetContext();
The <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 In some usage scenarios, user code will not have to explicitly
instantiate an appropriate implementation
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 Appendix D, Spring.NET's spring-objects.xsd). 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 Chapter 36, Visual Studio.NET Integration for more information regarding such integration. Your XML object definitions can also be defined within the
standard .NET application configuration file by registering the
<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 Section 5.12.1, “Context Hierarchies” and Section 5.2.2.3, “Composing XML-based configuration metadata”. The It can be useful to have object definitions span multiple XML files. Often each individual XML configuration file represents a logical layer or module in your architecture. You can use the IApplicationContext
constructor to load object definitions from all these XML fragments.
This constructor takes multiple IResource
locations, as was shown in the previous section. Alternatively, use
one or more occurrences of the <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 the preceeding example, external object definitions are being
loaded from three files, An The // create and configure objects IApplicationContext context = new XmlApplicationContext("services.xml", "daos.xml"); // retrieve configured instance PetStoreService service = (PetStoreService) context.GetObject("PetStoreService"); // use configured instance IList userList = service.GetUserNames(); You use the method
A Spring IoC container manages one or more objects. These objects are created with the configuration metadata that you supply to the container. Within the container itself, these object definitions are represented as IObjectDefinition objects, which contain (among other information) the following metadata:
This metadata translates to a set of properties that make up each object definition. The following table lists some of these properties, with links to documentation Table 5.1. Object definition explanation
In addition to object definitions which contain information on how
to create a specific object, the
IApplicationContext implementations also permit
the registration of existing objects that are created outside the
container, by users. This is done by accessing the
ApplicationContext's
IObjectFactory via the property
Every object has one or more identifiers. These identifiers must be unique within the container that hosts the objects. An object usually has only one identifier, but if it requires more than one, the extra ones can be considered aliases. When using XML-based configuration metadata, you use the
In an object definition itself, you may supply more than one
name for the object, by using a combination of up to one name
specified by the Specifying all aliases where the object is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for an object that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object defintions. In XML-based configuration metadata, you can use of the <alias/> element to accomplish this. <alias name="fromName" alias="toName"/> In this case, an object in the same container which is named
For example, the configuration metadata for subsystem A may refer to a DbProvider via the name 'SubsystemA-DbProvider. The configuration metadata for subsystem B may refer to a DbProvider via the name 'SubsystemB-DbProvider'. When composing the main application that uses both these subsystems the main application refers to the DbProvider via the name 'MyApp-DbProvider'. To have all three names refer to the same object you add to the MyApp configuration metadata the following aliases definitions: <alias name="SubsystemA-DbProvider" alias="SubsystemB-DbProvider"/> <alias name="SubsystemA-DbProvider" alias="MyApp-DbProvider"/> Now each component and the main app can refer to the connection through 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. An 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 in the
When you create an object using the constructor approach, all normal classes are usable by and compatible with Spring. That is, the class being developed does not need to implement any specific interfaces or to be coded in a specific fashion. Simply specifying the object type should be sufficient. However, depending on what type of IoC you are going to use for that specific object, you may need to create a default constructor. With XML-based configuration metadata you can specify your object class as follows: <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/> For details about the mechanism for supplying arguments to the constructor (if required), and setting object instance properties after the object is constructed, see Section 5.3.1, “Dependency injection”. This XML fragment describes an object definition that will be
identified by the exampleObject name, instances
of which will be of the The name of the assembly that contains the type
must be specified in the If you have defined nested classes use the addition symbol, +,
to reference the nested class. For example, if the class
<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
When defining an object which is to be created using a static factory method, you use the type attribute to specify the type containing the static factory method and an attribute named factory-method to specify the name of the factory method itself. You should be able to call this method (with an optional list of arguments as described later) and return a live object, which subsequently is treated as if it had been created through a constructor. One use for such an object definition is to call static factories in legacy code. The following object definition specifies that the object will
be created by calling a factory-method. The definition does not
specify the type of the returned object, only the type containing the
factory method. In this example, <object id="exampleObject" type="Examples.ExampleObjectFactory, ExamplesLibrary" factory-method="CreateInstance"/> For details about the mechanism for supplying (optional) arguments to the factory method and setting object instance properties after it has been returned from the factory, see Section 5.3.2, “Dependencies and configuration in detail” Similar to instantiation through a static factory
method, instantiation with an instance factory method invokes a
a non-static method on an existing object from the container to create
a new object. To use this mechanism, leave the <!-- 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"/> This approach shows that the factory object itself can be managed and configured through dependency injection (DI). See Dependencies and configuraiton in detail. Generic types can also be created in much the same manner an non-generic types. The 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. <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 Section 5.11, “Configuration of IApplicationContext” for additional information on using type aliases. The 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 <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'. Using 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
A typical enterprise application does not consist of a single object. Even the simplest application has a few 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 to a fully realized application where objects collaborate to achieve a goal. Dependency injection (DI) is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments and properties that are set on the object instance after it is constructed. (Factory methods may be considered a special case of providing constructor arguments for the purposes of this description). The container injects these dependencies when it creates the object. This process is fundamentally the inverse to the case when the object itself is controlling the instantiation or location of its dependencies by using direct construction of classes, or the Service Locator pattern. The inverting of this responsibility is why the name Inversion of Control (IoC) is used to describe the container's actions. Code is cleaner when using DI and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies, and does not know the location or class of the dependencies. Long sections of initialization code that you used to hide in a #region tag simply go away, and are placed by container configuration metadata. One can also consider this clean up an application of the principal of Separation of Concerns. Before using DI, you class was responsible for business logic AND its configuration, it was concerns with doing more than one thing. DI removes the responsibility of configuration from the class, leaving it only with a single purpose, as the location of business logic. Furthermore, since you class does not know the location of its dependencies these classes also become easier to test, in particular when the dependencies are interfaces or abstract base classes allowing for stub or mock implementation to be used in unit tests. Dependency injection exists in two major variants, Constructor-based dependency injection and Setter-based dependency injection. Constructor-based DI is accomplished by the container invoking a constructor with a number of arguments, each representing a dependency. Calling a static factory method with specific arguments to construct the object is nearly equivalent, and this discussion treats arguments to a constructor and to a static factory method similarly. The following example shows a class that can only be dependency-injected with constructor injection. Notice that there is nothing special about this class (no container specific interfaces, base classes or attributes) 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 resolution matching occurs using the argument's type. If ambiguity exists 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 are supplied to the appropriate constructor when the object being instantiated. Consider the following class: namespace X.Y { public class Foo { public Foo(Bar bar, Baz baz) { // ... } } } No potential ambiguity exists, assuming of course that Bar and
Baz classes are not related by inheritance. Thus the following
configuration will work just fine, and you do not need to specify
the constructor argument indexes and / or types explicitly in the
<object id="foo" type="X.Y.Foo, Example"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> </object> <object id="bar" type="X.Y.Bar, Example"/> <object id="baz" type="X.Y.Baz, Example"/> 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
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; } } In the preceding scenario, the container
can use type matching with simple types by
explicitly specifying the type of the constructor argument using
the <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
Table 5.2. Type aliases
Use the <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </object> In addition to resolving the ambiguity of multiple simple values, specifying an index also resolves ambiguity where a constructor has two arguments of the same type. Note that the index is 0 based. You can specify constructor argumetn by name using
<object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp"> <constructor-arg name="years" value="7500000"/> <constructor-arg name="ultimateAnswer" value="42"/> </object> Setter-based DI is accomplished by the container invoking setter properties on your objects after invoking a no-argument constructor or no-argument static factory method to instantiate your object. The following eample shows 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... } The The configuration for the dependencies comes in the form of the
The container resolves object dependeices as:
The Spring container validates the configuration of each object as the container is created, including the validation of whether object reference properties refer to valid object. However, the object properties themselves are not set until the object is actually created. Objects that are defined as singletons and set to be pre-instantiated, are created when the container is created. Otherwise, the object is created only when it is requested. Creation of an object potentially causes a graph of objects to be created as the objects dependencies and its dependencies' dependencies (and so on) are created and assigned. You can generally trust Spring.NET to do the right thing. It
detects configuration problems, such as references to non-existent
object definitions and circular dependencies, at container load-time.
Spring sets properties and resolves 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. For example, the object throws an
exception as a result of a missing or invalid property. This
potentially delayed visibility of some configuration issues is why
If no circular dependencies exist, when one or more
collaborating objects are being injected into a dependent object, each
collaborating object is totally configured prior
to being passed into the dependent object. This means that if object A
has a dependency on object B, the Spring IoC container completely
configures object B prior to invoking the setter method on object A.
In other words, the object is instantiated (if not a pre-instantiated
singleton), its dependencies are set, and the relevant lifecycle
methods (such as a configured init method or the
First, an example of using XML-based configuration metadata for setter-based DI. A small part 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; } } } In the preceding example, 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 Class Ghe constructor arguments specified in the object
definition will be used to pass in as arguments to the constructor of
the 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 } Arguments to the static factory method are supplied via
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; } } } As mentioned in the previous section, you can define object
properties and constructor arguments as either references to other
managed objects (collaborators), or as values defined inline. Spring's
XML-based configuration metadata supports sub-element types within its
The In the following example, we use a
<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> An idref element is simply an error-proof way to pass the
id (string value - not a reference) of another
object in the container to a
<object id="theTargetObject" type="..."> . . . </object> <object id="theClientObject" type="..."> <property name="targetName"> <idref object="theTargetObject"/> </property> </object> This above object definition snipped is exactly equivalent (at runtime) to the following snippit: <object id="theTargetObject" type="..."> . . . </object> <object id="theClientObject" type="..."> <property name="targetName" value="theTargetObject"/> </object> The first form is preferable to the second is
that using the Additionally, if the reference object is in the same XML unit,
and the object name is the object id, you can
use the <property name="targetName"> <idref local="theTargetObject"/> </property> Usually 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. The Specifying the target object through the
<ref object="someObject"/> Specifying the target object by using the
<ref local="someObject"/> Specifying the target object through the
<!-- in the parent context --> <object id="AccountService" type="MyApp.SimpleAccountService, MyApp"> <!-- insert dependencies as required as here --> </object> <!-- in the child (descendant) context --> <object id="AccountService" <-- notice that the name of this object is the same as the name of the 'parent' object type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop"> <property name="target"> <ref parent="AccountService"/> <-- notice how we refer to the parent object --> </property> <!-- insert other configuration and dependencies as required as here --> </object> An <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> An inner object definition does not require a defined id or
name; the container ignores these values. It also ignores the
The <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. The value of a Dictionary entry, or a set value, can also again be any of the following 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 Section 5.3.2.9, “Value and ref shortcut forms” for more information. Spring supports setting values for classes that expose
properties based on the generic collection interfaces
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
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> As of Spring 1.3, the container supports the merging of
collections. An application developer can define a parent-style
This section on merging discusses the parent-child object mechanism. Readers unfamiliar with parent and child object definitions may wish to read the relevant section before continuing. The following example demonstrates collection merging: <object id="parent" abstract="true" type="Example.ComplexObject, Examples"> <property name="AdminEmails"> <name-values> <add key="administrator" value="administrator@example.com"/> <add key="support" value="support@example.com"/> </name-values> </property> </object> <object id="child" parent="parent" > <property name="AdminEmails"> <!-- the merge is specified on the *child* collection definition --> <name-values merge="true"> <add key="sales" value="sales@example.com"/> <add key="support" value="support@example.co.uk"/> </name-values> </property> </object> Notice the use of the administrator=administrator@example.com sales=sales@example.com support=support@example.co.uk The child Properties collection's value set inherits all
property elements from the parent
Spring treats empty arguments for properties and the like as empty Strings. The following XML-based configuration metadata snippet sets the email property to the empty String value ("") <object type="Examples.ExampleObject, ExamplesLibrary"> <property name="email" value=""/> </object> This results in the email property being set to the empty string
value ( exampleObject.Email = "";
The <object type="Examples.ExampleObject, ExamplesLibrary"> <property name="email"><null/></property> </object> This results in the email property being set to
exampleObject.Email = null;
An indexer lets you set and get values from a collection using a
familiar bracket 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>
Spring XML used to be even more verbose. What is now popular usage is actually the shortcut from of the original way to specify values and references. There are also some shortcut forms that are less verbose than
using the full <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 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"/>
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 You can use compound or nested property names when you set 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
<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. In C# events are built right into the language thanks to the
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.HandleEvent When 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 Rather than having to specifically declare in your code that you
are adding a method to be invoked on an event, using the
Using the The same event registration in the example above can be achieved
using configuration using the <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
Regular 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 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> Finally, 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 If an object is a dependency of another that usually means that
one object is set as a property of another. Typically you accomplish
this with the <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager"> <property name="manager" ref="manager"/> </object> <object id="manager" type="Examples.ManagerObject, ExamplesLibrary"/> To express a dependency on multiple objects, supply a list of
object names as the value of the ' <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" />
By default, In XML, this behavior is controlled by the
<object id="lazy" type="MyCompany.ExpensiveToCreateObject, MyApp" lazy-init="true"/> <object name="not.lazy" type="MyCompany.AnotherObject, MyApp"/> When the preceding configuration is consumed by an
However, when a lazy-initialized object is a dependency of a
singleton object that is not
You can also control lazy-initialization at the container level by
using the <objects default-lazy-init="true"> <!-- no objects will be pre-instantiated... --> </objects> The 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: Table 5.3. Autowiring modes
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:
Some disadvantages of autowiring:
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. The Spring IoC container can check for unresolved dependencies of an object deployed into the container. When enabling checking for unresolved dependencies all properties of the object must have an explicit values set for them in the object definition or have their values set via autowiring. This feature useful when you want to ensure that all properties
(or all properties of a certain type) are set on an object. An object
often has default values for many properties, or some properties do not
apply to all usage scenarios, so this feature is of limited use. You can
enable dependency checking per object, just as with the autowiring
functionality. The default is not not check
dependencies. In XML-based configuration metadata, you specify
dependency checking via the Table 5.4. Dependency checking modes
In most application scenarios, most object in the container are singletons. When a singleton object needs to collaborate with another singleton object, or a non-singleton object needs to collaborate with another non-singleton object, you typically handle the dependency by defining one object as a property of the other. A problem arrises when the object lifecycles are different. Suppose singleton object A needs to use a non-singleton (prototype) object B, perhaps on each method invocation on A. The container only creates the singleton object A once, and thus only gets one opportunity to set the properties. The container cannot provide object A with a new instance of object B every time one is needed. A solution is to forego some inversion of control. You can make object A aware
of the container by implementing the
using 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 preceding is not desirable, because the business code is aware of and coupled to the Sring 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 injection is the ability of the container to
override methods on container managed objects, to
return the result of looking up another named object in the container.
The lookup typically involves a prototype object as in the scenario
described in the preceding section. The Spring framework implements
this method injection by a dynamically generating a subclass
overriding the method using the classes in the
Looking at the 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 to be injected requires a signature of the following form: <public|protected> [abstract] <return-type> TheMethodName(no-arguments); If the method is <!-- 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 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). A 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. With XML-based configuration metadata, you can use the
public class MyValueCalculator { public virtual string ComputeValue(string input) { // ... some real code } // ... some other methods } A class implementing the
/// <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"/> You can use one or more contained System.String String Str Because the number of arguments is often enough to distinguish between each possible choice, this shortcut can save a lot of typing, by allowing you to typ just the shortest string which will match an argument type. 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
The In the case of a property exposed on an instance, the target
object that a 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 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
<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"/> The The following example demonstrates using a
<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"/> The The The following example (in an XML based
<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 Note that since this class is expected to be used primarily for
accessing factory methods, this factory defaults to operating in
A static target method may be specified by setting the
Arguments for the method invocation may be specified in two ways
(or even a mixture of both)... the first involves setting the
<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
<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
<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
[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> In addition to The <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> When you create an object definition, you create a recipe for creating actual instances of the class defined by that object definition. The idea that an object definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe. You can control not only the various dependencies and configuration values that are to be plugged into an object that is created from a particular object definition, but also the scope of the objects created from a particular object definition. This approach powerful and flexible in that you can 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. Ob jects can be defined to be deployed in one of a number of scopes: out of the box, the Spring Framework supports five scopes, three of which are available only if you use a web-aware IApplicationContext. The following scopes supported. Support for user defined custom scopes is planned for Spring .NET 2.0. Table 5.5. Object Scopes
Singleton scoped objects have only one shared instance of an object managed by the container. All request for objects with an id or ids matching that object definition 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, the Spring IoC container creates exactly one instance of the object defined by that object definition. This single instance is stored in a cache of such singleton object, and all subsequent requests and references for that named object return the cached object. Spring's concept of a singleton differns from the Singleton pattern as defined in the 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 is 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 creates 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, for example: <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 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, the object is
injected into another object or you request through a
The following examples defines an object as a prototype in XML: <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary" scope="prototype"/>
In contrast to the other scopes, 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, with no further record of that prototype instance. Thus, although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped objects and release any expensive resources that the prototype object(s) are holding. To get the Spring container to release resources held by prototype-scoped objects, try using a custom object post processor which would hold a reference to the objects that need to be cleaned up. In some respects, the Spring container's role in regard to a prototype-scoped object is a replacement for the C# 'new' operator. All lifecycle management past that point must be handled by the client. (For details on the lifecycle of an object in the Spring container, see Section 5.6.1, “Lifecycle interfaces”. When you use singleton-scoped objects with dependencies on prototype objects, be aware that dependencies are resolved at instantiation time. Thus if you dependency-inject a prototype-scoped objects into a singleton-scoped object, a new prototype object is instantiated and then dependency-injected into the singleton object. The prototype instance is the sole instance that is ever supplied to the singleton-scoped object. However, suppose you want the singleton-scoped object to acquire a new instance of the prototype-scoped object repeatedly at runtime. You cannot dependency-inject a prototype-scoped object into your singleton object, because that injection occurs only once, when the Spring container is instantiating the singleton object and resolving and injecting its dependencies. If you need a new instance of a prototype object at runtime more than once, see Section 5.3.8, “Method injection”. The request, session and application scopes are only available if you use a web-aware Spring IApplicationContext implementation, such as WebApplicationContext. If you use these scopes with regular Spring IoC containers such as the XmlApplicationContext, you will get an exception complaining about an unknown object scope. Please refer to the web documentation on object scopes for more information. Type 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 [Serializable, TypeConverter(typeof(FontConverter)), ...] public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDisposable { // Methods ... etc .. } The default type converter for enumerations is the
<object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests"> <property name="name" value="Rod"/> <property name="FileMode" value="Create"/> </object> Spring.NET pre-registers a number of custom
Table 5.6. Built-in TypeConverters
Spring.NET uses the standard .NET mechanisms for the resolution of
There are a few ways to register custom type converters. The
fundamental storage area in Spring for custom type converters is the
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
If you are constructing your IoC container Programatically then
you should use the This section shows in detail how to define a custom type
converter that does not use the .NET 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
<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> To interact with the container's management of the object
lifecycle, you can implement the Spring
Internally, Spring.NET uses implementations of the
The
It is recommended that you do not use the
<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. Implementing the
Since the IDisposable interface resides
in the core .NET library, it does not couple your class to Spring as
in the case with the IInitializingObject
interface. However, you may also specify a destruction method that is
not tied to the IDisposable interface. In the
case of XML-based configuration metadata, you use the
<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 } } When an IApplicationContext creates a class that implements the IApplicationContextAware interface, the class is provided with a reference to that IApplicationContext. public interface IApplicationContextAware { IApplicationContext ApplicationContext { set; } } Thus objects can manipulate programmatically the IApplicationContext that created them, through the IApplicationContext interface, or by casting the reference to a known subclass of this interface, such as IConfigurableApplicationContext, which exposes additional functionality. One use would be the programmatic retrieval of other objects. Sometimes this capability is useful; however, in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to objects as properties. Other methods of the IApplicationContext provide access to file resources, publishing application events, and accessing a IMessageSource. These additional features are described in Section 5.10, “The IApplicationContext” When an IApplicationContext creates a
class that implements the
public interface IObjectNameAware { string ObjectName { set; } } The callback is invoked after population of normal object properties but before an initialization callback such as IInitializingObject 's AfterPropertiesSet method or a custom initalization method is invoked. An object definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on. A child object definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed. Using parent and child object definitions can save a lot of typing. Effectively, this is a form of templating. If you work with an IApplicationContext interface programmatically,
child object definitions are represented by the
<object id="inheritedTestObject" type="Spring.Objects.TestObject, Spring.Core.Tests" abstract="true"> <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 uses 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, that is, it must accept the parent's property values. A child object definition inherits constructor argument values, property values and method overrides from the parent, with the option to add new values. Any initialization method, destroy method and/or static factory methods that you specify will override the corresponding parent settings. The remaining settings are always be taken from the child
definition: The preceding example explicitly marks the parent object definition
as abstract using the <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 abstract like this, it is usable only as a pure template
object definition that serves 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
The Spring container is essentially nothing more than an advanced factory capable of maintaining a registry of different objects and their dependencies. The
[C#] IResource input = new FileSystemResource ("objects.xml"); XmlObjectFactory factory = new XmlObjectFactory(input); That is pretty much it. Using [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 <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
A sub-interface of
Check the SDK docs for additional details on
IConfigurableObjectFactory methods and properties and the full
Sometimes there is a need to ask an
The 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 The first extension point that we will look at is the
You can configure multiple
The
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 Other extensions to the 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 The It is important to know that the 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
This 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 definition using 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. Using callback interfaces or annotations in conjunction with a
custom IObjectPostProcessor implementation is a common means of
extending the Spring IoC container. The 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 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 container Error 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
This component is the
<object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core"/> Finally, one can configure an instance of the
<object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core"> <property name="RequiredAttributeType" value="MyApp.Attributes.MandatoryAttribute, MyApp"/> </object> The next extension point that we will look at is the
public interface IObjectFactoryPostProcessor { void PostProcessObjectFactory (IConfigurableListableObjectFactory factory); } You can configure multiple
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
In an 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 An
The 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 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 The 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
The 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> You may also use the value environment variables to replace
property placeholders. The use of environment variables is
controlled via the property
<object name="appConfigPropertyHolder" type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core"> <property name="configSections" value="DaoConfiguration,DatabaseConfiguration"/> <property name="EnvironmentVariableMode" value="Override"/> </object> </objects> The 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
The example usage is similar to when using
<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> The 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.
You use this by defining an instance of
<object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core"> <property name="VariableSources"> <list> <object type="Spring.Objects.Factory.Config.PropertyFileVariableSource, Spring.Core"> <property name="Location" value="~\application.properties" /> <property name="IgnoreMissingResources" value="true"/> </object> <object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core"> <property name="SectionNames" value="CryptedConfiguration" /> </object> </list> </property> </object>
The IVariableSource interface is shown below public 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. The The The
The IFactoryObject concept and interface is used in a number of
places within the Spring Framework. Some examples of its use is
described in Section 5.3.9, “Setting a reference using the members of other objects and
classes.” for the
Finally, there is sometimes a need to ask a container for an
actual The
While the The basis for the context module is the
Short version: use an
As the Find below a feature matrix that lists what features are provided
by the Table 5.7. Feature Matrix
Well 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="resourceHandlers" 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> <resourceHandlers> <handler protocol="db" type="MyCompany.MyApp.Resources.MyDbResource"/> </resourceHandlers> <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
Instead 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
To register a custom parser register a section handler of the type
<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"); Creating a custom resource handler means implementing the
<object id="myResourceHandlers" type="Spring.Objects.Factory.Config.ResourceHandlerConfigurer, Spring.Core"> <property name="ResourceHandlers"> <dictionary> <entry key="db" value="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/> </dictionary> </property> </object> Type 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
<configuration> <configSections> <sectionGroup name="spring"> <!-- other configuration section handler defined here --> <section name="typeAliases" 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 Section 5.2.6, “Object creation of generic types”. Another way is to define an object of the type
<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> The standard .NET mechanism for specifying a type converter is to
add a 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
<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> As already stated in the previous section, the
You 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 <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 The
When an
Spring.NET provides two <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
<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 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
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, The A 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
The 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
Within the
// 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 // 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,
( Event handling in the The event argument type, Implementing custom events can be done as well. Simply call the
Let's have a look at an example. First, the
<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 : IApplicationEventListener { // notification address private string notificationAddress; public string NotificationAddress { set { this.notificationAddress = value; } } public void HandleApplicationEvent(ApplicationEvent evt) { if (evt instanceof BlackListEvent) { // notify appropriate person } } } The All marker interfaces available with ObjectFactories still work.
The Object post-processors are classes which implement the
Object factory post-processors are classes which implement the
The The 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 usage GenericApplicationContext 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 this GenericApplicationContext ctx = new GenericApplicationContext(); ObjectDefinitionScanner scanner = new ObjectDefinitionScanner(ctx); scanner.scan("MyAssembly.dll"); ctx.refresh(); Refer to the Spring API documentation for more information. The 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 The 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 Beginning 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. [1] See the section entitled Section 3.1, “Inversion of Control” [2] 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. [3] More information about creating custom
|