SPRNET-1536 merge SPRNET-CODECONFIG refdocs
This commit is contained in:
574
doc/reference/src/codeconfig-attribute-reference.xml
Normal file
574
doc/reference/src/codeconfig-attribute-reference.xml
Normal file
@@ -0,0 +1,574 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter version="5" xml:id="codeconfig-attribute-reference"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:ns5="http://www.w3.org/1998/Math/MathML"
|
||||
xmlns:ns42="http://www.w3.org/2000/svg"
|
||||
xmlns:ns4="http://www.w3.org/1999/xlink"
|
||||
xmlns:ns3="http://www.w3.org/1999/xhtml"
|
||||
xmlns:ns="http://docbook.org/ns/docbook">
|
||||
<title>Attribute Reference</title>
|
||||
|
||||
<para>In this chapter, we will explore the attributes that are the essential
|
||||
components for declaring Object Definitions with Spring CodeConfig. These
|
||||
attributes have a corresponding representation in Spring XML so should be
|
||||
very familiar to current Spring.NET users.</para>
|
||||
|
||||
<sect1 xml:id="attribute-reference">
|
||||
<title>[Configuration] Attribute</title>
|
||||
|
||||
<para>The <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute is applied to classes that contain one or more <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attributed-methods. During scanning by the
|
||||
<literal>CodeConfigApplicationContext</literal>, only types having the
|
||||
<literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute will be considered candidates to contain Object Definition
|
||||
configurations.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the Configuration Attribute</title>
|
||||
|
||||
<para></para>
|
||||
|
||||
<sect3>
|
||||
<title>Simple Usage</title>
|
||||
|
||||
<para>The most common usage of the <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute simply applies the attribute to a class without any
|
||||
attribute parameters. The name of the of the type, once registered
|
||||
with the <literal>CodeConfigApplicationContext</literal>, will be the
|
||||
name of the class itself. Note that it is not a common use-case to ask
|
||||
the container for this configuration class.<programlisting
|
||||
language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
//[ObjectDef] methods here
|
||||
}</programlisting></para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Controlling the Name of the Configuration Class</title>
|
||||
|
||||
<para>While not a common use-case, if you need fine-grained control
|
||||
over the name of the type registered with the
|
||||
<literal>CodeConfigApplicationContext</literal>, the <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute accepts a <literal>Name</literal> parameter which will be
|
||||
applied to the registered Object Definition in the
|
||||
<literal>CodeConfigApplicationContext</literal>.<programlisting
|
||||
language="csharp">[Configuration("MySpecialConfigurationClass")]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
//[ObjectDef] methods here
|
||||
}</programlisting></para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="objectdef-attribute-reference">
|
||||
<title>[ObjectDef] Attribute</title>
|
||||
|
||||
<para>The <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute is applied to one or more methods within any class to which the
|
||||
<literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute has been applied. During scanning, any <literal>public
|
||||
virtual</literal> method having the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute is considered to contain Object Definition metadata.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the ObjectDef Attribute</title>
|
||||
|
||||
<para></para>
|
||||
|
||||
<sect3>
|
||||
<title>Simple Usage</title>
|
||||
|
||||
<para>The first usage of the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute simply applies the attribute to the method. The name of the
|
||||
of the Object to be registered with the
|
||||
<literal>CodeConfigApplicationContext</literal>, will be the name of
|
||||
the method itself.<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting></para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Controlling the Name and Aliases of the Defined Object</title>
|
||||
|
||||
<para>If you need to control the name of the Object registered with
|
||||
the <literal>CodeConfigApplicationContext</literal>, the
|
||||
<literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute accepts one or more comma-delimited names as aliases for the
|
||||
Object when registered.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef(Names="TheHomeController")]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
|
||||
[ObjectDef(Names="TheSpecialNameForAboutController,AliasForAboutController")]
|
||||
public virtual AboutController AboutController()
|
||||
{
|
||||
return new AboutController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Setting an Init Method for the Object</title>
|
||||
|
||||
<para>If you need to declare an Initialization Method for the object
|
||||
definition, the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute accepts a method name to be invoked at the appropriate stage
|
||||
in the object's creation by the
|
||||
<literal>CodeConfigApplicationContext</literal>.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef(InitMethod="AfterCreation")] //assumes a public method on the HomeController type named 'AfterCreation()'
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para><note>
|
||||
<para>You can just also call the method 'AfterCreation' inside the
|
||||
body of the HomeController implementation itself.</para>
|
||||
</note></para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Setting a Destroy Method for the Object</title>
|
||||
|
||||
<para>If you need to declare a Destroy Method for the object
|
||||
definition, the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute accepts a method name to be invoked at the appropriate stage
|
||||
in the object's destruction by the
|
||||
<literal>CodeConfigApplicationContext</literal>.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef(DestroyMethod="CleanupResources")] //assumes a public method on the HomeController type named 'CleanupResources()'
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="dependson-attribute-reference">
|
||||
<title>[DependsOn] Attribute</title>
|
||||
|
||||
<para>The <literal>[DependsOn]</literal> attribute can be applied to any
|
||||
<literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>-attributed
|
||||
method to declare a construction sequence dependency upon one or more
|
||||
objects that the <literal>CodeConfigApplicationContext</literal> will
|
||||
ensure are created prior to the creation of the current object. This is
|
||||
only required if there is a hidden depedency between the two classes that
|
||||
isn't exposed via constructor or setter properties.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the DependsOn Attribute</title>
|
||||
|
||||
<para></para>
|
||||
|
||||
<sect3>
|
||||
<title>Controlling Creation Dependencies</title>
|
||||
|
||||
<para>The <literal>[DependsOn]</literal> attribute accepts one or more
|
||||
comma-delimited strings representing the names of the objects upon
|
||||
which the current object will depend.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
[DependsOn("Dependency1")] //HomeController requires "Dependency1" to be created first
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
[DependsOn("Dependency1", "Dependency2")] //AboutController requires "Dependency1" and "Dependency2" to be created first
|
||||
public virtual AboutController AboutController()
|
||||
{
|
||||
return new AboutController();
|
||||
}b
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="import-attribute-reference">
|
||||
<title>[Import] Attribute</title>
|
||||
|
||||
<para>The <literal>[Import]</literal> attribute allows you to identify one
|
||||
or more additional types that will also be scanned when the current type
|
||||
is scanned.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the Import Attribute</title>
|
||||
|
||||
<para></para>
|
||||
|
||||
<sect3>
|
||||
<title>Specifying Additional Types to Scan</title>
|
||||
|
||||
<para>To support your specifying additional types to scan, the
|
||||
<literal>[Import]</literal> attribute accepts one or more
|
||||
comman-delimited Types to scan as well. To be candidates for scanning,
|
||||
the types listed in this array must also have the <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute applied to them. Note that no error is reported if these
|
||||
types lack the<literal>[Configuration</literal>] attribute, but
|
||||
without it they will not satisfy the scanner's requirements for
|
||||
Configuration candidates.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[Import(typeof(MySecondConfiguration), typeof(MyThirdConfiguration))]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}
|
||||
|
||||
[Configuration]
|
||||
public class MySecondConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual AboutController AboutController()
|
||||
{
|
||||
return new AboutController();
|
||||
}
|
||||
}
|
||||
|
||||
[Configuration]
|
||||
public class MyThirdConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual SomeOtherController SomeOtherController()
|
||||
{
|
||||
return new SomeOtherController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Chaining [Import] Directives</title>
|
||||
|
||||
<para>Types pointed to by one <literal>[Import]</literal> attribute
|
||||
may in turn have their own <literal>[Import]</literal> attributes
|
||||
pointing to yet more types to scan. Using this approach, its possible
|
||||
to specify perhaps only a single 'root' class from which to 'begin'
|
||||
the scan and leverage the <literal>[Import]</literal> attribute to
|
||||
'chain' successive types into the scanning scope, transitively
|
||||
pointing from one <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>-attributed
|
||||
type to the next as in the following example where
|
||||
<literal>MyConfigurationClass</literal> has an
|
||||
<literal>[Import]</literal> attribute pointing to the
|
||||
<literal>MySecondConfiguration</literal> class which in turn has an
|
||||
<literal>[Import</literal>] attribute pointing to the
|
||||
<literal>MyThirdConfiguration</literal> class.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[Import(typeof(MySecondConfiguration))]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}
|
||||
|
||||
[Configuration]
|
||||
[Import(typeof(MyThirdConfiguration))]
|
||||
public class MySecondConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual AboutController AboutController()
|
||||
{
|
||||
return new AboutController();
|
||||
}
|
||||
}
|
||||
|
||||
[Configuration]
|
||||
public class MyThirdConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual SomeOtherController SomeOtherController()
|
||||
{
|
||||
return new SomeOtherController();
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>Given this series of transitive or 'chained'
|
||||
<literal>[Import]</literal>attributes, the
|
||||
<literal>CodeConfigApplicationContext</literal> would only need to be
|
||||
told to scan the single <literal>MyConfigurationClass</literal> type
|
||||
in order to effectively scan and discover the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
methods contained all three <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
types. Using this approach, its possible to use a compositional
|
||||
approach to segregate <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
methods into multiple<literal> <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
classes and then chain them together just as one might do with XML
|
||||
based configuration files for many of the other
|
||||
<literal>IApplicationContext</literal> implementations.</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="importresource-attribute-reference">
|
||||
<title>[ImportResource] Attribute</title>
|
||||
|
||||
<para>Just as the <literal>[Import]</literal> attribute provides the
|
||||
ability to reference and import additional types attributed with the
|
||||
<literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link>
|
||||
</literal>attribute, the <literal>[ImportResrource]</literal> attribute
|
||||
permits referencing and importing Object Defintions from any
|
||||
<literal>IResource</literal> implementation including those defined
|
||||
natively in Spring.NET ("<literal>file://</literal>",
|
||||
"<literal>assembly://</literal>", etc.).</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the ImportResourceAttribute</title>
|
||||
|
||||
<para></para>
|
||||
|
||||
<sect3>
|
||||
<title>Specifying an IResource</title>
|
||||
|
||||
<para>To import an <literal>IResource</literal>, simply reference its
|
||||
path in the <literal>[ImportResource]</literal> attribute. In the
|
||||
following example, the embedded assembly resource
|
||||
<literal>ObjectDefinitions.xml</literal> is being imported into the
|
||||
process of scanning and parsing the
|
||||
<literal>MyConfigurationClass</literal> type. This makes all of the
|
||||
object definitions present in the embedded
|
||||
<literal>ObjectDefinitions.xml</literal> file available to the
|
||||
<literal>CodeConfigApplicationContext</literal> as it builds its
|
||||
Object Defintions.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[ImportResource("assembly://MyApplication.Config/MyCompany.MyApplication.Config/ObjectDefinitions.xml")]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Specifying Multiple IResources</title>
|
||||
|
||||
<para>To import multiple <literal>IResource</literal>s, simply provide
|
||||
multiple <literal>[ImportResource] </literal>attributes, each with the
|
||||
single resource to import. The following example demonstrates
|
||||
importing an embedded assembly resource as well as two XML files on
|
||||
disk.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[ImportResource("assembly://MyApplication.Config/MyCompany.MyApplication.Config/ObjectDefinitions.xml")]
|
||||
[ImportResource("file://ServiceObjectDefinitions.xml")]
|
||||
[ImportResource("file://c:/MySpecialConfigLocation/Deployment/SiteB/RepositoryObjectDefinitions.xml")]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Specifying a specific IObjectDefintionReader to Parse the
|
||||
IResource</title>
|
||||
|
||||
<para>By default, the<literal> [ImportResource]</literal> attribute
|
||||
will use the Spring.NET provided
|
||||
<literal>XmlObjectDefinitionReader</literal> to parse the imported
|
||||
<literal>IResource</literal>. If your imported resource cannot be
|
||||
parsed with the <literal>XmlObjectDefinitionReader</literal> then you
|
||||
can provide the type of the specific implementation of
|
||||
<literal>IObjectDefinitionReader</literal> that the<literal>
|
||||
[ImportResource]</literal> process should use. Note that this provided
|
||||
type must implement the <literal>IObjectDefinitionReader</literal>
|
||||
interface or an Exception will be thrown when the
|
||||
<literal>[ImportResource]</literal> attribute is evaluated.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[ImportResource("assembly://MyApplication.Config/MyCompany.MyApplication.Config/ObjectDefinitions.CSV", DefinitionReader = typeof(MyCommaSeparatedValueObjectDefinitionReader))]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="lazy-attribute-reference">
|
||||
<title>[Lazy] Attribute</title>
|
||||
|
||||
<para>The <literal>[Lazy]</literal> attribute allows you to specify that
|
||||
the object described by the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
should either be be lazily or eagerly instantiated.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the Lazy Attribute</title>
|
||||
|
||||
<para></para>
|
||||
|
||||
<sect3>
|
||||
<title>Specifying Lazy Instantiation</title>
|
||||
|
||||
<para>To specify Lazy Instantiation of any singleton object by the
|
||||
<literal>CodeConfigApplicationContext</literal>, apply the<literal>
|
||||
[Lazy] </literal>attribute to any <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>-attributed
|
||||
method as in the following example. Note that the default usage of
|
||||
the<literal>[Lazy]</literal> attribute sets Lazy = true and so
|
||||
<literal>[Lazy]</literal> and <literal>[Lazy(true)]</literal> are
|
||||
considered functionally equivalent. Also note that specification of
|
||||
lazy instantiation is only valid for Singleton-scoped objects; any
|
||||
attempt to apply the <literal>[Lazy]</literal> attribute to a
|
||||
non-singleton-scoped <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
method will result in an exception thrown by the underlying
|
||||
ApplicationContext.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
[Lazy] //functionally equivalent to [Lazy(true)]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
[Lazy] //invalid here because the scope is non-Singleton
|
||||
[Scope(ObjectScope.Prototype)]
|
||||
public virtual InvalidController InvalidController()
|
||||
{
|
||||
return new InvalidController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Specifying Non-Lazy (eager) Instantiation</title>
|
||||
|
||||
<para>As the default instantiation behavior for the
|
||||
<literal>CodeConfigApplicationContext</literal> is to perform eager
|
||||
instantiation, no special attribute needs to be applied to achieve
|
||||
eager instantiation of the object. However, the
|
||||
<literal>[Lazy]</literal> attribute will accept a
|
||||
<literal>bool</literal> value of <literal>false</literal> if you
|
||||
desire to be explicit about the <literal>[Lazy]</literal> setting for
|
||||
the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link>
|
||||
</literal>as shown in the following code snippet.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
[Lazy(false)] //functionally equivalent to simply not applying the [Lazy] attribute at all
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="scope-attribute-reference">
|
||||
<title>[Scope] Attribute</title>
|
||||
|
||||
<para>The [Scope] attribute permits you to declare the lifetime of the
|
||||
object managed by the <literal>CodeConfigApplicationContext</literal> for
|
||||
each <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>-attributed
|
||||
method.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Scope Attribute Usage</title>
|
||||
|
||||
<para>The <literal>[Scope]</literal> attribute accepts a single
|
||||
<literal>ObjectScope</literal> <literal>enum</literal> argument as
|
||||
defined by Spring.NET and demonstrated in the following snippet:</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class MyConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
[Scope(ObjectScope.Prototype)]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
return new HomeController();
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
[Scope(ObjectScope.Singleton)] //technically redundant since all types default to Singleton ObjectScope
|
||||
public virtual CustomerRepository CustomerRepository()
|
||||
{
|
||||
return new CustomerRepository();
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
[Scope(ObjectScope.Session)]
|
||||
public virtual UserSettings UserSettings()
|
||||
{
|
||||
return new UserSettings();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
536
doc/reference/src/codeconfig-context.xml
Normal file
536
doc/reference/src/codeconfig-context.xml
Normal file
@@ -0,0 +1,536 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter version="5" xml:id="codeconfig-context"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:ns5="http://www.w3.org/1998/Math/MathML"
|
||||
xmlns:ns42="http://www.w3.org/2000/svg"
|
||||
xmlns:ns4="http://www.w3.org/1999/xlink"
|
||||
xmlns:ns3="http://www.w3.org/1999/xhtml"
|
||||
xmlns:ns="http://docbook.org/ns/docbook">
|
||||
<title>CodeConfigApplicationContext Reference</title>
|
||||
|
||||
<para>The <literal>CodeConfigApplicationContext</literal> is an
|
||||
implementation of <literal>IApplicationContext</literal> designed to gather
|
||||
its configuration from code-based sources as opposed to XML-based sources as
|
||||
is the common case with most other <literal>IApplicationContext</literal>
|
||||
implementations provided by Spring.NET.</para>
|
||||
|
||||
<para>This chapter introduces the CodeConfigApplicationContext and how you
|
||||
can use .NET code to configure the Spring.NET container instead of XML
|
||||
files. For a general overview on the design of the Spring.NET container
|
||||
please see <link
|
||||
ns4:href="http://www.springframework.net/doc-latest/reference/html/objects.html#objects-basics">container
|
||||
overview</link>. The distribution includes three sample applications, two
|
||||
console applications (the familiar MovieFinder and a prime number generator)
|
||||
and a ASP.NET MVC web application. Refer to the <link
|
||||
linkend="sample-apps">examples section</link> for more information.</para>
|
||||
|
||||
<note>
|
||||
<para>The code-based configuration support requires .NET 2.0 or higher and
|
||||
solutions that depend upon CodeConfig must be compiled with Visual Studio
|
||||
2008 or later.</para>
|
||||
</note>
|
||||
|
||||
<sect1>
|
||||
<title>Concepts</title>
|
||||
|
||||
<para>Internally, Spring.NET has a metadata model around the classes it is
|
||||
responsible for managing, the main abstraction in this metadata model is
|
||||
the interface <interfacename>IObjectDefinition</interfacename>. The
|
||||
<interfacename>IObjectDefinition</interfacename> serves as the 'recipie'
|
||||
that Spring.NET uses to perform dependency injection. In the case of
|
||||
XML-based configuration sources, XmlApplicationContext parses XML files to
|
||||
populate the metadata model. In the case of CodeConfig, the
|
||||
<literal>CodeConfigApplicationContext</literal> scans one or more
|
||||
assemblies containing one or more types attributed with the <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
attribute, parses them to construct appropriate
|
||||
<literal>ObjectDefinition</literal> instances, and registers those Object
|
||||
Definitions with the <literal>IApplicationContext</literal> for use. You
|
||||
can also mix-and-match configuration sources, with some object definitions
|
||||
originating in XML and others in code.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Using the CodeConfigApplicationContext</title>
|
||||
|
||||
<para>The <literal>CodeConfigApplicationContext</literal> usage pattern
|
||||
consists of the following high-level steps:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Instantiate an instance of the
|
||||
<literal>CodeConfigApplicationContext</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>[optional]</emphasis> Provide one ore more filtering
|
||||
constraints to control the Assemblies and/or Types to participate in
|
||||
the scanning</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Perform the actual scanning</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Initialize (refresh) the
|
||||
<literal>CodeConfigApplicationContext</literal> which creates the
|
||||
object definition and eagerly instantiates singleton objects.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Mixing and matching configuration metadata formats</title>
|
||||
|
||||
<para>You can also use a combination of XML and Code base configuration metadata to configure
|
||||
the Spring.NET container. If you are an existing user of Spring.NET, incrementally adopting
|
||||
the code base configuration model will be a common use-case. In this scenario you should use
|
||||
the component-scan XML namespace to reference configuration metadata. Using the
|
||||
component-scan namespace requires you to register a custom namespace parser in App.config.
|
||||
Below is an example showing the use of the code config namespace</para>
|
||||
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:context="http://www.springframework.net/context">
|
||||
|
||||
<context:component-scan base-assemblies=""/>
|
||||
|
||||
<!-- <object/> definitions here -->
|
||||
|
||||
|
||||
</objects>
|
||||
</programlisting>
|
||||
|
||||
<para>The base-assemblies attribute allows you to express limitations
|
||||
of Assemblies to scan via a comma seperated list of assembly names.
|
||||
The filter is a StartsWith filter</para>
|
||||
|
||||
<para>You will also need to configure the context namespace parser in
|
||||
the main .NET application configuraiton file as shown below</para>
|
||||
|
||||
<programlisting language="myxml"><configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="spring">
|
||||
<!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity -->
|
||||
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<spring>
|
||||
<parsers>
|
||||
<parser type="Spring.Context.Config.ContextNamespaceParser, Spring.Core.Configuration" />
|
||||
</parsers>
|
||||
</spring>
|
||||
|
||||
</configuration></programlisting>
|
||||
|
||||
|
||||
|
||||
<para>You can also start from a CodeConfig class and import XML based
|
||||
object defintions. The example below shows loading of an embedded XML
|
||||
resource file using the <literal>[ImportResource]</literal>
|
||||
attribute.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[ImportResource("assembly://MyApp/MyApp.MyNamespace.MyConfig/ObjectDefinitions.xml"))]
|
||||
public class DataModuleConfigurationClass
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual SomeType SomeType()
|
||||
{
|
||||
return new SomeType();
|
||||
}
|
||||
}</programlisting>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Scanning Basics</title>
|
||||
|
||||
<para>The behavior of the <literal>CodeConfigApplicationContext</literal>
|
||||
scanning operation can be controlled by the following constraints:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Assembly Inclusion Constraint</emphasis></para>
|
||||
|
||||
<para>Only assemblies matching this contraint will be scanned;
|
||||
defaults to 'all assemblies'.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Type Inclusion Contraint</emphasis></para>
|
||||
|
||||
<para>Only types matching this contraint in assemblies matching the
|
||||
<emphasis>Assembly Inclusion Constraint</emphasis> will be scanned;
|
||||
defaults to 'all types'.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<sect2>
|
||||
<title>Scaning all assemblies</title>
|
||||
|
||||
<para>The simplest way to get started using code-based configuration is
|
||||
to instruct the context to scan all assemblies, as shown below</para>
|
||||
|
||||
<programlisting language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanAllAssemblies();
|
||||
ctx.Refresh();</programlisting>
|
||||
|
||||
<note>
|
||||
<para>Despite the name of the method 'ScanAllAssemblies', not all
|
||||
assemblies need to be scanned for [Configuraiton] attributes. There is
|
||||
an implicit filter that exclude the .NET BCL libraries as well as the
|
||||
Spring.NET assemblies since these will never contain any
|
||||
[Configuration] attributed classes. The name 'ScanAllAssemblies'
|
||||
should be interpreted as scanning all of the other assemblies you
|
||||
reference in your application.</para>
|
||||
</note>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Scanning specific assemblies and types</title>
|
||||
|
||||
<para>While the scanning process is very rapid (as compared to the
|
||||
overhead of parsing XML files) you may want to control the scope of the
|
||||
scanning operations to match your deployment or other usage models. To
|
||||
facilitate control of the scope of the scanning operation, the
|
||||
<literal>CodeConfigApplicationContext</literal> provides several
|
||||
<literal>.ScanXXX()</literal> methods that accept constraints to be
|
||||
applied to the assemblies and types during the scanning process. The
|
||||
format of these constraints is that of
|
||||
<literal>Predicate<T></literal> where <literal>T</literal> is
|
||||
either <literal>System.Reflection.Assembly</literal> or
|
||||
<literal>System.Type</literal>, respectively. Recall that
|
||||
<literal>Predicate<T></literal> is any method that accepts a
|
||||
single parameter of <literal>Type T</literal> and returns a
|
||||
<literal>bool</literal>.</para>
|
||||
|
||||
<para>The list of scan methods and brief description is shown
|
||||
below</para>
|
||||
|
||||
<table>
|
||||
<title>Description</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>ScanAllAssemblies()</literal></entry>
|
||||
|
||||
<entry>Scans all assemblies, except those in the .NET BCL and
|
||||
Spring distribution</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>ScanWithTypeFilter(Predicate<Type>
|
||||
typePredicate)</literal></entry>
|
||||
|
||||
<entry>Scans only those types that match the
|
||||
<literal>typePredicate</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>ScanWithAssemblyFilter(Predicate<Assembly>
|
||||
assemblyPredicate)</literal></entry>
|
||||
|
||||
<entry>Scans only those assemblines that match the
|
||||
<literal>assemblyPredicate</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>Scan(Predicate<Assembly>
|
||||
assemblyPredicate, Predicate<Type>
|
||||
typePredicate)</literal></entry>
|
||||
|
||||
<entry>Scans the AppDomain root path for assemblies that match
|
||||
the <literal>assemblyPredicate</literal> and types that match
|
||||
the <literal>typePredicate</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>Scan(AssemblyObjectDefinitionScanner
|
||||
scanner)</literal></entry>
|
||||
|
||||
<entry>Performs the scan using the settings encapsulated in the
|
||||
provided <literal>ObjectDefintionScanner</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>Other sections below provide a more detailed description and usage
|
||||
examples for the scan methods.</para>
|
||||
|
||||
<para>Note that as with any <literal>Predicate<T></literal>
|
||||
construct, the <literal>Predicate<Assembly></literal> and
|
||||
<literal>Predicate<Type></literal> constraints may be of arbitrary
|
||||
complexity, formulated using any combination of standard C# AND
|
||||
(<literal>&&</literal>), OR (<literal>||</literal>), and NOT
|
||||
(<literal>!</literal>) operators.</para>
|
||||
|
||||
<para>The following example matches assemblies with names containing
|
||||
"Config" but NOT containing "Configuration" OR containing
|
||||
"Services":</para>
|
||||
|
||||
<programlisting language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanWithAssemblyFilter(assy => (assy.Name.FullName.Contains("Config") && !assy.Name.FullName.Contains("Configuration")) || assy.Name.FullName.Contains("Services");</programlisting>
|
||||
|
||||
<para>Because its merely a .NET delegate, note that it is also possible
|
||||
to pass any arbitrary method that satisfies the contract
|
||||
(<literal>Predicate<T></literal>), so assuming that the method
|
||||
<literal>IsOneOfOurConfigAssemblies</literal> is defined elsewhere as
|
||||
follows...</para>
|
||||
|
||||
<programlisting language="csharp">private bool IsOneOfOurConfigAssemblies(Assembly assy)
|
||||
{
|
||||
return (assy.Name.FullName.Contains("Config") && !assy.Name.FullName.Contains("Configuration")) || assy.Name.FullName.Contains("Services");
|
||||
};</programlisting>
|
||||
|
||||
<para>...its possible to express the constraint in the call to
|
||||
.Scan(...) much more succinctly as follows:</para>
|
||||
|
||||
<programlisting language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanWithAssemblyFilter(IsOneOfOurConfigAssemblies);</programlisting>
|
||||
|
||||
<para>None of this is anything other than simple .NET Delegate handling,
|
||||
but its important to take note that the full flexibility of .NET
|
||||
Delegates and lambda expressions is at your disposal for formulating and
|
||||
passing scanning constraints.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Assembly Inclusion Constraints</title>
|
||||
|
||||
<para>To facilitate limiting the scope of scanning at the Assembly
|
||||
level, the <literal>CodeConfigApplicationContext</literal> provides
|
||||
several <literal>.ScanXXX()</literal> method signatures that accept a
|
||||
constraint to be applied to the assemblies at scan time. The format of
|
||||
this constraint matches
|
||||
<literal>Predicate<System.Reflection.Assembly></literal> (e.g. any
|
||||
delegate method that accepts a single
|
||||
<literal>System.Reflection.Assembly</literal> param and returns a
|
||||
<literal>bool</literal>).</para>
|
||||
|
||||
<para>As an example, the following snippet demonstrates the invocation
|
||||
of the scanning operation such that it will only scan assemblies whose
|
||||
filename begins with the string
|
||||
"<literal>MyCompany.MyApplication.Config.</literal>" and so would match
|
||||
assemblies like
|
||||
<literal>MyCompany.MyApplication.Config.Services.dll</literal> and
|
||||
<literal>MyCompany.MyApplication.Config.Infrastructure.dll</literal> but
|
||||
would not match an assembly named
|
||||
<literal>MyCompany.MyApplication.Core.dll</literal>.<programlisting
|
||||
language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanWithAssemblyFilter(assy => assy.Name.FullName.StartsWith("MyCompany.MyApplication.Config."));</programlisting>Because
|
||||
the <literal>Predicate<System.Reflection.Assembly></literal> has
|
||||
access to the full reflection metadata of each assembly, it is also
|
||||
possible to indicate assemblies to scan based on properties of one or
|
||||
more contained types as in the following example that will scan any
|
||||
assembly that contains at least one <literal>Type</literal> whose name
|
||||
ends in "<literal>Config</literal>". Note that even though this
|
||||
constraint is dependent upon <literal>Type</literal> metadata, it is
|
||||
still a functional <literal>Assembly</literal> contraint, resulting in
|
||||
filtering only at the Assembly level.</para>
|
||||
|
||||
<programlisting language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanWithAssemblyFilter(a => a.GetTypes().Any(assy => assy.GetTypes().Any(type => type.FullName.EndsWith("Config"))));</programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Type Inclusion Constraints</title>
|
||||
|
||||
<para>To limit the scope of scanning of types within assemblies, the
|
||||
<literal>CodeConfigApplicationContext</literal> provides several
|
||||
<literal>.ScanXXX()</literal> method signatures that accept a constraint
|
||||
to be applied to include types within assemblies at scan time. The
|
||||
format of this contraint matches
|
||||
<literal>Predicate<System.Type></literal> (e.g. any delegate
|
||||
method that accepts a single <literal>System.Type</literal> param and
|
||||
returns a <literal>bool</literal>).</para>
|
||||
|
||||
<para>As an example, the following snippet demonstrates the invocation
|
||||
of the scanning operation such that it will only scan types whose names
|
||||
contain the string "Config" and so would match types named
|
||||
"<literal>MyConfiguration</literal>",
|
||||
"<literal>ServicesConfiguration</literal>", and
|
||||
"<literal>ConfigurationSettings</literal>" but not
|
||||
"<literal>MyClass</literal>".</para>
|
||||
|
||||
<programlisting language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanWithTypeFilter(type => type.FullName.Contains("Config");</programlisting>
|
||||
|
||||
<para>There are two important aspects to take note of in re: the
|
||||
behavior of the <literal>CodeConfigApplicationContext</literal> with
|
||||
regards to <emphasis>Type Inclusion
|
||||
Constraints</emphasis><emphasis></emphasis></para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Type Inclusion Constraints</emphasis> are applied
|
||||
only to types defined in assemblies that also satisfy the
|
||||
<emphasis>Assembly Inclusion Constraint</emphasis></para>
|
||||
|
||||
<para>No matter whether any given <literal>Type</literal> satisfies
|
||||
the <emphasis>Type Inclusion Contstraint</emphasis>, if the
|
||||
<literal>Type</literal> is defined in an assembly that fails to
|
||||
satisfy the <emphasis>Assembly Inclusion Constraint</emphasis>, the
|
||||
<literal>Type</literal> will not be scanned for Object
|
||||
Defintions.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>There is always an implicit additional <emphasis>Type
|
||||
Inclusion Constraint</emphasis> of "...and the
|
||||
<literal>Type</literal> must have the <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
attribute applied to it"</para>
|
||||
|
||||
<para>No Type that does not have the <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
attribute applied to its declaration will ever be scanned regardless
|
||||
of any <emphasis>Type Inclusion Constraint</emphasis>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Advanced Scanning Behavior</title>
|
||||
|
||||
<para>In some cases, you may want more fine-grained control of the
|
||||
scanning behavior the <literal>CodeConfigApplicationContext</literal>. In
|
||||
this section, we explore the various techniques for achieving this level
|
||||
of control.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Combining Root Path, Assembly Constraints, and Type
|
||||
Constraints</title>
|
||||
|
||||
<para>The <literal>CodeConfigApplicationContext</literal> provides
|
||||
several <literal>.ScanXXX(...)</literal> method overloads that accept
|
||||
both an Assembly Constraint and a Type Constraint. These may be combined
|
||||
as in the following example:</para>
|
||||
|
||||
<programlisting language="csharp">var ctx = new CodeConfigApplicationContext();
|
||||
ctx.Scan(assy => assy.FullName.Name.BeginsWith("Config"), type => type.Name.Contains("Infrastructure"));</programlisting>
|
||||
|
||||
<para>Note that it is not possible to exclude specific types from the
|
||||
scanning process using these overloads of the
|
||||
<literal>.Scan(...)</literal> method. To get type-exclusion control, you
|
||||
must instantiate and pass in your own instance of the
|
||||
<literal>AssemblyObjectDefinitionScanner</literal> as described in the
|
||||
following section(s).</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Using your own AssemblyObjectDefintionScanner Instance</title>
|
||||
|
||||
<para>If you need more fine-grained control of the scanning behavior of
|
||||
the <literal>CodeConfigApplicationContext</literal>, you can instantiate
|
||||
and configure your own instance of the
|
||||
<literal>AssemblyObjectDefinitionScanner</literal> and pass it to the
|
||||
<literal>.Scan(...)</literal> method directly. The
|
||||
<literal>AssemblyObjectDefinitonScanner</literal> provides many methods
|
||||
for defining the contraints that will control the scanning
|
||||
process.</para>
|
||||
|
||||
<sect3>
|
||||
<title>Scanning Specific Assemblies and Types</title>
|
||||
|
||||
<para>The <literal>AssemblyObjectDefinitionScanner</literal> provides
|
||||
methods that permit specific assemblies or types to be included or
|
||||
excluded.</para>
|
||||
|
||||
<programlisting language="csharp">var scanner = new AssemblyObjectDefinitionScanner();
|
||||
|
||||
scanner.AssemblyHavingType<MyConfigurations>(); //add the assembly containing this type to the list of assemblies to be scanned
|
||||
scanner.IncludeType<MySpecialConfiguration>(); //add this specific type the list of types to be scanned
|
||||
scanner.ExcludeType<MyConfigurationToBeIgnored>(); //exclude this specific type from the list of types to be scanned
|
||||
|
||||
var ctx = new CodeConfigApplicationContext();
|
||||
ctx.Scan(scanner);</programlisting>
|
||||
|
||||
<para>For those that prefer a more fluent feel to the
|
||||
<literal>AssemblyObjectDefinitionScanner</literal> API, there are
|
||||
methods that permit successive filter criteria to be strung together
|
||||
in a sequence as in the following example:</para>
|
||||
|
||||
<programlisting language="csharp">var scanner = new AssemblyObjectDefinitionScanner();
|
||||
|
||||
scanner
|
||||
.WithAssemblyFilter(assy => assy.FullName.Name.StartsWith("Config"))
|
||||
.WithIncludeFilter(type => type.Name.Contains("MyApplication"))
|
||||
.WithExcludeFilter(type => type.Name.EndsWith("Service"))
|
||||
.WithExcludeFilter(type => type.Name.StartsWith("Microsoft"));
|
||||
|
||||
var ctx = new CodeConfigApplicationContext();
|
||||
ctx.Scan(scanner);</programlisting>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>Use of XML Namespace and scanning</title>
|
||||
<para> By default, classes attributed with [Component] , [Repository] , [Service] ,
|
||||
[Controller] , [Configuration] or a custom attribute that extends [Component] are the only
|
||||
detected candidate components. However, you can modify and extend this behavior simply by
|
||||
applying custom filters. Add them as <emphasis role="italic">include-filter</emphasis> or
|
||||
<emphasis role="italic">exclude-filter</emphasis> sub-elements of the component-scan
|
||||
element. Each filter element requires the type and expression attributes. The following
|
||||
table describes the filtering options. </para>
|
||||
<para>
|
||||
<table frame="all">
|
||||
<title>Table Filter Types</title>
|
||||
<tgroup cols="3">
|
||||
<colspec colname="c1" colnum="1" colwidth="1*"/>
|
||||
<colspec colname="c2" colnum="2" colwidth="4.24*"/>
|
||||
<colspec colname="c3" colnum="3" colwidth="3.85*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Filter Type</entry>
|
||||
<entry>Example Expression</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>attribute</entry>
|
||||
<entry><literal>Spring.Stereotype.RepositoryAttribute, Spring.Core</literal></entry>
|
||||
<entry> An attribute to be present at the type level in target components. </entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>assignable</entry>
|
||||
<entry><literal>My.Namespace.IFoo, My.Assembly</literal></entry>
|
||||
<entry> A class (or interface) that the target components are assignable to
|
||||
(extend/implement). </entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>regex</entry>
|
||||
<entry><literal>My.NameSpace.*.*Dao</literal></entry>
|
||||
<entry> A regex expression to be matched by the target components class names.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>custom</entry>
|
||||
<entry><literal>My.Namespace.MyTypeFilter, My.Assembly</literal></entry>
|
||||
<entry> A custom implementation of the
|
||||
<literal>Spring.Context.Attributes.TypeFilters.ITypeFilter</literal> interface. </entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
<para> The following example shows the XML configuration ignoring all [Repository] attributed
|
||||
classes and only scanning types with names that end with Dao using "stub" repositories
|
||||
instead. </para>
|
||||
<programlisting><objects>
|
||||
|
||||
<context:component-scan base-assemblies="My.Namespace">
|
||||
<context:include-filter type="regex" expression=".*Dao"/>
|
||||
<context:exclude-filter type="annotation" expression="Spring.Stereotype.RepositoryAttribute, Spring.Core"/>
|
||||
</context:component-scan>
|
||||
|
||||
</beans> </programlisting>
|
||||
</sect1>
|
||||
</chapter>
|
||||
700
doc/reference/src/codeconfig-migration-example.xml
Normal file
700
doc/reference/src/codeconfig-migration-example.xml
Normal file
@@ -0,0 +1,700 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter version="5" xml:id="codeconfig-migration-example"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:ns5="http://www.w3.org/1998/Math/MathML"
|
||||
xmlns:ns42="http://www.w3.org/2000/svg"
|
||||
xmlns:ns4="http://www.w3.org/1999/xlink"
|
||||
xmlns:ns3="http://www.w3.org/1999/xhtml"
|
||||
xmlns:ns="http://docbook.org/ns/docbook">
|
||||
<title>Introducing CodeConfig</title>
|
||||
|
||||
<sect1>
|
||||
<title>A Dependency Injection Example</title>
|
||||
|
||||
<para>We will introduce the new code based approach by working with a very
|
||||
simple application that will provide us the context to understand the
|
||||
concepts of CodeConfig. We start by examining a sample application that
|
||||
uses Spring.NET configured via ‘traditional’ XML configuration files. Then
|
||||
we show how CodeConfig can be used to achieve the same results without any
|
||||
XML configuration files at all.</para>
|
||||
|
||||
<para>To begin with, let’s explore the sample application that we will be
|
||||
working with. This sample app is included in the Spring.NET CodeConfig
|
||||
download package in the
|
||||
<literal>/examples/Spring.CodeConfig.Migration</literal> folder.</para>
|
||||
|
||||
<para>To keep things simple, it’s just a .NET console application designed
|
||||
to calculate and display the prime numbers between zero and an arbitrary
|
||||
maximum number. There are four classes that must collaborate together to
|
||||
do the work: <literal>ConsoleReporter</literal>,
|
||||
<literal>PrimeGenerator</literal>,
|
||||
<literal>PrimeEvaluationEngine</literal>, and
|
||||
<literal>OutputFormatter</literal>. <literal>ConsoleReporter</literal>
|
||||
depends on the <literal>PrimeGenerator</literal> which in turn depends on
|
||||
the <literal>PrimeEvaluationEngine</literal> to calculate the prime
|
||||
numbers. <literal>ConsoleReporter</literal> also depends on
|
||||
<literal>OutputFormatter</literal> to format the results. The main console
|
||||
application then simply asks <literal>ConsoleReporter</literal> to write
|
||||
its report and <literal>ConsoleReporter</literal> goes to work. The
|
||||
following Figure is a UML class diagram showing a simple way to visualize
|
||||
the dependencies between these objects.</para>
|
||||
|
||||
<para><screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/Migration_App_UML_Diagram.png">
|
||||
<info>
|
||||
<author>
|
||||
<personname></personname>
|
||||
</author>
|
||||
|
||||
<pubdate></pubdate>
|
||||
</info>
|
||||
</imagedata>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
|
||||
<para>A simple <literal>Main()</literal> method that would do this without
|
||||
the Spring.NET container could look something like Listing 1. Note the
|
||||
in-line injection of dependencies via constructor arguments that builds up
|
||||
the collaborating objects.</para>
|
||||
|
||||
<programlisting language="csharp" linenumbering="unnumbered">//Listing 1 (sample Main method not using Spring.NET)
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ConsoleReport report = new ConsoleReport(
|
||||
new OutputFormatter(),
|
||||
new PrimeGenerator(new PrimeEvaluationEngine()));
|
||||
|
||||
report.MaxNumber = 1000;
|
||||
report.Write();
|
||||
|
||||
Console.WriteLine("--- hit enter to exit --");
|
||||
Console.ReadLine();
|
||||
}</programlisting>
|
||||
|
||||
<para>Using Spring.NET, as opposed to manually injecting dependencies as
|
||||
in Listing 1, the collaborating objects are composed together with their
|
||||
dependencies injected by the Spring.NET container at run-time. Initially,
|
||||
the configuration of these objects is controlled from a Spring.NET XML
|
||||
configuration file (see Listing 2).</para>
|
||||
|
||||
<programlisting language="xml"><!-- Listing 2 (Spring.NET XML Configuration file, application-context.xml) -->
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<object name="ConsoleReport" type="Primes.ConsoleReport, Primes">
|
||||
<constructor-arg ref="PrimeGenerator"/>
|
||||
<constructor-arg ref="OutputFormatter"/>
|
||||
<property name="MaxNumber" value="1000"/>
|
||||
</object>
|
||||
|
||||
<object name="PrimeGenerator" type="Primes.PrimeGenerator, Primes">
|
||||
<constructor-arg>
|
||||
<object type="Primes.PrimeEvaluationEngine, Primes"/>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="OutputFormatter" type="Primes.OutputFormatter, Primes"/>
|
||||
|
||||
</objects></programlisting>
|
||||
|
||||
<para>In Listing 2 you can also see the use of “<literal>ref</literal>”
|
||||
element to refer to collaborating objects and the property
|
||||
“<literal>MaxNumber</literal>” being set to “<literal>1000</literal>” on
|
||||
the <literal>ConsoleReport</literal> object after it’s constructed. This
|
||||
is the maximum number up to which we want the software to calculate prime
|
||||
numbers. In Listing 3 we see the construction of the
|
||||
<literal>XmlApplicationContext</literal> which is initialized by passing
|
||||
it the name of the XML Configuration file. This container is then used to
|
||||
resolve the <literal>ConsoleReport</literal> object with all of its
|
||||
dependencies properly satisfied and its <literal>MaxNumber</literal>
|
||||
property assigned the value of <literal>1000</literal>.</para>
|
||||
|
||||
<programlisting language="csharp">//Listing 3 (initializing the XmlApplicationContext container)
|
||||
static void Main(string[] args)
|
||||
{
|
||||
IApplicationContext ctx = CreateContainerUsingXML();
|
||||
|
||||
ConsoleReport report = ctx["ConsoleReport"] as ConsoleReport;
|
||||
report.Write();
|
||||
|
||||
ctx.Dispose();
|
||||
|
||||
Console.WriteLine("--- hit enter to exit --");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static IApplicationContext CreateContainerUsingXML()
|
||||
{
|
||||
return new XmlApplicationContext("application-context.xml");
|
||||
}</programlisting>
|
||||
|
||||
<para>While this XML-based configuration is well-understood by Spring.NET
|
||||
users and others alike as a common method for expressing configuration
|
||||
settings, it suffers from several challenges common to all XML file
|
||||
including being overly-verbose and full of string-literals that are
|
||||
unfriendly to most of the modern refactoring tools.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Migration to CodeConfig</title>
|
||||
|
||||
<para>To reduce or even eliminate the use of XML for configuring the
|
||||
Spring.NET DI container, let’s look at how we can express the same
|
||||
configuration metadata in code using Spring.NET CodeConfig. There are
|
||||
several steps to using CodeConfig. We will look at each of them in the
|
||||
likely sequence that one would follow to convert an existing XML-based
|
||||
configuration for Spring.NET over to use the CodeConfig approach.</para>
|
||||
|
||||
<sect2>
|
||||
<title>The CodeConfig Classes</title>
|
||||
|
||||
<sect3>
|
||||
<title>Creating the CodeConfig Classes</title>
|
||||
|
||||
<para>First, we need to construct one or more classes to contain our
|
||||
configuration metadata and attribute them properly. Spring.NET
|
||||
CodeConfig relies upon attributes applied to classes and methods to
|
||||
convey its metadata. Shown in Listing 4 is the CodeConfig class
|
||||
(<literal>PrimesConfiguration</literal>) for our sample application.
|
||||
<programlisting language="csharp">// Listing 4, (Spring.NET Configuration Class, PrimesConfiguration.cs)
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using Primes;
|
||||
using Spring.Context.Attributes;
|
||||
|
||||
namespace SpringApp
|
||||
{
|
||||
[Configuration]
|
||||
public class PrimesConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual ConsoleReport ConsoleReport()
|
||||
{
|
||||
ConsoleReport report = new ConsoleReport(OutputFormatter(), PrimeGenerator());
|
||||
|
||||
report.MaxNumber = Convert.ToInt32(ConfigurationManager.AppSettings.Get("MaximumNumber"));
|
||||
return report;
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
public virtual IOutputFormatter OutputFormatter()
|
||||
{
|
||||
return new OutputFormatter();
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
public virtual IPrimeGenerator PrimeGenerator()
|
||||
{
|
||||
return new PrimeGenerator(new PrimeEvaluationEngine());
|
||||
}
|
||||
}
|
||||
}</programlisting></para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Elements of the CodeConfig Classes</title>
|
||||
|
||||
<para>Let’s explore the important elements of the CodeConfig file in
|
||||
Listing 4 to understand how it can convey the same information to the
|
||||
Spring.NET container as the XML file in Listing 2.</para>
|
||||
|
||||
<sect4>
|
||||
<title>The Class</title>
|
||||
|
||||
<para>At the class level, you will notice the
|
||||
<literal>PrimesConfiguration</literal> class has the<literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
attribute applied to it. During the initialization phase of the DI
|
||||
container, Spring.NET CodeConfig reads classes with these
|
||||
attributes. Note that there is no specific inheritance hierarchy
|
||||
required of a configuration class: no special base class or
|
||||
interface implementation is required, leaving you free to leverage
|
||||
inheritance and polymorphism to achieve some interesting
|
||||
configuration and composition scenarios. Also note these special
|
||||
identifying attributes are only applied to your CodeConfig classes,
|
||||
not the types for which they are providing object definition
|
||||
metadata. This means that your classes that do the work of your
|
||||
application (e.g., <literal>ConsoleReport</literal>,
|
||||
<literal>PrimeGenerator</literal>, etc.) are free to remain
|
||||
undiluted POCO (Plain-Old-CLR-Object) classes that have themselves
|
||||
no direct dependency on the Spring.NET framework.</para>
|
||||
</sect4>
|
||||
|
||||
<sect4>
|
||||
<title>The Methods</title>
|
||||
|
||||
<para>At the member level of the
|
||||
<literal>PrimesConfiguration</literal> class, you will notice
|
||||
several methods having the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute. This attribute identifies the method to which it is
|
||||
applied as being the logical representation of a single object
|
||||
definition for the Spring.NET container.</para>
|
||||
|
||||
<para>To begin understanding how this works let’s look at the
|
||||
simplest of the definitions, that of the OutputFormatter. Let’s
|
||||
start with the method visibility: all <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods must be declared both public and virtual.</para>
|
||||
|
||||
<sidebar>
|
||||
<title>Why must the [ObjectDef] methods be virtual?</title>
|
||||
|
||||
<para>The requirement for the <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods being virtual comes from the need when using CodeConfig
|
||||
for the container to proxy <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods on the <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes. When the container is asked for an object, this proxy
|
||||
intercepts the invocation of the <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods and ensures that requests for objects respect object
|
||||
scoping rules like singleton and prototype. Singleton scope
|
||||
ensures that if you ask the container multiple times for the same
|
||||
named object, it will always return the same instance rather than
|
||||
a new one each time. Singleton scope is common in server-side
|
||||
programming and is the default lifecycle in Spring.NET.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>The method return type, <literal>IOutputFormatter</literal>,
|
||||
becomes the type that the DI container will be configured to
|
||||
register. The method name itself,
|
||||
<literal>OutputFormatter</literal>, is the equivalent of the id or
|
||||
name that will be assigned to the object in the container. This name
|
||||
can also be controlled by setting the <literal>Names</literal>
|
||||
property on the <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
attribute itself.</para>
|
||||
|
||||
<para>The body of the <literal>OutputFormatter()</literal> method
|
||||
simply creates a new instance of the
|
||||
<literal>OutputFormatter</literal> and returns it. In simple terms,
|
||||
we can think of the<literal> OutputFormatter()</literal> method as a
|
||||
factory method that knows how to construct and return an instance of
|
||||
something that implements the <literal>IOutputFormatter</literal>
|
||||
interface (in this case, the concrete
|
||||
<literal>OutputFormatter</literal> class).</para>
|
||||
</sect4>
|
||||
|
||||
<sect4>
|
||||
<title>More Complex Methods</title>
|
||||
|
||||
<para>To understand a slightly more complex <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
method, let’s now examine the <literal>PrimeGenerator()</literal>
|
||||
method. Given what we already know about CodeConfig, it’s easy to
|
||||
see that the <literal>PrimeGenerator()</literal> method describes an
|
||||
Object Definition that will be registered with the container under
|
||||
the name “<literal>PrimeGenerator</literal>” (the method name) and
|
||||
the type <literal>IPrimeGenerator</literal> (the return type of the
|
||||
method).</para>
|
||||
|
||||
<para>The method needs to return a new
|
||||
<literal>PrimeGenerator</literal> but unlike the
|
||||
<literal>OutputFormater</literal> class that offers an empty default
|
||||
constructor, the <literal>PrimeGenerator</literal> class’ only
|
||||
public constructor requires an instance of the
|
||||
<literal>PrimeEvaluationEngine</literal> class be passed to it. To
|
||||
satisfy this constructor dependency, we simply create a new
|
||||
<literal>PrimeEvaluationEngine</literal> object in-line and pass it
|
||||
to the new <literal>PrimeGenerator</literal> class. In this way, the
|
||||
dependency between <literal>PrimeGenerator</literal> and
|
||||
<literal>PrimeEvaluationEngine</literal> is satisfied in much the
|
||||
same way as when coded ‘by hand’ as shown in Listing 1.</para>
|
||||
|
||||
<para>As a slightly more complex <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
example, let’s examine the <literal>ConsoleReport()</literal> method
|
||||
next. This method needs to return a new
|
||||
<literal>ConsoleReport</literal> instance, but as with the
|
||||
<literal>PrimeGenerator</literal> class we lack a zero-argument
|
||||
public constructor. The only public constructor of the
|
||||
<literal>ConsoleReport</literal> class requires an
|
||||
<literal>IOutputFormatter</literal> instance and an
|
||||
<literal>IPrimeGenerator</literal> instance be provided. In our call
|
||||
to new up an instance of the <literal>ConsoleReport</literal> class
|
||||
in the <literal>ConsoleReport()</literal> <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
method, we are invoking the other <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods themselves to return these types. Since these other methods
|
||||
in turn return <literal>IOutputFormatter</literal> and
|
||||
<literal>IPrimeGenerator</literal> instances respectively, calls to
|
||||
these other methods will satisfy the constructor dependency of the
|
||||
<literal>ConsoleReport</literal> class and thus permit us to create
|
||||
a new <literal>ConsoleReport</literal> to return at the end of the
|
||||
<literal>ConsoleReport()</literal> method itself. In this manner, we
|
||||
are delegating from one <literal>[ObjectDef] </literal>method to
|
||||
the other <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods to create the object graph that we seek to return from the
|
||||
call to the <literal>ConsoleReport()</literal> method.</para>
|
||||
</sect4>
|
||||
|
||||
<sect4>
|
||||
<title>Controlling Properties on Objects</title>
|
||||
|
||||
<para>But what about the “<literal>MaxNumber</literal>” property
|
||||
that is set for the <literal>ConsoleReport</literal> object in the
|
||||
XML file in Listing 2? As you can see from Listing 4, setting this
|
||||
property on our <literal>ConsoleReport</literal> object is as simple
|
||||
as…well, setting the property on our
|
||||
<literal>ConsoleReport</literal> object! Since our
|
||||
<literal>ConsoleReport()</literal> method merely has to return a new
|
||||
<literal>ConsoleReport</literal> instance, we are completely free to
|
||||
use any approach (in code) we choose to modify the
|
||||
<literal>ConsoleReport</literal> instance before we return it. In
|
||||
this case, it’s a simple matter of reading the value out of the
|
||||
<literal>App.Config</literal> file and then setting the property to
|
||||
the desired value before we return the instance of the
|
||||
<literal>ConsoleReport</literal> object from the method.</para>
|
||||
</sect4>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Creating and Initializing the Application Context</title>
|
||||
|
||||
<para>Once we have translated the XML configuration file in Listing 2
|
||||
into the CodeConfig class in Listing 4, we need to tell our application
|
||||
to use it. For that, we need to switch from encapsulating our container
|
||||
in the Spring.NET <literal>XmlApplicationContext</literal> to
|
||||
encapsulating it in the <literal>CodeConfigApplicationContext</literal>
|
||||
instead. Just as the <literal>XmlApplicationContext</literal> is
|
||||
designed to use XML as the initial entry point to its configuration
|
||||
settings, the <literal>CodeConfigApplicationContext</literal> is
|
||||
designed to scan assemblies for <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes and <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods as the initial entry point to its configuration settings.
|
||||
Listing 5 shows the<literal> CreateContainerUsingCodeConfig()</literal>
|
||||
method from the <literal>Program.cs</literal> file in the sample
|
||||
application that demonstrates this process.</para>
|
||||
|
||||
<programlisting language="csharp">//Listing 5 (bootstrapping the CodeConfigApplicationContext from Program.cs)
|
||||
private static IApplicationContext CreateContainerUsingCodeConfig()
|
||||
{
|
||||
CodeConfigApplicationContext ctx = new CodeConfigApplicationContext();
|
||||
ctx.ScanAllAssemblies();
|
||||
ctx.Refresh();
|
||||
return ctx;
|
||||
}</programlisting>
|
||||
|
||||
<para>After instantiating the
|
||||
<literal>CodeConfigApplicationContext</literal>, we next invoke the
|
||||
<literal>ScanAllAssemblies() </literal>method to perform the scanning
|
||||
for the <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>-attributed
|
||||
classes and <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>-attributed
|
||||
methods within our project. Lastly, the container is initialized by
|
||||
calling the <literal>Refresh()</literal> method and then the
|
||||
ready-to-use context is returned from the method. In the invocation of
|
||||
the <literal>ScanAllAssemblies()</literal> method, we are asking the
|
||||
<literal>CodeConfigApplicationContext</literal> to scan the current
|
||||
AppDomain’s root folder and all subfolders recursively for all
|
||||
assemblies that might contain CodeConfig classes (classes having the
|
||||
<link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
attribute).</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>More Granular Control Using CodeConfig</title>
|
||||
|
||||
<para>The example in Listing 4 and Listing 5 demonstrates only the most
|
||||
basic use-cases for CodeConfig. More granular control over each of the
|
||||
definitions is provided by applying additional attributes to the <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes and <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods and by setting various values on these attributes. Among these are
|
||||
the following:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal><link
|
||||
linkend="scope-attribute-reference">[Scope]</link></literal> for
|
||||
controlling object lifecycle settings on a <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
such as singleton, prototype, etc.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal><link
|
||||
linkend="import-attribute-reference">[Import]</link> </literal>for
|
||||
chaining <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes together so that you can logically divide your <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods among multiple classes in much the same way you may do so with
|
||||
multiple XML files that provide pointers to other XML files</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal><link
|
||||
linkend="importresource-attribute-reference">[ImportResource]</link></literal>
|
||||
for combining <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes with any of Spring.NET’s many implementations of its
|
||||
<literal>IResource</literal> abstraction (file://, assembly://, etc.),
|
||||
the most common one being an XML resource so that you can define part
|
||||
of your configuration metadata in <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes and other parts of it in XML files as either embedded
|
||||
resource(s) in your assemblies or as file(s) on disk.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal><link
|
||||
linkend="lazy-attribute-reference">[Lazy]</link></literal> for
|
||||
controlling lazy instantiation of singleton objects</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>If you require aliases (additional, multiple names) for the Type
|
||||
in the container, the <literal><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
attribute also accepts an array of strings that if provided will be
|
||||
registered as aliases for the Type registration.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>In addition, finer-grained control of the specific assemblies to
|
||||
scan, and specific <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes to include and/or exclude is supported by the scanning API. It is
|
||||
also possible to compose configurations by dividing your <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods into multiple different <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes and then to assemble them as building blocks to configure your
|
||||
container as it is initialized.</para>
|
||||
|
||||
<para>The CodeConfig approach enables us to express the same configuration
|
||||
metadata to our Dependency Injection container as the XML file in Listing
|
||||
2 had provided, but in a form that is at once both significantly more
|
||||
powerful and flexible as well as more resilient to the refactoring our
|
||||
container-managed application objects.</para>
|
||||
|
||||
<para>To address additional common non-XML configuration scenarios, such
|
||||
as the XML schemas for AOP and Transaction management, Spring.NET is also
|
||||
evolving a more fluent-style configuration API that will build upon
|
||||
CodeConfig in even more flexible ways in the near future including
|
||||
convention-based registration of objects.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Organizing and Composing Multiple [Configuration] Classes</title>
|
||||
|
||||
<para>The <link linkend="sample-apps">examples</link> referenced in this
|
||||
document and provided in this distribution almost all employ merely a
|
||||
single <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link> class
|
||||
from which their ApplicationContext is to be configured. For these simple
|
||||
examples this approach is viable but just as is the case when configuring
|
||||
the ApplicationContext via XML, any significantly complex solution is
|
||||
likely to require separating your <link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link> methods into
|
||||
multiple <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link>
|
||||
classes.</para>
|
||||
|
||||
<para>Just as there are several strategies for effectively managing
|
||||
multiple XML configuration files, so too are there many options available
|
||||
to the developer to organize and compose multiple <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link> classes
|
||||
together in a larger solution. This section doesn't attempt to cover all
|
||||
of the available options in deep detail, but is intended to provide a
|
||||
high-level understanding of some of the techniques that can be combined
|
||||
together to help manage multiple such classes. Users familair with the
|
||||
common techniques for composing together multiple XML configuration files
|
||||
for Spring.NET will recognize some of these same patterns applied to <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link> classes
|
||||
in the following sections as well.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Multiple Stand-Alone Configuration Classes</title>
|
||||
|
||||
<para>The simplest organization approach is providing multiple
|
||||
stand-alone <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link>
|
||||
classes. In this scenario, <link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link> methods are
|
||||
organized into separate <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link>
|
||||
classes but each of the <link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link>
|
||||
classes is entirely self-contained and unrealted to the others. The
|
||||
decomposition principles can of course be anything of your choosing. One
|
||||
simple possibility might be to divide your configuration data between
|
||||
different kinds of services as in the following example:</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class WcfServicesConfigurations
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual IWebService MySpecialService()
|
||||
{
|
||||
//construct and return a IWebService implementation here
|
||||
}
|
||||
}
|
||||
|
||||
[Configuration]
|
||||
public class RepositoryServicesConfigurations
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual ICustomerRepository MyCustomerRepository()
|
||||
{
|
||||
//construct and return a ICustomerRepository implementation here
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
public virtual IShippingRepository MyShippingRepository()
|
||||
{
|
||||
//construct and return a IShippingRepository implementation here
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>In this example, both of these <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
classes would need to be explicitly scanned and registered with the
|
||||
<literal><link
|
||||
linkend="codeconfig-context">CodeConfigApplicationContext</link></literal>
|
||||
since they each are completely stand-alone and both are needed for the
|
||||
proper configuration of the ApplicationContext. Since these two classes
|
||||
in this example have no interdependencies between them, each class may
|
||||
be placed into a different file or even assembly.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>High-Level [Configuration] Classes that [Import] Others</title>
|
||||
|
||||
<para>Another strategy for composing multiple <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes together is to devise one or more 'high-level entry-point'
|
||||
classes and leverage the <literal><link
|
||||
linkend="import-attribute-reference">[Import]</link></literal> attribute
|
||||
so that the scanning of the high-level class automatically imports one
|
||||
or more lower-level classes. The high-level classes may contain
|
||||
[ObjectDef] methods of their own or merely hold reference to one or
|
||||
more [Import] classes as needed.</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
[Import(typeof(MyWebServicesConfigurations))]
|
||||
[Import(typeof(MyMessagingServicesConfigurations))]
|
||||
[Import(typeof(MyPersistenceServicesConfigurations))]
|
||||
public class ServicesConfigurations
|
||||
{
|
||||
//rest of class here as needed
|
||||
}</programlisting>
|
||||
|
||||
<para>In this example, only the
|
||||
<literal>ServicesConfigurations</literal> class needs to be scanned
|
||||
because the <link
|
||||
linkend="import-attribute-reference"><literal>[Import]</literal></link>
|
||||
attributes point directly to the other classes to scan for
|
||||
<literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
and <literal linkend="objectdef-attribute-reference"><link
|
||||
linkend="objectdef-attribute-reference">[ObjectDef]</link></literal>
|
||||
metadata.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Referencing [ObjectDef]s from one [Configuration] Class in
|
||||
Another</title>
|
||||
|
||||
<para>Once you decompose your <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods into separate classes, often you will find that you have a need
|
||||
to reference the objects defined in one <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
class when coding the <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods in another <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
class. The architecture of Spring CodeConfig for .NET makes it simple to
|
||||
address this need: you can simply ask the ApplicationContext to resolve
|
||||
the needed Type.</para>
|
||||
|
||||
<para>To understand how this works, its first important to understand
|
||||
that <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
classes are themselves registered as types in the ApplicationContext
|
||||
<emphasis>in addition to</emphasis> the types defined in their <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods. Combining that knowledge with the special
|
||||
<literal>IApplicationContextAware</literal> interface in Spring.NET
|
||||
allows us to ask the ApplicationContext to inject
|
||||
<emphasis>itself</emphasis> into our <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
classes. This ApplicationContext is then available to us to resolve
|
||||
requests for needed types that may be defined elsewhere, whether in
|
||||
other <link
|
||||
linkend="configuration-attribute-reference"><literal>[Configuration]</literal></link>
|
||||
classes or perhaps even other XML files.</para>
|
||||
|
||||
<para>Let's explore the following example where the
|
||||
<literal>SecondConfiguration</literal> class needs access to the
|
||||
<literal>TransactionManager</literal> that is defined in the
|
||||
<literal>FirstConfiguration</literal> class in order to properly build
|
||||
and configure a <literal>CustomerRepository</literal> instance:</para>
|
||||
|
||||
<programlisting language="csharp">[Configuration]
|
||||
public class FirstConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
public virtual TransactionManager MySpecialTransactionManager()
|
||||
{
|
||||
return new TransactionManager();
|
||||
}
|
||||
}
|
||||
|
||||
[Configuration]
|
||||
public class SecondConfiguration : IApplicationContextAware //note the interface implementation
|
||||
{
|
||||
//field to hold the injected context
|
||||
private IApplicationContext _context;
|
||||
|
||||
//property setter defined by the IApplcationContextAware interface
|
||||
// so that the context can inject itself into the class
|
||||
public IApplicationContext ApplicationContext { set { _context = value; } }
|
||||
|
||||
[ObjectDef]
|
||||
public virtual ICustomerRepository CustomerRepository()
|
||||
{
|
||||
//to construct the CustomerRepository, we need a TransactionManager instance
|
||||
// as a constructor argument so let's ask the injected context to resolve one for us
|
||||
return new CustomerRepository(_context.GetObject<TransactionManager>());
|
||||
}
|
||||
}
|
||||
|
||||
//somewhere else in your solution the CustomerRepository class is defined as follows...
|
||||
public class CustomerRespository : ICustomerRespository
|
||||
{
|
||||
private TransactionManager _transactionManager;
|
||||
|
||||
public CustomerRespository(TransactionManager transactionManager)
|
||||
{
|
||||
_transactionManager = transactionManager;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>In this way, there is no direct coupling between <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
classes and the SecondConfiguration class is only aware of the
|
||||
ApplicationContext itself and the actual Types it needs to construct the
|
||||
Types described in its <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
methods.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
266
doc/reference/src/codeconfig-sample-apps.xml
Normal file
266
doc/reference/src/codeconfig-sample-apps.xml
Normal file
@@ -0,0 +1,266 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter version="5" xml:id="codeconfig-sample-apps"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:ns52="http://www.w3.org/1999/xhtml"
|
||||
xmlns:ns5="http://www.w3.org/1999/xlink"
|
||||
xmlns:ns4="http://www.w3.org/2000/svg"
|
||||
xmlns:ns3="http://www.w3.org/1998/Math/MathML"
|
||||
xmlns:ns="http://docbook.org/ns/docbook">
|
||||
<title>Sample Applications</title>
|
||||
|
||||
<section>
|
||||
<title>Overview</title>
|
||||
|
||||
<para>The Spring CodeConfig for .NET project includes three sample
|
||||
applications:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link
|
||||
linkend="sample-moviefinder-codeconfig">Spring.IoCQuickStart.MovieFinder</link></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link
|
||||
linkend="sample-mvc-codeconfig">Spring.MvcQuickStart</link></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link
|
||||
linkend="sample-migration-codeconfig">Spring.CodeConfig.Migration</link></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="sample-moviefinder-codeconfig">
|
||||
<title>Spring.IoCQuickStart.MovieFinder</title>
|
||||
|
||||
<para>The Spring.IoCQuickStart.MovieFinder sample application is the same
|
||||
fundamental code as provided in the sample app by the same name that is
|
||||
provided with <link
|
||||
ns5:href="http://springframework.net/download.html">the main Spring.NET
|
||||
Framework download package</link>. This section assumes you are already
|
||||
familiar with the sample application as provided in that download package.
|
||||
This version of this sample application has been modified to rely upon
|
||||
CodeConfig for its Object Definitions.</para>
|
||||
|
||||
<section>
|
||||
<title>Modifying App.config</title>
|
||||
|
||||
<para>The first modification to the existing sample application involves
|
||||
changes to the <literal><spring></literal> element in the
|
||||
App.config file:</para>
|
||||
|
||||
<programlisting language="xml"> <spring>
|
||||
|
||||
<parsers>
|
||||
<!-- Equivalent to 'NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));' -->
|
||||
<parser type="Spring.Context.Config.ContextNamespaceParser, Spring.Core.Configuration" />
|
||||
</parsers>
|
||||
|
||||
<context>
|
||||
<!-- using embedded assembly configuration file -->
|
||||
<resource uri="assembly://Spring.IocQuickStart.MovieFinder/Spring.IocQuickStart.MovieFinder/CodeConfigBootstrap.xml"/>
|
||||
</context>
|
||||
|
||||
</spring></programlisting>
|
||||
|
||||
<para>The important changes here are the introducton of the<literal>
|
||||
<parsers></literal> section (to register the
|
||||
<literal>ContextNamespaceParser</literal> required for CodeConfig) and
|
||||
the change of the <literal><resource></literal> element to point
|
||||
to the <literal>CodeConfigBootstrap.xml</literal> file instead of the
|
||||
<literal>Appcontext.xml</literal> file as before.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Replacing Appcontext.xml with CodeConfigBootstrap.xml</title>
|
||||
|
||||
<para>Where before the <literal>Appcontext.xml</literal> contained all
|
||||
of the XML-based object definitions for the application, in this case
|
||||
the <literal>CodeConfigBootstrap.xml</literal> merely contains the
|
||||
single instruction telling the context to use CodeConfig:</para>
|
||||
|
||||
<programlisting language="xml"><?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net"
|
||||
xmlns:context="http://www.springframework.net/context">
|
||||
|
||||
<description>An example that demonstrates code based configuration for object definitions.</description>
|
||||
|
||||
<context:code-config/>
|
||||
|
||||
</objects>
|
||||
</programlisting>
|
||||
|
||||
<para>In this case, the single
|
||||
<literal><context:code-config/></literal> element is sufficient to
|
||||
tell the context to perform scanning for its object definition
|
||||
metadata.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Introducing the MovieFinderConfiguration CodeConfig class</title>
|
||||
|
||||
<para>The final modification needed to migrate the sample application to
|
||||
rely upon CodeConfig is to author the classes that will provide the
|
||||
Object Definitions for the Application Context to discover when
|
||||
performing the scan. In the case of this simple application, this is
|
||||
encapsulated in the single new
|
||||
<literal>MovieFinderConfiguration</literal> class as shown in the
|
||||
following:</para>
|
||||
|
||||
<programlisting language="csharp"> [Configuration]
|
||||
public class MovieFinderConfiguration
|
||||
{
|
||||
|
||||
[ObjectDef]
|
||||
public virtual MovieLister MyMovieLister()
|
||||
{
|
||||
MovieLister movieLister = new MovieLister();
|
||||
movieLister.MovieFinder = FileBasedMovieFinder();
|
||||
return movieLister;
|
||||
|
||||
}
|
||||
|
||||
[ObjectDef]
|
||||
public virtual IMovieFinder FileBasedMovieFinder()
|
||||
{
|
||||
return new ColonDelimitedMovieFinder(new FileInfo("movies.txt"));
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>Using a combination of <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
and <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
attributes, this class faithfully reproduces the same Object Definition
|
||||
configuration as had been described by the
|
||||
<literal>Appcontext.xml</literal> file in the iniitial sample
|
||||
application as delivered with the main Spring.NET Framework
|
||||
download.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="sample-mvc-codeconfig">
|
||||
<title>Spring.MvcQuickStart</title>
|
||||
|
||||
<para>The Spring.MvcQuickStart sample application is the same fundamental
|
||||
code as provided in the sample app by the same name that is provided with
|
||||
<link ns5:href="http://springframework.net/download.html">the main
|
||||
Spring.NET Framework download package</link>. This section assumes you are
|
||||
already familiar with the sample application as provided in that download
|
||||
package. This version of this sample application has been modified to rely
|
||||
upon CodeConfig for its Object Definitions.</para>
|
||||
|
||||
<section>
|
||||
<title>Modifying Web.config</title>
|
||||
|
||||
<para>The first modification to the existing sample application involves
|
||||
changes to the <literal><spring></literal> element in the
|
||||
Web.config file:</para>
|
||||
|
||||
<programlisting language="xml"><spring>
|
||||
<parsers>
|
||||
<!-- Equivalent to 'NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));' -->
|
||||
<parser type="Spring.Context.Config.ContextNamespaceParser, Spring.Core.Configuration" />
|
||||
</parsers>
|
||||
|
||||
<context>
|
||||
<resource uri="~/Config/CodeConfigBootsrap.xml"/>
|
||||
</context>
|
||||
</spring></programlisting>
|
||||
|
||||
<para>The important changes here are the introducton of
|
||||
the<literal><parsers></literal> section (to register the
|
||||
<literal>ContextNamespaceParser</literal> required for CodeConfig) and
|
||||
the change of the <literal><resource></literal> element to point
|
||||
to the <literal>CodeConfigBootstrap.xml</literal> file instead of the
|
||||
<literal>controllers.xml</literal> file as before.</para>
|
||||
|
||||
<para>In addition, the section name for the
|
||||
<literal><parsers></literal> element must be registered with the
|
||||
<literal><spring></literal> sectionGroup as shown here so that the
|
||||
element can be properly interpreted:</para>
|
||||
|
||||
<programlisting language="xml"> <configSections>
|
||||
<sectionGroup name="spring">
|
||||
<section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc"/>
|
||||
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
|
||||
</sectionGroup>
|
||||
|
||||
<!--
|
||||
remainder of configSections element here...
|
||||
-->
|
||||
|
||||
</configSections></programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Replacing controllers.xml with CodeConfigBootstrap.xml</title>
|
||||
|
||||
<para>Where before the <literal>controllers.xml</literal> file contained
|
||||
all of the XML-based object definitions for the controllers for our MVC
|
||||
application, in this case the <literal>CodeConfigBootstrap.xml</literal>
|
||||
merely contains the single instruction telling the context to use
|
||||
CodeConfig:</para>
|
||||
|
||||
<programlisting language="xml"><?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net"
|
||||
xmlns:context="http://www.springframework.net/context">
|
||||
|
||||
<context:code-config/>
|
||||
|
||||
</objects> </programlisting>
|
||||
|
||||
<para>In this case, the single
|
||||
<literal><context:code-config/></literal> element is sufficient to
|
||||
tell the context to perform scanning for its object definition
|
||||
metadata.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Introducing the ControllerConfiguration CodeConfig class</title>
|
||||
|
||||
<para>The final modification needed to migrate the sample application to
|
||||
rely upon CodeConfig is to author the classes that will provide the
|
||||
Object Definitions for the Application Context to discover when
|
||||
performing the scan. In the case of this simple application, this is
|
||||
encapsulated in the single new
|
||||
<literal>ControllerConfiguration</literal> class as shown in the
|
||||
following:</para>
|
||||
|
||||
<programlisting language="csharp"> [Configuration]
|
||||
public class ControllerConfiguration
|
||||
{
|
||||
[ObjectDef]
|
||||
[Scope(ObjectScope.Prototype)]
|
||||
public virtual HomeController HomeController()
|
||||
{
|
||||
HomeController controller = new HomeController();
|
||||
controller.Message = "Welcome to ASP.NET MVC powered by Spring.NET (Code-Config)!";
|
||||
return controller;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>Using a combination of <literal><link
|
||||
linkend="configuration-attribute-reference">[Configuration]</link></literal>
|
||||
and <link
|
||||
linkend="objectdef-attribute-reference"><literal>[ObjectDef]</literal></link>
|
||||
attributes, this class faithfully reproduces the same Object Definition
|
||||
configuration as had been described by the
|
||||
<literal>controllers.xml</literal> file in the iniitial sample
|
||||
application as delivered with the main Spring.NET Framework
|
||||
download.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="sample-migration-codeconfig">
|
||||
<title>Spring.CodeConfig.Migration</title>
|
||||
|
||||
<para>This sample demonstates a step-by-step detailed examination of the
|
||||
process of migrating an XML-configuration based solution to use CodeConfig
|
||||
exclusively and is described in detail in <link
|
||||
linkend="migration-example">the Introduction section</link> of the
|
||||
reference documents.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
BIN
doc/reference/src/images/Migration_App_UML_Diagram.png
Normal file
BIN
doc/reference/src/images/Migration_App_UML_Diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
doc/reference/src/images/ScreenShot023.png
Normal file
BIN
doc/reference/src/images/ScreenShot023.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
File diff suppressed because it is too large
Load Diff
@@ -6392,17 +6392,8 @@ ctx.Refresh();</programlisting>
|
||||
RootObjectDefinition, etc. Note a web version of this application class
|
||||
has not yet been implemented.</para>
|
||||
|
||||
<para>An example, with a<emphasis> yet to be created</emphasis> DLL
|
||||
scanner, that would get configuration metadata from the .dll named
|
||||
MyAssembly.dll located in the runtime path, would look something like
|
||||
this</para>
|
||||
|
||||
<programlisting language="csharp">GenericApplicationContext ctx = new GenericApplicationContext();
|
||||
ObjectDefinitionScanner scanner = new ObjectDefinitionScanner(ctx);
|
||||
scanner.scan("MyAssembly.dll");
|
||||
ctx.refresh();</programlisting>
|
||||
|
||||
<para>Refer to the Spring API documentation for more information.</para>
|
||||
<para>For a an even richer XML-free configuration experience, refer
|
||||
instead to the Spring CodeConfig approach.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="objects-servicelocator">
|
||||
|
||||
Reference in New Issue
Block a user