aop performance improvements
This commit is contained in:
@@ -76,7 +76,7 @@ namespace Spring.Aop.Framework
|
||||
/// Array updated on changes to the advisors list, which is easier to
|
||||
/// manipulate internally
|
||||
/// </summary>
|
||||
private IAdvisor[] _advisorsArray = new IAdvisor[] {};
|
||||
private volatile IAdvisor[] _advisorsArray = new IAdvisor[] { };
|
||||
|
||||
/// <summary>
|
||||
/// List of introductions.
|
||||
@@ -88,7 +88,7 @@ namespace Spring.Aop.Framework
|
||||
/// manipulate internally
|
||||
/// </summary>
|
||||
private IIntroductionAdvisor[] _introductionsArray
|
||||
= new IIntroductionAdvisor[] {};
|
||||
= new IIntroductionAdvisor[] { };
|
||||
|
||||
/// <summary>
|
||||
/// Interface map specifying which object should interface methods be
|
||||
@@ -100,7 +100,7 @@ namespace Spring.Aop.Framework
|
||||
/// to the target object.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
private IDictionary interfaceMap = new ListDictionary();
|
||||
private readonly IDictionary interfaceMap = new ListDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Spring.Aop.ITargetSource"/> for this instance.
|
||||
@@ -120,7 +120,7 @@ namespace Spring.Aop.Framework
|
||||
/// <summary>
|
||||
/// The list of <see cref="Spring.Aop.Framework.AdvisedSupport"/> event listeners.
|
||||
/// </summary>
|
||||
private IList listeners = new ArrayList();
|
||||
private readonly IList listeners = new ArrayList();
|
||||
|
||||
/// <summary>
|
||||
/// The advisor chain factory.
|
||||
@@ -149,7 +149,8 @@ namespace Spring.Aop.Framework
|
||||
/// <exception cref="Spring.Aop.Framework.AopConfigException">
|
||||
/// If this
|
||||
/// </exception>
|
||||
public AdvisedSupport(Type[] interfaces) : this()
|
||||
public AdvisedSupport(Type[] interfaces)
|
||||
: this()
|
||||
{
|
||||
if (interfaces != null)
|
||||
{
|
||||
@@ -181,14 +182,14 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return this.advisorChainFactory;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
if (this.advisorChainFactory != null)
|
||||
{
|
||||
@@ -216,12 +217,12 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
bool initialized = !(this.m_targetSource is EmptyTargetSource);
|
||||
this.m_targetSource = value;
|
||||
|
||||
|
||||
if (this.m_targetSource != null && !initialized && interfaceMap.Count == 0)
|
||||
{
|
||||
Type[] interfaces = ReflectionUtils.GetInterfaces(this.m_targetSource.TargetType);
|
||||
foreach (Type intf in interfaces)
|
||||
{
|
||||
{
|
||||
AddInterfaceInternal(intf);
|
||||
}
|
||||
}
|
||||
@@ -240,23 +241,31 @@ namespace Spring.Aop.Framework
|
||||
get
|
||||
{
|
||||
bool canBeSerialized = TargetSource.TargetType.IsSerializable;
|
||||
if (canBeSerialized)
|
||||
if (!canBeSerialized) return false;
|
||||
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
for (int i = 0; canBeSerialized && i < _advisorsArray.Length; i++)
|
||||
IAdvisor[] advisorsArray = this._advisorsArray;
|
||||
IIntroductionAdvisor[] introductionsArray = this._introductionsArray;
|
||||
|
||||
for (int i = 0; i < advisorsArray.Length; i++)
|
||||
{
|
||||
IAdvisor advisor = _advisorsArray[i];
|
||||
IAdvisor advisor = advisorsArray[i];
|
||||
canBeSerialized = advisor.GetType().IsSerializable
|
||||
&& advisor.Advice.GetType().IsSerializable;
|
||||
if (!canBeSerialized) return false;
|
||||
}
|
||||
for (int i = 0; canBeSerialized && i < _introductionsArray.Length; i++)
|
||||
|
||||
for (int i = 0; i < introductionsArray.Length; i++)
|
||||
{
|
||||
IIntroductionAdvisor advisor = _introductionsArray[i];
|
||||
IIntroductionAdvisor advisor = introductionsArray[i];
|
||||
canBeSerialized = advisor.GetType().IsSerializable
|
||||
&& advisor.Advice.GetType().IsSerializable;
|
||||
if (!canBeSerialized) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return canBeSerialized;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +282,7 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
Type[] proxiedInterfaces = new Type[this.interfaceMap.Keys.Count];
|
||||
this.interfaceMap.Keys.CopyTo(proxiedInterfaces, 0);
|
||||
@@ -282,7 +291,7 @@ namespace Spring.Aop.Framework
|
||||
}
|
||||
set
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
this.interfaceMap.Clear();
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
@@ -307,7 +316,7 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return new Hashtable(this.interfaceMap);
|
||||
}
|
||||
@@ -332,7 +341,7 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
if (intf != null)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
foreach (Type proxyInterface in this.interfaceMap.Keys)
|
||||
{
|
||||
@@ -359,9 +368,10 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
// lock(this.SyncRoot)
|
||||
{
|
||||
return (IAdvisor[]) this._advisorsArray.Clone();
|
||||
// return (IAdvisor[]) _advisorsArray.Clone();
|
||||
return _advisorsArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,9 +397,9 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return (IIntroductionAdvisor[]) this._introductionsArray.Clone();
|
||||
return (IIntroductionAdvisor[])this._introductionsArray.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,7 +471,7 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public virtual int IndexOf(IAdvisor advisor)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return IndexOfInternal(advisor);
|
||||
}
|
||||
@@ -482,7 +492,7 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public virtual int IndexOf(IIntroductionAdvisor advisor)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return IndexOfInternal(advisor);
|
||||
}
|
||||
@@ -509,7 +519,7 @@ namespace Spring.Aop.Framework
|
||||
bool wasRemoved = false;
|
||||
if (advisor != null)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
int index = IndexOf(advisor);
|
||||
if (index == -1)
|
||||
@@ -545,7 +555,7 @@ namespace Spring.Aop.Framework
|
||||
public virtual void RemoveAdvisor(int index)
|
||||
{
|
||||
DieIfFrozen("Cannot remove advisor: config is frozen");
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
RemoveAdvisorInternal(index);
|
||||
}
|
||||
@@ -569,7 +579,7 @@ namespace Spring.Aop.Framework
|
||||
/// </exception>
|
||||
public bool RemoveAdvice(IAdvice advice)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
int index = IndexOf(advice);
|
||||
if (index == -1)
|
||||
@@ -606,7 +616,7 @@ namespace Spring.Aop.Framework
|
||||
bool wasRemoved = false;
|
||||
if (introduction != null)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
int index = IndexOf(introduction);
|
||||
if (index == -1)
|
||||
@@ -639,7 +649,7 @@ namespace Spring.Aop.Framework
|
||||
public virtual void RemoveIntroduction(int index)
|
||||
{
|
||||
DieIfFrozen("Cannot remove introduction: config is frozen");
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
if (index < 0 || index >= _introductions.Count)
|
||||
{
|
||||
@@ -647,7 +657,7 @@ namespace Spring.Aop.Framework
|
||||
"Introduction index " + index + " is out of bounds: Only have " + _introductions.Count +
|
||||
" introductions.");
|
||||
}
|
||||
IIntroductionAdvisor advisor = (IIntroductionAdvisor) _introductions[index];
|
||||
IIntroductionAdvisor advisor = (IIntroductionAdvisor)_introductions[index];
|
||||
// remove all interfaces introduced by the advisor...
|
||||
foreach (Type intf in advisor.Interfaces)
|
||||
{
|
||||
@@ -658,33 +668,33 @@ namespace Spring.Aop.Framework
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Removes the supplied <paramref name="interceptor"/> from the list of
|
||||
// /// <see cref="Spring.Aop.Framework.AdvisedSupport.Advisors"/> for this
|
||||
// /// proxy.
|
||||
// /// </summary>
|
||||
// /// <param name="interceptor">
|
||||
// /// The <see cref="AopAlliance.Intercept.IInterceptor"/> to be removed.
|
||||
// /// </param>
|
||||
// /// <exception cref="AopConfigException">
|
||||
// /// If this proxy configuration is frozen and the
|
||||
// /// <paramref name="interceptor"/> cannot be added.
|
||||
// /// </exception>
|
||||
// public bool RemoveInterceptor(IInterceptor interceptor)
|
||||
// {
|
||||
// AssertFrozen("Cannot remove interceptor: config is frozen");
|
||||
// int index = IndexOf(interceptor);
|
||||
// if (index == -1)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// RemoveAdvisor(index);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Removes the supplied <paramref name="interceptor"/> from the list of
|
||||
// /// <see cref="Spring.Aop.Framework.AdvisedSupport.Advisors"/> for this
|
||||
// /// proxy.
|
||||
// /// </summary>
|
||||
// /// <param name="interceptor">
|
||||
// /// The <see cref="AopAlliance.Intercept.IInterceptor"/> to be removed.
|
||||
// /// </param>
|
||||
// /// <exception cref="AopConfigException">
|
||||
// /// If this proxy configuration is frozen and the
|
||||
// /// <paramref name="interceptor"/> cannot be added.
|
||||
// /// </exception>
|
||||
// public bool RemoveInterceptor(IInterceptor interceptor)
|
||||
// {
|
||||
// AssertFrozen("Cannot remove interceptor: config is frozen");
|
||||
// int index = IndexOf(interceptor);
|
||||
// if (index == -1)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// RemoveAdvisor(index);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the supplied <paramref name="advisor"/> to the list
|
||||
@@ -705,12 +715,12 @@ namespace Spring.Aop.Framework
|
||||
public virtual void AddAdvisor(int index, IAdvisor advisor)
|
||||
{
|
||||
DieIfFrozen("Cannot add advisor: config is frozen");
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
// advisor already in list (SPRNET-846)
|
||||
if (_advisors.Contains(advisor)) return;
|
||||
|
||||
if(index == -1)
|
||||
if (index == -1)
|
||||
{
|
||||
this._advisors.Add(advisor);
|
||||
}
|
||||
@@ -756,7 +766,7 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
if (advisor is IIntroductionAdvisor)
|
||||
{
|
||||
AddIntroduction((IIntroductionAdvisor) advisor);
|
||||
AddIntroduction((IIntroductionAdvisor)advisor);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -786,7 +796,7 @@ namespace Spring.Aop.Framework
|
||||
DieIfFrozen("Cannot add introduction: config is frozen");
|
||||
introductionAdvisor.ValidateInterfaces();
|
||||
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
if (index < this._introductions.Count)
|
||||
{
|
||||
@@ -822,13 +832,13 @@ namespace Spring.Aop.Framework
|
||||
public virtual void AddIntroduction(IIntroductionAdvisor introductionAdvisor)
|
||||
{
|
||||
Type introductionType = introductionAdvisor.Advice.GetType();
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
int pos = this._introductions.Count;
|
||||
for (int i = 0; i < pos; i++)
|
||||
{
|
||||
IIntroductionAdvisor introduction
|
||||
= (IIntroductionAdvisor) this._introductions[i];
|
||||
= (IIntroductionAdvisor)this._introductions[i];
|
||||
if (introduction.Advice.GetType() == introductionType)
|
||||
{
|
||||
pos = i;
|
||||
@@ -858,14 +868,14 @@ namespace Spring.Aop.Framework
|
||||
/// </exception>
|
||||
public virtual void ReplaceIntroduction(int index, IIntroductionAdvisor introduction)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
if(index < 0 || index >= _introductions.Count)
|
||||
if (index < 0 || index >= _introductions.Count)
|
||||
{
|
||||
throw new AopConfigException(
|
||||
"Introduction index " + index + " is out of bounds:" +
|
||||
" there are currently " + _introductions.Count +
|
||||
" introductions." );
|
||||
" introductions.");
|
||||
}
|
||||
|
||||
_introductions[index] = introduction;
|
||||
@@ -897,7 +907,7 @@ namespace Spring.Aop.Framework
|
||||
public bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor)
|
||||
{
|
||||
DieIfFrozen("Cannot replace advisor: config is frozen.");
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
int index = IndexOf(oldAdvisor);
|
||||
if (index == -1 || newAdvisor == null)
|
||||
@@ -920,7 +930,7 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public virtual string ToProxyConfigString()
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return ToStringInternal();
|
||||
}
|
||||
@@ -1016,7 +1026,7 @@ namespace Spring.Aop.Framework
|
||||
/// </param>
|
||||
public virtual void AddListener(IAdvisedSupportListener listener)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
this.listeners.Add(listener);
|
||||
}
|
||||
@@ -1031,7 +1041,7 @@ namespace Spring.Aop.Framework
|
||||
/// </param>
|
||||
public virtual void RemoveListener(IAdvisedSupportListener listener)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
this.listeners.Remove(listener);
|
||||
}
|
||||
@@ -1052,10 +1062,10 @@ namespace Spring.Aop.Framework
|
||||
/// </exception>
|
||||
public virtual void AddInterface(Type intf)
|
||||
{
|
||||
DieIfFrozen("Cannot add interface: configuration is frozen.");
|
||||
DieIfFrozen("Cannot add interface: configuration is frozen.");
|
||||
AssertUtils.ArgumentNotNull(intf, "intf", "Cannot proxy a null interface.");
|
||||
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
AddInterfaceInternal(intf);
|
||||
InterfacesChanged();
|
||||
@@ -1090,8 +1100,8 @@ namespace Spring.Aop.Framework
|
||||
/// <see langword="true"/> if the interface was removed.</returns>
|
||||
public virtual bool RemoveInterface(Type intf)
|
||||
{
|
||||
DieIfFrozen("Cannot remove interface: configuration is frozen.");
|
||||
lock(this.SyncRoot)
|
||||
DieIfFrozen("Cannot remove interface: configuration is frozen.");
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
if (intf != null && this.interfaceMap.Contains(intf))
|
||||
{
|
||||
@@ -1125,7 +1135,7 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public virtual int IndexOf(IAdvice advice)
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return IndexOfInternal(advice);
|
||||
}
|
||||
@@ -1158,7 +1168,7 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
for (int i = 0; i < this._advisors.Count; ++i)
|
||||
{
|
||||
IAdvisor advisor = (IAdvisor) this._advisors[i];
|
||||
IAdvisor advisor = (IAdvisor)this._advisors[i];
|
||||
if (advisor.Advice == advice)
|
||||
{
|
||||
return i;
|
||||
@@ -1275,7 +1285,7 @@ namespace Spring.Aop.Framework
|
||||
public int CountAdviceOfType(Type interceptorType)
|
||||
{
|
||||
int count = 0;
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
foreach (IAdvisor advisor in this._advisors)
|
||||
{
|
||||
@@ -1313,8 +1323,9 @@ namespace Spring.Aop.Framework
|
||||
/// </summary>
|
||||
private void UpdateAdvisorsArray()
|
||||
{
|
||||
this._advisorsArray = new IAdvisor[this._advisors.Count];
|
||||
this._advisors.CopyTo(this._advisorsArray, 0);
|
||||
IAdvisor[] advisorsArray = new IAdvisor[this._advisors.Count];
|
||||
this._advisors.CopyTo(advisorsArray, 0);
|
||||
this._advisorsArray = advisorsArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1322,8 +1333,9 @@ namespace Spring.Aop.Framework
|
||||
/// </summary>
|
||||
private void UpdateIntroductionsArray()
|
||||
{
|
||||
this._introductionsArray = new IIntroductionAdvisor[this._introductions.Count];
|
||||
this._introductions.CopyTo(this._introductionsArray, 0);
|
||||
IIntroductionAdvisor[] introductionsArray = new IIntroductionAdvisor[this._introductions.Count];
|
||||
this._introductions.CopyTo(introductionsArray, 0);
|
||||
this._introductionsArray = introductionsArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1454,7 +1466,7 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
lock(this.SyncRoot)
|
||||
lock (this.SyncRoot)
|
||||
{
|
||||
return ToStringInternal();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Spring.Threading;
|
||||
|
||||
@@ -40,11 +41,17 @@ namespace Spring.Aop.Framework
|
||||
/// advice can use this to make advised calls. They can also use it to find
|
||||
/// advice configuration.
|
||||
/// </p>
|
||||
/// <note>
|
||||
/// <p>
|
||||
/// To expose the current proxy, set the <see cref="Spring.Aop.Framework.ProxyConfig.ExposeProxy"/>
|
||||
/// property on the controlling proxy to <see langword="true"/>.
|
||||
/// The default value for the <see cref="Spring.Aop.Framework.ProxyConfig.ExposeProxy"/> property
|
||||
/// is <see langword="false"/>, for performance reasons.
|
||||
/// </p>
|
||||
/// <note>
|
||||
/// The AOP framework does not expose proxies by default, as there is a
|
||||
/// performance cost in doing so.
|
||||
/// </note>
|
||||
/// <p>
|
||||
/// <p>
|
||||
/// The functionality in this class might be used by a target object that
|
||||
/// needed access to resources on the invocation. However, this approach
|
||||
/// should not be used when there is a reasonable alternative, as it makes
|
||||
@@ -56,34 +63,21 @@ namespace Spring.Aop.Framework
|
||||
/// <author>Aleksandar Seovic (.NET)</author>
|
||||
public sealed class AopContext
|
||||
{
|
||||
private const string CURRENTPROXY_SLOTNAME = "AopContext.CurrentProxySlotName";
|
||||
[ThreadStatic]
|
||||
private static Stack tls_ProxyStack;
|
||||
|
||||
/// <summary>
|
||||
/// The AOP proxy associated with this thread.
|
||||
/// The AOP proxy stack associated with this thread.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// Will be <cref lang="null"/> unless the
|
||||
/// <see cref="Spring.Aop.Framework.ProxyConfig.ExposeProxy"/> property
|
||||
/// on the controlling proxy has been set to <see langword="true"/>.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The default value for the
|
||||
/// <see cref="Spring.Aop.Framework.ProxyConfig.ExposeProxy"/> property
|
||||
/// is <see langword="false"/>, for performance reasons.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
private static Stack ProxyStack
|
||||
{
|
||||
get
|
||||
{
|
||||
Stack proxyStack = LogicalThreadContext.GetData(CURRENTPROXY_SLOTNAME) as Stack;
|
||||
if (proxyStack == null)
|
||||
if (tls_ProxyStack == null)
|
||||
{
|
||||
proxyStack = new Stack();
|
||||
LogicalThreadContext.SetData(CURRENTPROXY_SLOTNAME, proxyStack);
|
||||
tls_ProxyStack = new Stack();
|
||||
}
|
||||
return proxyStack;
|
||||
return tls_ProxyStack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,8 +100,7 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
Stack proxyStack = LogicalThreadContext.GetData(CURRENTPROXY_SLOTNAME) as Stack;
|
||||
return (proxyStack != null && proxyStack.Count > 0);
|
||||
return (tls_ProxyStack != null && tls_ProxyStack.Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,13 +114,14 @@ namespace Spring.Aop.Framework
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ProxyStack.Count == 0)
|
||||
Stack proxyStack = ProxyStack;
|
||||
if (proxyStack.Count == 0)
|
||||
{
|
||||
throw new AopConfigException(
|
||||
"Cannot find proxy: Set the 'ExposeProxy' property " +
|
||||
"to 'true' on IAdvised to make it available.");
|
||||
}
|
||||
return ProxyStack.Peek();
|
||||
return proxyStack.Peek();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,12 +157,13 @@ namespace Spring.Aop.Framework
|
||||
/// </exception>
|
||||
public static void PopProxy()
|
||||
{
|
||||
if (ProxyStack.Count == 0)
|
||||
Stack proxyStack = ProxyStack;
|
||||
if (proxyStack.Count == 0)
|
||||
{
|
||||
throw new AopConfigException(
|
||||
"Proxy stack empty. Always call 'PushProxy' before 'PopProxy'.");
|
||||
}
|
||||
ProxyStack.Pop();
|
||||
proxyStack.Pop();
|
||||
}
|
||||
|
||||
#region Constructor (s) / Destructor
|
||||
|
||||
@@ -22,82 +22,84 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using Spring.Collections;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Aop.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="Spring.Aop.Framework.IAdvisorChainFactory"/> implementation
|
||||
/// that caches advisor chains on a per-advised-method basis.
|
||||
/// </summary>
|
||||
/// <author>Rod Johnson</author>
|
||||
/// <author>Aleksandar Seovic (.NET)</author>
|
||||
[Serializable]
|
||||
public sealed class HashtableCachingAdvisorChainFactory : IAdvisorChainFactory
|
||||
{
|
||||
private IDictionary methodCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="AopAlliance.Intercept.IInterceptor"/> and
|
||||
/// <see cref="Spring.Aop.Framework.InterceptorAndDynamicMethodMatcher"/>
|
||||
/// instances for the supplied <paramref name="proxy"/>.
|
||||
/// </summary>
|
||||
/// <param name="advised">The proxy configuration object.</param>
|
||||
/// <param name="proxy">The object proxy.</param>
|
||||
/// <param name="method">
|
||||
/// The method for which the interceptors are to be evaluated.
|
||||
/// </param>
|
||||
/// <param name="targetType">
|
||||
/// The <see cref="System.Type"/> of the target object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The list of <see cref="AopAlliance.Intercept.IInterceptor"/> and
|
||||
/// <see cref="Spring.Aop.Framework.InterceptorAndDynamicMethodMatcher"/>
|
||||
/// instances for the supplied <paramref name="proxy"/>.
|
||||
/// </returns>
|
||||
public IList GetInterceptors(IAdvised advised, object proxy, MethodInfo method, Type targetType)
|
||||
{
|
||||
IList cached = (IList) this.methodCache[method];
|
||||
if (cached == null)
|
||||
{
|
||||
// recalculate...
|
||||
cached = AdvisorChainFactoryUtils.CalculateInterceptors(advised, proxy, method, targetType);
|
||||
/// <summary>
|
||||
/// <see cref="Spring.Aop.Framework.IAdvisorChainFactory"/> implementation
|
||||
/// that caches advisor chains on a per-advised-method basis.
|
||||
/// </summary>
|
||||
/// <author>Rod Johnson</author>
|
||||
/// <author>Aleksandar Seovic (.NET)</author>
|
||||
[Serializable]
|
||||
public sealed class HashtableCachingAdvisorChainFactory : IAdvisorChainFactory
|
||||
{
|
||||
private readonly IDictionary methodCache = new ListDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="AopAlliance.Intercept.IInterceptor"/> and
|
||||
/// <see cref="Spring.Aop.Framework.InterceptorAndDynamicMethodMatcher"/>
|
||||
/// instances for the supplied <paramref name="proxy"/>.
|
||||
/// </summary>
|
||||
/// <param name="advised">The proxy configuration object.</param>
|
||||
/// <param name="proxy">The object proxy.</param>
|
||||
/// <param name="method">
|
||||
/// The method for which the interceptors are to be evaluated.
|
||||
/// </param>
|
||||
/// <param name="targetType">
|
||||
/// The <see cref="System.Type"/> of the target object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The list of <see cref="AopAlliance.Intercept.IInterceptor"/> and
|
||||
/// <see cref="Spring.Aop.Framework.InterceptorAndDynamicMethodMatcher"/>
|
||||
/// instances for the supplied <paramref name="proxy"/>.
|
||||
/// </returns>
|
||||
public IList GetInterceptors(IAdvised advised, object proxy, MethodInfo method, Type targetType)
|
||||
{
|
||||
IList cached = (IList)this.methodCache[method];
|
||||
if (cached == null)
|
||||
{
|
||||
// recalculate...
|
||||
cached = AdvisorChainFactoryUtils.CalculateInterceptors(advised, proxy, method, targetType);
|
||||
this.methodCache[method] = cached;
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the first proxy is created.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The relevant <see cref="Spring.Aop.Framework.AdvisedSupport"/> source.
|
||||
/// </param>
|
||||
public void Activated(AdvisedSupport source)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Invoked when the first proxy is created.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The relevant <see cref="Spring.Aop.Framework.AdvisedSupport"/> source.
|
||||
/// </param>
|
||||
public void Activated(AdvisedSupport source)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when advice is changed after a proxy is created.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The relevant <see cref="Spring.Aop.Framework.AdvisedSupport"/> source.
|
||||
/// </param>
|
||||
public void AdviceChanged(AdvisedSupport source)
|
||||
{
|
||||
methodCache.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// Invoked when advice is changed after a proxy is created.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The relevant <see cref="Spring.Aop.Framework.AdvisedSupport"/> source.
|
||||
/// </param>
|
||||
public void AdviceChanged(AdvisedSupport source)
|
||||
{
|
||||
methodCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when interfaces are changed after a proxy is created.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The relevant <see cref="Spring.Aop.Framework.AdvisedSupport"/> source.
|
||||
/// </param>
|
||||
public void InterfacesChanged(AdvisedSupport source)
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Invoked when interfaces are changed after a proxy is created.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The relevant <see cref="Spring.Aop.Framework.AdvisedSupport"/> source.
|
||||
/// </param>
|
||||
public void InterfacesChanged(AdvisedSupport source)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace Spring.Aop.Framework
|
||||
private IAopProxyFactory aopProxyFactory =
|
||||
ObjectUtils.InstantiateType( typeof(ProxyConfig).Assembly, "Spring.Aop.Framework.DynamicProxy.CachedAopProxyFactory") as IAopProxyFactory;
|
||||
private bool exposeProxy;
|
||||
private object syncRoot = new object();
|
||||
private readonly object syncRoot = new object();
|
||||
#endregion
|
||||
|
||||
#region Properites
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2007 the original author or authors.
|
||||
* Copyright <20> 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,8 +22,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Spring.Collections;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
@@ -79,29 +80,23 @@ namespace Spring.Reflection.Dynamic
|
||||
#if NET_2_0
|
||||
#region Generated Function Cache
|
||||
|
||||
private static readonly IDictionary methodCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Obtains cached property info or creates a new entry, if none is found.
|
||||
/// </summary>
|
||||
private static FunctionDelegate GetOrCreateDynamicMethod(MethodInfo methodInfo)
|
||||
private class SafeMethodState
|
||||
{
|
||||
FunctionDelegate method = (FunctionDelegate)methodCache[methodInfo];
|
||||
if (method == null)
|
||||
public readonly FunctionDelegate method;
|
||||
public readonly object[] nullArguments;
|
||||
|
||||
public SafeMethodState(FunctionDelegate method, object[] nullArguments)
|
||||
{
|
||||
method = DynamicReflectionManager.CreateMethod(methodInfo);
|
||||
lock (methodCache)
|
||||
{
|
||||
methodCache[methodInfo] = method;
|
||||
}
|
||||
this.method = method;
|
||||
this.nullArguments = nullArguments;
|
||||
}
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IDictionary stateCache = new HybridDictionary();
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly FunctionDelegate method;
|
||||
private readonly object[] nullArguments;
|
||||
private readonly SafeMethodState state;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the safe method wrapper.
|
||||
@@ -111,9 +106,15 @@ namespace Spring.Reflection.Dynamic
|
||||
{
|
||||
AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a dynamic method for a null value.");
|
||||
|
||||
state = (SafeMethodState)stateCache[methodInfo];
|
||||
if (state == null)
|
||||
{
|
||||
state = new SafeMethodState(DynamicReflectionManager.CreateMethod(methodInfo),
|
||||
new object[methodInfo.GetParameters().Length]
|
||||
);
|
||||
stateCache[methodInfo] = state;
|
||||
}
|
||||
this.methodInfo = methodInfo;
|
||||
this.method = GetOrCreateDynamicMethod(methodInfo);
|
||||
this.nullArguments = new object[methodInfo.GetParameters().Length];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -131,14 +132,15 @@ namespace Spring.Reflection.Dynamic
|
||||
public object Invoke(object target, params object[] arguments)
|
||||
{
|
||||
// special case - when calling Invoke(null,null) it is undecidible if the second null is an argument or the argument array
|
||||
if (arguments==null && nullArguments.Length==1) arguments=nullArguments;
|
||||
int arglen = (arguments==null?0:arguments.Length);
|
||||
AssertUtils.IsTrue(
|
||||
nullArguments.Length == arglen
|
||||
, string.Format("Invalid number of arguments passed into method {0} - expected {1}, but was {2}", methodInfo.Name, nullArguments.Length, arglen)
|
||||
);
|
||||
object[] nullArguments = state.nullArguments;
|
||||
if (arguments == null && nullArguments.Length == 1) arguments = nullArguments;
|
||||
int arglen = (arguments == null ? 0 : arguments.Length);
|
||||
if (nullArguments.Length != arglen)
|
||||
{
|
||||
throw new ArgumentException(string.Format("Invalid number of arguments passed into method {0} - expected {1}, but was {2}", methodInfo.Name, nullArguments.Length, arglen));
|
||||
}
|
||||
|
||||
return this.method(target, arguments);
|
||||
return this.state.method(target, arguments);
|
||||
}
|
||||
#else
|
||||
private IDynamicMethod dynamicMethod;
|
||||
@@ -206,7 +208,7 @@ namespace Spring.Reflection.Dynamic
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#if NET_2_0
|
||||
/// <summary>
|
||||
/// Factory class for dynamic methods.
|
||||
@@ -263,7 +265,7 @@ namespace Spring.Reflection.Dynamic
|
||||
|
||||
private static readonly CreateMethodCallback s_createMethodCallback = new CreateMethodCallback(CreateInternal);
|
||||
|
||||
#region Create Method
|
||||
#region Create Method
|
||||
|
||||
/// <summary>
|
||||
/// Creates dynamic method instance for the specified <see cref="MethodInfo"/>.
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
using AopAlliance.Aop;
|
||||
using NUnit.Framework;
|
||||
|
||||
using Spring.Objects;
|
||||
@@ -34,58 +34,58 @@ using Spring.Util;
|
||||
|
||||
namespace Spring.Aop.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit tests for the AopContext class.
|
||||
/// </summary>
|
||||
/// <author>Rick Evans</author>
|
||||
[TestFixture]
|
||||
public sealed class AopContextTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
// makes sure the context is always empty before any unit test...
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
AopContext.PopProxy();
|
||||
} while (true);
|
||||
}
|
||||
catch (AopConfigException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof (AopConfigException))]
|
||||
public void CurrentProxyChokesIfNoAopProxyIsOnTheStack()
|
||||
{
|
||||
AopContext.CurrentProxy.ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CurrentProxyStackJustPeeksItDoesntPop()
|
||||
{
|
||||
string foo = "Foo";
|
||||
AopContext.PushProxy(foo);
|
||||
object fooref = AopContext.CurrentProxy;
|
||||
Assert.IsTrue(ReferenceEquals(foo, fooref),
|
||||
"Not the exact same instance (must be).");
|
||||
// must not have been popped off the stack by looking at it...
|
||||
object foorefref = AopContext.CurrentProxy;
|
||||
Assert.IsTrue(ReferenceEquals(fooref, foorefref),
|
||||
"Not the exact same instance (must be).");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof (AopConfigException))]
|
||||
public void PopProxyWithNothingOnStack()
|
||||
{
|
||||
AopContext.PopProxy();
|
||||
/// <summary>
|
||||
/// Unit tests for the AopContext class.
|
||||
/// </summary>
|
||||
/// <author>Rick Evans</author>
|
||||
[TestFixture]
|
||||
public sealed class AopContextTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
// makes sure the context is always empty before any unit test...
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
AopContext.PopProxy();
|
||||
} while (true);
|
||||
}
|
||||
catch (AopConfigException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(AopConfigException))]
|
||||
public void CurrentProxyChokesIfNoAopProxyIsOnTheStack()
|
||||
{
|
||||
AopContext.CurrentProxy.ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CurrentProxyStackJustPeeksItDoesntPop()
|
||||
{
|
||||
string foo = "Foo";
|
||||
AopContext.PushProxy(foo);
|
||||
object fooref = AopContext.CurrentProxy;
|
||||
Assert.IsTrue(ReferenceEquals(foo, fooref),
|
||||
"Not the exact same instance (must be).");
|
||||
// must not have been popped off the stack by looking at it...
|
||||
object foorefref = AopContext.CurrentProxy;
|
||||
Assert.IsTrue(ReferenceEquals(fooref, foorefref),
|
||||
"Not the exact same instance (must be).");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(AopConfigException))]
|
||||
public void PopProxyWithNothingOnStack()
|
||||
{
|
||||
AopContext.PopProxy();
|
||||
}
|
||||
|
||||
[Test(Description = "SPRNET-1158")]
|
||||
public void IsActiveMatchesStackState()
|
||||
{
|
||||
Assert.IsFalse(AopContext.IsActive);
|
||||
@@ -97,11 +97,72 @@ namespace Spring.Aop.Framework
|
||||
|
||||
#region CurrentProxyIsThreadSafe
|
||||
|
||||
[Test, Explicit]
|
||||
public void ProxyPerformanceTests()
|
||||
{
|
||||
int runs = 5000000;
|
||||
StopWatch watch = new StopWatch();
|
||||
|
||||
ITestObject testObject = new ChainableTestObject(null);
|
||||
using (watch.Start("Naked Duration: {0}"))
|
||||
{
|
||||
for (int i = 0; i < runs; i++)
|
||||
{
|
||||
object result = testObject.DoSomething(this);
|
||||
}
|
||||
}
|
||||
|
||||
ITestObject hardcodedWrapper = new ChainableTestObject(testObject);
|
||||
using (watch.Start("Hardcoded Wrapper Duration: {0}"))
|
||||
{
|
||||
for (int i = 0; i < runs; i++)
|
||||
{
|
||||
object result = hardcodedWrapper.DoSomething(this);
|
||||
}
|
||||
}
|
||||
|
||||
PeformanceTestAopContextInterceptor interceptor = new PeformanceTestAopContextInterceptor();
|
||||
ITestObject proxy = CreateProxy(testObject, interceptor, false);
|
||||
using(watch.Start("Proxy Duration ('ExposeProxy'==false): {0}"))
|
||||
{
|
||||
for(int i=0;i<runs;i++)
|
||||
{
|
||||
object result = proxy.DoSomething(this);
|
||||
}
|
||||
}
|
||||
Assert.AreEqual(runs, interceptor.Calls);
|
||||
|
||||
interceptor = new PeformanceTestAopContextInterceptor();
|
||||
proxy = CreateProxy(testObject, interceptor, true);
|
||||
using(watch.Start("Proxy Duration ('ExposeProxy'==true): {0}"))
|
||||
{
|
||||
for(int i=0;i<runs;i++)
|
||||
{
|
||||
object result = proxy.DoSomething(this);
|
||||
}
|
||||
}
|
||||
Assert.AreEqual(runs, interceptor.Calls);
|
||||
}
|
||||
|
||||
private class PeformanceTestAopContextInterceptor : IMethodInterceptor
|
||||
{
|
||||
public int Calls = 0;
|
||||
|
||||
public object Invoke(IMethodInvocation invocation)
|
||||
{
|
||||
Calls++;
|
||||
Object ret = invocation.Proceed();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
[Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-341")]
|
||||
public void CurrentProxyIsThreadSafe()
|
||||
{
|
||||
AsyncTestMethod t1 = new AsyncTestMethod(100, new ThreadStart(ProxyTestObjectAndExposeProxy));
|
||||
AsyncTestMethod t2 = new AsyncTestMethod(100, new ThreadStart(ProxyTestObjectAndExposeProxy));
|
||||
ProxyTestObjectAndExposeProxy();
|
||||
|
||||
AsyncTestMethod t1 = new AsyncTestMethod(1000, new ThreadStart(ProxyTestObjectAndExposeProxy));
|
||||
AsyncTestMethod t2 = new AsyncTestMethod(1000, new ThreadStart(ProxyTestObjectAndExposeProxy));
|
||||
t1.Start();
|
||||
t2.Start();
|
||||
|
||||
@@ -109,32 +170,85 @@ namespace Spring.Aop.Framework
|
||||
t2.AssertNoException();
|
||||
}
|
||||
|
||||
public interface ITestObject
|
||||
{
|
||||
object DoSomething(object arg);
|
||||
}
|
||||
|
||||
private class ChainableTestObject : ITestObject
|
||||
{
|
||||
private readonly ITestObject next;
|
||||
|
||||
public ChainableTestObject(ITestObject next)
|
||||
{
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public virtual object DoSomething(object arg)
|
||||
{
|
||||
if (next != null)
|
||||
{
|
||||
return next.DoSomething(arg);
|
||||
}
|
||||
// simulate some sensible work
|
||||
string rep = string.Format("{0} {1}", this.GetType(), arg.GetHashCode());
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProxyTestObjectAndExposeProxy()
|
||||
{
|
||||
TestObject target = new TestObject();
|
||||
target.Age = 26;
|
||||
TestAopContextInterceptor interceptor = new TestAopContextInterceptor();
|
||||
|
||||
ITestObject proxy = CreateProxyChain(interceptor, true);
|
||||
|
||||
Assert.IsFalse(AopContext.IsActive);
|
||||
Assert.AreEqual(this, proxy.DoSomething(this), "Incorrect return value");
|
||||
Assert.IsFalse(AopContext.IsActive);
|
||||
Assert.AreEqual(2, interceptor.Calls); // 2 interceptions on the way
|
||||
}
|
||||
|
||||
private ITestObject CreateProxyChain(IAdvice interceptor, bool exposeProxy)
|
||||
{
|
||||
ITestObject first = new ChainableTestObject(null);
|
||||
ITestObject firstProxy = CreateProxy(first, interceptor, exposeProxy);
|
||||
Assert.IsNotNull(firstProxy);
|
||||
|
||||
ITestObject second = new ChainableTestObject(firstProxy);
|
||||
ITestObject secondProxy = CreateProxy(second, interceptor, exposeProxy);
|
||||
Assert.IsNotNull(secondProxy);
|
||||
return secondProxy;
|
||||
}
|
||||
|
||||
private ITestObject CreateProxy(object target, IAdvice interceptor, bool exposeProxy)
|
||||
{
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.ExposeProxy = true;
|
||||
pf.ExposeProxy = exposeProxy;
|
||||
pf.Target = target;
|
||||
pf.AddAdvice(new TestAopContextInterceptor());
|
||||
pf.AddAdvice(interceptor);
|
||||
|
||||
ITestObject proxy = pf.GetProxy() as ITestObject;
|
||||
Assert.IsNotNull(proxy);
|
||||
Assert.AreEqual(target.Age, proxy.Age, "Incorrect age");
|
||||
return pf.GetProxy() as ITestObject;
|
||||
}
|
||||
|
||||
private class TestAopContextInterceptor : IMethodInterceptor
|
||||
{
|
||||
public int Calls = 0;
|
||||
|
||||
public object Invoke(IMethodInvocation invocation)
|
||||
{
|
||||
Calls++;
|
||||
Assert.IsTrue(AopContext.IsActive);
|
||||
Assert.IsNotNull(AopContext.CurrentProxy);
|
||||
Assert.AreSame(invocation.Proxy, AopContext.CurrentProxy);
|
||||
|
||||
Object ret = invocation.Proceed();
|
||||
|
||||
Assert.IsNotNull(AopContext.CurrentProxy);
|
||||
Assert.IsTrue(AopContext.IsActive);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user