fix another concurrency issue in InitDestroyAttributeObjectPostProcessor, minor code cleanup, add resharper code style guidance for solution

This commit is contained in:
Marko Lahma
2013-10-28 07:52:34 +02:00
parent 21cbbd0ac9
commit ddd6e3a76b
3 changed files with 238 additions and 180 deletions

View File

@@ -0,0 +1,25 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_INVOCABLE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue"></s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexRemoved">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=URL/@EntryIndexedValue"></s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=URL/@EntryIndexRemoved">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/IdentifierHighlightingEnabled/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/AnalysisEnabled/@EntryValue">SOLUTION</s:String>
<s:Boolean x:Key="/Default/Environment/TextControl/HighlightCurrentLine/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOR_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOREACH_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FIXED_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BETWEEN_USING_GROUPS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String>
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters /&gt;&lt;/data&gt;</s:String>
<s:Boolean x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=961894CCC510410ABE2B99132B253C80/CaseSensitive/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=961894CCC510410ABE2B99132B253C80/Pattern/@EntryValue">(?&lt;=^)(TODO:)(.*)</s:String></wpf:ResourceDictionary>

View File

@@ -23,15 +23,17 @@ using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using Spring.Collections;
using Spring.Core;
using Spring.Objects.Factory.Config;
using Common.Logging;
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Attributes
{
/// <summary>
/// <see cref="IInstantiationAwareObjectPostProcessor"/> implementation
/// that autowires annotated fields, properties and arbitrary config methods.
@@ -64,21 +66,19 @@ namespace Spring.Objects.Factory.Attributes
/// thus the latter configuration will override the former for properties wired through
/// both approaches.
/// </summary>
public class AutowiredAttributeObjectPostProcessor : InstantiationAwareObjectPostProcessorAdapter,
IObjectFactoryAware, IOrdered
public class AutowiredAttributeObjectPostProcessor : InstantiationAwareObjectPostProcessorAdapter, IObjectFactoryAware, IOrdered
{
private static readonly ILog Logger = LogManager.GetLogger<AutowiredAttributeObjectPostProcessor>();
private static readonly ILog logger = LogManager.GetLogger<AutowiredAttributeObjectPostProcessor>();
private int _order = int.MaxValue - 2;
private int order = int.MaxValue - 2;
private static IConfigurableListableObjectFactory _objectFactory;
private static IConfigurableListableObjectFactory objectFactory;
private SynchronizedHashtable _candidateConstructorsCache = new SynchronizedHashtable();
private readonly SynchronizedHashtable candidateConstructorsCache = new SynchronizedHashtable();
private readonly IDictionary<Type, InjectionMetadata> _injectionMetadataCache =
new Dictionary<Type, InjectionMetadata>();
private readonly IDictionary<Type, InjectionMetadata> injectionMetadataCache = new Dictionary<Type, InjectionMetadata>();
private IList<Type> _autowiredPropertyTypes = new List<Type>();
private readonly IList<Type> autowiredPropertyTypes = new List<Type>();
/// <summary>
/// Return the order value of this object, where a higher value means greater in
@@ -97,11 +97,10 @@ namespace Spring.Objects.Factory.Attributes
/// </returns>
public int Order
{
get { return _order; }
private set { _order = value; }
get { return order; }
private set { order = value; }
}
/// <summary>
/// Callback that supplies the owning factory to an object instance.
/// </summary>
@@ -121,7 +120,7 @@ namespace Spring.Objects.Factory.Attributes
/// </exception>
public IObjectFactory ObjectFactory
{
set { _objectFactory = (IConfigurableListableObjectFactory) value; }
set { objectFactory = (IConfigurableListableObjectFactory) value; }
}
/// <summary>
@@ -129,8 +128,10 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
public void AddAutowiredType(Type attributeType)
{
if (!_autowiredPropertyTypes.Contains(attributeType))
_autowiredPropertyTypes.Add(attributeType);
if (!autowiredPropertyTypes.Contains(attributeType))
{
autowiredPropertyTypes.Add(attributeType);
}
}
/// <summary>
@@ -140,8 +141,8 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
public AutowiredAttributeObjectPostProcessor()
{
_autowiredPropertyTypes.Add(typeof(AutowiredAttribute));
_autowiredPropertyTypes.Add(typeof(ValueAttribute));
autowiredPropertyTypes.Add(typeof (AutowiredAttribute));
autowiredPropertyTypes.Add(typeof (ValueAttribute));
}
/// <summary>
@@ -153,75 +154,77 @@ namespace Spring.Objects.Factory.Attributes
/// <exception cref="ObjectsException">in case of errors</exception>
public override ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName)
{
// Quick check on the concurrent map first, with minimal locking.
ConstructorInfo[] candidateConstructors = _candidateConstructorsCache.ContainsKey(objectType)
? (ConstructorInfo[])_candidateConstructorsCache[objectType]
: null;
if (candidateConstructors == null)
// Quick check on the concurrent map first, with minimal locking.
ConstructorInfo[] candidateConstructors = candidateConstructorsCache.ContainsKey(objectType)
? (ConstructorInfo[]) candidateConstructorsCache[objectType]
: null;
if (candidateConstructors == null)
{
lock (_candidateConstructorsCache)
lock (candidateConstructorsCache)
{
candidateConstructors = _candidateConstructorsCache.ContainsKey(objectType)
? (ConstructorInfo[])_candidateConstructorsCache[objectType]
: null;
if (candidateConstructors == null)
candidateConstructors = candidateConstructorsCache.ContainsKey(objectType)
? (ConstructorInfo[]) candidateConstructorsCache[objectType]
: null;
if (candidateConstructors == null)
{
ConstructorInfo[] rawCandidates = objectType.GetConstructors();
IList<ConstructorInfo> candidates = new List<ConstructorInfo>(rawCandidates.Length);
ConstructorInfo requiredConstructor = null;
ConstructorInfo defaultConstructor = null;
foreach(var candidate in rawCandidates)
{
AutowiredAttribute attr =
Attribute.GetCustomAttribute(candidate, typeof (AutowiredAttribute)) as AutowiredAttribute;
ConstructorInfo[] rawCandidates = objectType.GetConstructors();
IList<ConstructorInfo> candidates = new List<ConstructorInfo>(rawCandidates.Length);
ConstructorInfo requiredConstructor = null;
ConstructorInfo defaultConstructor = null;
foreach (var candidate in rawCandidates)
{
AutowiredAttribute attr =
Attribute.GetCustomAttribute(candidate, typeof (AutowiredAttribute)) as AutowiredAttribute;
if (attr != null)
{
if (requiredConstructor != null) {
throw new ObjectCreationException("Invalid autowire-marked constructor: " + candidate +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
}
if (candidate.GetParameters().Length == 0)
if (requiredConstructor != null)
{
throw new InvalidOperationException("Autowired annotation requires at least one argument: " + candidate);
}
throw new ObjectCreationException("Invalid autowire-marked constructor: " + candidate +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
}
if (candidate.GetParameters().Length == 0)
{
throw new InvalidOperationException("Autowired annotation requires at least one argument: " + candidate);
}
if (attr.Required)
{
if (candidates.Count > 0)
if (candidates.Count > 0)
{
throw new ObjectCreationException(
"Invalid autowire-marked constructors: " + candidates +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
}
requiredConstructor = candidate;
}
candidates.Add(candidate);
}
else if (candidate.GetParameters().Length == 0)
throw new ObjectCreationException(
"Invalid autowire-marked constructors: " + candidates +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
}
requiredConstructor = candidate;
}
candidates.Add(candidate);
}
else if (candidate.GetParameters().Length == 0)
{
defaultConstructor = candidate;
}
}
if (candidates.Count > 0)
defaultConstructor = candidate;
}
}
if (candidates.Count > 0)
{
// Add default constructor to list of optional constructors, as fallback.
if (requiredConstructor == null && defaultConstructor != null) {
candidates.Add(defaultConstructor);
}
candidateConstructors = candidates.ToArray();
}
else {
candidateConstructors = new ConstructorInfo[0];
}
_candidateConstructorsCache.Add(objectType, candidateConstructors);
}
}
}
return (candidateConstructors.Length > 0 ? candidateConstructors : null);
// Add default constructor to list of optional constructors, as fallback.
if (requiredConstructor == null && defaultConstructor != null)
{
candidates.Add(defaultConstructor);
}
candidateConstructors = candidates.ToArray();
}
else
{
candidateConstructors = new ConstructorInfo[0];
}
candidateConstructorsCache.Add(objectType, candidateConstructors);
}
}
}
return (candidateConstructors.Length > 0 ? candidateConstructors : null);
}
/// <summary>
/// Finds autowire candidates and verifies them
/// </summary>
@@ -243,7 +246,7 @@ namespace Spring.Objects.Factory.Attributes
/// <seealso cref="Spring.Objects.Factory.Support.IConfigurableObjectDefinition.FactoryMethodName"/>
public override object PostProcessBeforeInstantiation(Type objectType, string objectName)
{
var objectDefinition = _objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition;
var objectDefinition = objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition;
if (objectType != null)
{
var metadata = FindAutowiringMetadata(objectType);
@@ -262,7 +265,7 @@ namespace Spring.Objects.Factory.Attributes
/// <returns>The actual property values to apply to the given object (can be the
/// passed-in PropertyValues instances0 or null to skip property population.</returns>
public override IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList<PropertyInfo> pis,
object objectInstance, string objectName)
object objectInstance, string objectName)
{
var metadata = FindAutowiringMetadata(objectInstance.GetType());
try
@@ -276,22 +279,20 @@ namespace Spring.Objects.Factory.Attributes
return pvs;
}
private InjectionMetadata FindAutowiringMetadata(Type objectType)
{
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = null;
_injectionMetadataCache.TryGetValue(objectType, out metadata);
if (metadata == null)
InjectionMetadata metadata;
if (injectionMetadataCache.TryGetValue(objectType, out metadata))
{
lock (_injectionMetadataCache)
return metadata;
}
lock (injectionMetadataCache)
{
if (!injectionMetadataCache.TryGetValue(objectType, out metadata))
{
if (!_injectionMetadataCache.TryGetValue(objectType, out metadata))
{
metadata = BuildAutowiringMetadata(objectType);
_injectionMetadataCache.Add(objectType, metadata);
}
metadata = BuildAutowiringMetadata(objectType);
injectionMetadataCache.Add(objectType, metadata);
}
}
return metadata;
@@ -303,7 +304,7 @@ namespace Spring.Objects.Factory.Attributes
do
{
foreach (var autowiredType in _autowiredPropertyTypes)
foreach (var autowiredType in autowiredPropertyTypes)
{
var currElements = new List<InjectionMetadata.InjectedElement>();
foreach (
@@ -314,9 +315,13 @@ namespace Spring.Objects.Factory.Attributes
var required = true;
var attr = Attribute.GetCustomAttribute(property, autowiredType);
if (attr is AutowiredAttribute)
required = ((AutowiredAttribute)attr).Required;
{
required = ((AutowiredAttribute) attr).Required;
}
if (attr != null && property.DeclaringType == objectType)
{
currElements.Add(new AutowiredPropertyElement(property, required));
}
}
foreach (
var field in
@@ -325,9 +330,13 @@ namespace Spring.Objects.Factory.Attributes
var required = true;
var attr = Attribute.GetCustomAttribute(field, autowiredType);
if (attr is AutowiredAttribute)
{
required = ((AutowiredAttribute) attr).Required;
}
if (attr != null && field.DeclaringType == objectType)
{
currElements.Add(new AutowiredFieldElement(field, required));
}
}
foreach (
var method in
@@ -336,18 +345,20 @@ namespace Spring.Objects.Factory.Attributes
var required = true;
var attr = Attribute.GetCustomAttribute(method, autowiredType);
if (attr is AutowiredAttribute)
required = ((AutowiredAttribute)attr).Required;
{
required = ((AutowiredAttribute) attr).Required;
}
if (attr != null && method.DeclaringType == objectType)
{
if (method.IsStatic)
{
Logger.Warn(
logger.Warn(
m => m("Autowired annotation is not supported on static methods: " + method.Name));
continue;
}
if (method.IsGenericMethod)
{
Logger.Warn(
logger.Warn(
m => m("Autowired annotation is not supported on generic methods: " + method.Name));
continue;
}
@@ -367,12 +378,16 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
private static void RegisterDependentObjects(string objectName, IList autowiredObjectNames)
{
if (objectName == null)
if (objectName == null)
{
return;
}
var objectDefinition = _objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition;
var objectDefinition = objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition;
if (objectDefinition == null)
{
return;
}
IList<string> dependsOn = new List<string>(objectDefinition.DependsOn);
foreach (var name in autowiredObjectNames)
@@ -381,10 +396,10 @@ namespace Spring.Objects.Factory.Attributes
if (!dependsOn.Contains(autowiredObjectName))
{
dependsOn.Add(autowiredObjectName);
Logger.Debug(
logger.Debug(
m =>
m("Autowiring by type from object name '{0}' to object named '{1}'", objectName,
autowiredObjectName));
m("Autowiring by type from object name '{0}' to object named '{1}'", objectName,
autowiredObjectName));
}
}
objectDefinition.DependsOn = dependsOn;
@@ -395,11 +410,11 @@ namespace Spring.Objects.Factory.Attributes
if (cachedArgument is DependencyDescriptor)
{
var descriptor = (DependencyDescriptor) cachedArgument;
return _objectFactory.ResolveDependency(descriptor, objectName, null);
return objectFactory.ResolveDependency(descriptor, objectName, null);
}
else if (cachedArgument is RuntimeObjectReference)
{
return _objectFactory.GetObject(((RuntimeObjectReference) cachedArgument).ObjectName);
return objectFactory.GetObject(((RuntimeObjectReference) cachedArgument).ObjectName);
}
else
{
@@ -412,7 +427,6 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
private class AutowiredPropertyElement : InjectionMetadata.InjectedElement
{
private readonly bool _required;
private bool _cached = false;
@@ -439,7 +453,7 @@ namespace Spring.Objects.Factory.Attributes
{
var descriptor = new DependencyDescriptor(property, _required);
IList autowiredObjectNames = new ArrayList();
value = _objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames);
value = objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames);
lock (this)
{
if (!_cached)
@@ -451,9 +465,9 @@ namespace Spring.Objects.Factory.Attributes
if (autowiredObjectNames.Count == 1)
{
var autowiredBeanName = autowiredObjectNames[0] as string;
if (_objectFactory.ContainsObject(autowiredBeanName))
if (objectFactory.ContainsObject(autowiredBeanName))
{
if (_objectFactory.IsTypeMatch(autowiredBeanName, property.GetType()))
if (objectFactory.IsTypeMatch(autowiredBeanName, property.GetType()))
{
_cachedFieldValue = new RuntimeObjectReference(autowiredBeanName);
}
@@ -485,7 +499,6 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
private class AutowiredFieldElement : InjectionMetadata.InjectedElement
{
private readonly bool _required;
private bool _cached = false;
@@ -512,7 +525,7 @@ namespace Spring.Objects.Factory.Attributes
{
var descriptor = new DependencyDescriptor(field, _required);
IList autowiredObjectNames = new ArrayList();
value = _objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames);
value = objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames);
lock (this)
{
if (!_cached)
@@ -524,9 +537,9 @@ namespace Spring.Objects.Factory.Attributes
if (autowiredObjectNames.Count == 1)
{
var autowiredBeanName = autowiredObjectNames[0] as string;
if (_objectFactory.ContainsObject(autowiredBeanName))
if (objectFactory.ContainsObject(autowiredBeanName))
{
if (_objectFactory.IsTypeMatch(autowiredBeanName, field.GetType()))
if (objectFactory.IsTypeMatch(autowiredBeanName, field.GetType()))
{
_cachedFieldValue = new RuntimeObjectReference(autowiredBeanName);
}
@@ -590,8 +603,8 @@ namespace Spring.Objects.Factory.Attributes
{
MethodParameter methodParam = new MethodParameter(method, i);
descriptors[i] = new DependencyDescriptor(methodParam, _required);
arguments[i] = _objectFactory.ResolveDependency(descriptors[i], objectName,
autowiredBeanNames);
arguments[i] = objectFactory.ResolveDependency(descriptors[i], objectName,
autowiredBeanNames);
if (arguments[i] == null && !_required)
{
arguments = null;
@@ -615,9 +628,9 @@ namespace Spring.Objects.Factory.Attributes
for (int i = 0; i < paramTypes.Length; i++)
{
string autowiredBeanName = autowiredBeanNames[i] as string;
if (_objectFactory.ContainsObject(autowiredBeanName))
if (objectFactory.ContainsObject(autowiredBeanName))
{
if (_objectFactory.IsTypeMatch(autowiredBeanName, paramTypes[i]))
if (objectFactory.IsTypeMatch(autowiredBeanName, paramTypes[i]))
{
_cachedMethodArguments[i] =
new RuntimeObjectReference(autowiredBeanName);
@@ -660,4 +673,4 @@ namespace Spring.Objects.Factory.Attributes
}
}
}
}
}

View File

@@ -22,9 +22,9 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Common.Logging;
using Spring.Objects;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Config;
using Spring.Core;
@@ -43,15 +43,14 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
public class InitDestroyAttributeObjectPostProcessor : IDestructionAwareObjectPostProcessor, IObjectFactoryAware, IOrdered
{
private static readonly ILog Logger = LogManager.GetLogger<InitDestroyAttributeObjectPostProcessor>();
private static readonly ILog logger = LogManager.GetLogger<InitDestroyAttributeObjectPostProcessor>();
private IConfigurableListableObjectFactory _objectFactory;
private readonly IDictionary<string, LifecycleLifecycleMetadata> _lifecycleMetadataCache;
private int _order = int.MaxValue;
private Type _initAttributeType;
private Type _destroyAttributeType;
private IConfigurableListableObjectFactory objectFactory;
private readonly IDictionary<string, LifecycleLifecycleMetadata> lifecycleMetadataCache;
private int order = int.MaxValue;
private Type initAttributeType;
private Type destroyAttributeType;
/// <summary>
/// Return the order value of this object, where a higher value means greater in
@@ -68,27 +67,38 @@ namespace Spring.Objects.Factory.Attributes
/// <returns>
/// The order value.
/// </returns>
public int Order { get { return _order; } private set { _order = value; } }
public int Order
{
get { return order; }
private set { order = value; }
}
/// <summary>
/// Specify the init attribute to check for, indicating initialization
/// methods to call after configuration of an object.
/// </summary>
public Type InitAttributeType { get { return _initAttributeType; } set { _initAttributeType = value; } }
public Type InitAttributeType
{
get { return initAttributeType; }
set { initAttributeType = value; }
}
/// <summary>
/// Specify the destroy attribute to check for, indicating disposal
/// methods to call before object is destroyed
/// </summary>
public Type DestroyAttributeType { get { return _destroyAttributeType; } set { _destroyAttributeType = value; } }
public Type DestroyAttributeType
{
get { return destroyAttributeType; }
set { destroyAttributeType = value; }
}
/// <summary>
///
/// </summary>
public IObjectFactory ObjectFactory
{
set { _objectFactory = value as IConfigurableListableObjectFactory; }
set { objectFactory = value as IConfigurableListableObjectFactory; }
}
/// <summary>
@@ -97,10 +107,10 @@ namespace Spring.Objects.Factory.Attributes
/// </summary>
public InitDestroyAttributeObjectPostProcessor()
{
_initAttributeType = typeof (PostConstructAttribute);
_destroyAttributeType = typeof (PreDestroyAttribute);
initAttributeType = typeof (PostConstructAttribute);
destroyAttributeType = typeof (PreDestroyAttribute);
_lifecycleMetadataCache = new Dictionary<string, LifecycleLifecycleMetadata>();
lifecycleMetadataCache = new Dictionary<string, LifecycleLifecycleMetadata>();
}
/// <summary>
@@ -137,7 +147,6 @@ namespace Spring.Objects.Factory.Attributes
return instance;
}
/// <summary>
/// Executed PreDestroy methods in given order for provided instance
/// </summary>
@@ -158,15 +167,21 @@ namespace Spring.Objects.Factory.Attributes
private LifecycleLifecycleMetadata FindLifecycleMetadata(Type instanceType, string name)
{
if (_lifecycleMetadataCache.ContainsKey(name))
return _lifecycleMetadataCache[name];
lock (_lifecycleMetadataCache)
LifecycleLifecycleMetadata metadata;
if (lifecycleMetadataCache.TryGetValue(name, out metadata))
{
var metadata = BuildLifecycleMetadata(instanceType, name);
_lifecycleMetadataCache.Add(name, metadata);
return metadata;
}
lock (lifecycleMetadataCache)
{
if (!lifecycleMetadataCache.TryGetValue(name, out metadata))
{
metadata = BuildLifecycleMetadata(instanceType, name);
lifecycleMetadataCache.Add(name, metadata);
}
}
return metadata;
}
private LifecycleLifecycleMetadata BuildLifecycleMetadata(Type instanceType, string name)
@@ -178,75 +193,79 @@ namespace Spring.Objects.Factory.Attributes
{
var curInitMethods = new List<LifecycleElement>();
var curDestroyMethods = new List<LifecycleElement>();
var methods = instanceType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var methods =
instanceType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
foreach (var methodInfo in methods)
{
var initAttribute =
Attribute.GetCustomAttribute(methodInfo, _initAttributeType) as PostConstructAttribute;
Attribute.GetCustomAttribute(methodInfo, initAttributeType) as PostConstructAttribute;
if (initAttribute != null && methodInfo.DeclaringType == instanceType)
{
Logger.Debug(m => m("Found init method on class [{0}]: {1}", instanceType.Name, methodInfo.Name));
logger.Debug(m => m("Found init method on class [{0}]: {1}", instanceType.Name, methodInfo.Name));
curInitMethods.Add(new LifecycleElement(methodInfo, initAttribute.Order));
}
var destroyAttribute =
Attribute.GetCustomAttribute(methodInfo, _destroyAttributeType) as PreDestroyAttribute;
Attribute.GetCustomAttribute(methodInfo, destroyAttributeType) as PreDestroyAttribute;
if (destroyAttribute != null && methodInfo.DeclaringType == instanceType)
{
Logger.Debug(m => m("Found destroy method on class [{0}]: {1}", instanceType.Name, methodInfo.Name));
logger.Debug(
m => m("Found destroy method on class [{0}]: {1}", instanceType.Name, methodInfo.Name));
curDestroyMethods.Add(new LifecycleElement(methodInfo, destroyAttribute.Order));
}
}
initMethods.InsertRange(0, curInitMethods.OrderBy(e => e.Order));
destroyMethods.InsertRange(0, curDestroyMethods.OrderBy(e => e.Order));
instanceType = instanceType.BaseType;
}
while (instanceType != null && instanceType != typeof(Object));
} while (instanceType != null && instanceType != typeof (Object));
var objectDef = _objectFactory.GetObjectDefinition(name);
var objectDef = objectFactory.GetObjectDefinition(name);
var metadata = new LifecycleLifecycleMetadata(initMethods, destroyMethods);
metadata.CheckConfigMembers(objectDef);
return metadata;
}
private class LifecycleLifecycleMetadata
{
private readonly IList<LifecycleElement> _initMethods;
private readonly IList<LifecycleElement> _destroyMethods;
private readonly IList<LifecycleElement> initMethods;
private readonly IList<LifecycleElement> destroyMethods;
public LifecycleLifecycleMetadata(IList<LifecycleElement> initMethods, IList<LifecycleElement> destroyMethods)
public LifecycleLifecycleMetadata(IList<LifecycleElement> initMethods,
IList<LifecycleElement> destroyMethods)
{
_initMethods = initMethods;
_destroyMethods = destroyMethods;
this.initMethods = initMethods;
this.destroyMethods = destroyMethods;
}
public void CheckConfigMembers(IObjectDefinition objectDef)
{
lock (_initMethods)
lock (initMethods)
{
for (int i = 0; i < _initMethods.Count; i++)
{
if (!_initMethods[i].CheckConfig(objectDef))
_initMethods.Remove(_initMethods[i]);
}
}
lock (_destroyMethods)
{
for (int i = 0; i < _destroyMethods.Count; i++)
for (int i = 0; i < initMethods.Count; i++)
{
if (!_destroyMethods[i].CheckConfig(objectDef))
_destroyMethods.Remove(_destroyMethods[i]);
if (!initMethods[i].CheckConfig(objectDef))
{
initMethods.Remove(initMethods[i]);
}
}
}
lock (destroyMethods)
{
for (int i = 0; i < destroyMethods.Count; i++)
{
if (!destroyMethods[i].CheckConfig(objectDef))
{
destroyMethods.Remove(destroyMethods[i]);
}
}
}
}
public void InvokeInitMethods(object instance, string objectName)
{
foreach (var lifecycleElement in _initMethods)
foreach (var lifecycleElement in initMethods)
{
lifecycleElement.Invoke(instance, objectName);
}
@@ -254,43 +273,44 @@ namespace Spring.Objects.Factory.Attributes
public void InvokeDestroyMethods(object instance, string objectName)
{
foreach (var lifecycleElement in _destroyMethods)
foreach (var lifecycleElement in destroyMethods)
{
lifecycleElement.Invoke(instance, objectName);
}
}
}
private class LifecycleElement
{
private readonly MethodInfo _method;
private readonly int _order;
public int Order { get { return _order; } }
private readonly MethodInfo method;
private readonly int order;
public int Order
{
get { return order; }
}
public LifecycleElement(MethodInfo method, int order)
{
_method = method;
_order = order;
this.method = method;
this.order = order;
}
public bool CheckConfig(IObjectDefinition objectDef)
{
if (_method.Name == objectDef.InitMethodName || _method.Name == objectDef.DestroyMethodName)
if (method.Name == objectDef.InitMethodName || method.Name == objectDef.DestroyMethodName)
{
return false;
}
return true;
}
public void Invoke(object instance, string objectName)
{
Logger.Debug(m => m("Invoking init method on object '" + objectName + "': " + _method.Name));
_method.Invoke(instance, new object[] {});
logger.Debug(m => m("Invoking init method on object '" + objectName + "': " + method.Name));
method.Invoke(instance, new object[] {});
}
}
}
}
}