AOP and DI: How to create an aspect-aware interfaced dependency-injected object?
<p>I'd like to create an <em>aspect-aware interfaced dependency-injected object</em> through the means of the Spring/4D framework. My issue is, that I don't know how to combine both parts. The general idea is the following:</p>

<ol>
<li><p>Create the aspect layer object and hold two interfaces to it: one to pass as the dependency to the object (<code>IAspect</code>) and one to weave in as aspect into the object (<code>IInterceptor</code>):</p>

<pre><code>Temp := TAspect.Create;
Aspect := Temp as IAspect;
Interceptor := Temp as IInterceptor;
</code></pre></li>
<li><p>Create the interfaced dependency-injected object:</p>

<pre><code>Instance := TInstance.Create(Aspect) {as IInstance};
</code></pre></li>
<li><p>Weave in the aspect:</p>

<pre><code>Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]);
</code></pre></li>
</ol>

<p>To solve this, I think of registering a factory with a custom constructor along these lines:</p>

<pre><code>Aspect := Resolve&lt;IAspect&gt;;
Interceptor := Aspect as IInterceptor;
Instance := InstanceFactory(Aspect); // InstanceFactory := Resolve&lt;IInstanceFactory&gt;;
Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]);
</code></pre>

<p>My issue is, how would I register this with the <code>Container: TContainer</code> from Spring?</p>

<hr>

<p><strong>Example</strong>: The program below behaves like I want and demonstrates through which aspect layers the <code>GetValue</code> call runs. The custom object creation hapens in the <code>$Region</code> in the main routine. How would I need to refactor this program to use the DI container from the Spring/4D framework, yet keep the custom construction of an aspect-aware object?</p>

<pre><code>program Project1;

{$AppType Console}

{$R *.res}

uses
  System.SysUtils,
  Spring,
  Spring.Interception;

type
  IAspect = interface
    ['{AF8E19F6-176D-490E-A475-4682336CAB89}']
    function GetSetting: String;
    procedure SetSetting(const Value: String);

    property Setting: String read GetSetting write SetSetting;
  end;

  TAspect = class (TInterfacedObject, IInterceptor, IAspect)
  strict private
    FSetting: String;

    function GetSetting: String;
    procedure SetSetting(const Value: String);

    procedure Intercept(const Invocation: IInvocation);

  public
    constructor Create;
  end;

  IThingy = interface (IInvokable)
    function GetAspect: IAspect;
    function GetValue: String;
    procedure SetValue(const Value: String);

    property InstanceAspect: IAspect read GetAspect;
    property Value: String read GetValue write SetValue;
  end;

  TThingy = class (TInterfacedObject, IThingy)
  strict private
    FInstanceAspect: IAspect;
    FClassAspect: IAspect;
    FValue: String;

    function GetAspect: IAspect;
    function GetValue: String;
    procedure SetValue(const Value: String);

  public
    constructor Create(const InstanceAspect, ClassAspect: IAspect);
  end;

{ TAspect }

constructor TAspect.Create;
begin
  inherited;
  FSetting := ' intercepted by class aspect';
end;

function TAspect.GetSetting: String;
begin
  Result := FSetting;
end;

procedure TAspect.Intercept(
  const Invocation: IInvocation);
begin
  Invocation.Proceed;

  if Invocation.Method.Name = 'GetValue' then
    Invocation.Result := TValue.From&lt;String&gt;(Invocation.Result.AsString + FSetting);
end;

procedure TAspect.SetSetting(
  const Value: String);
begin
  FSetting := Value;
end;

{ TThingy }

constructor TThingy.Create(const InstanceAspect, ClassAspect: IAspect);
begin
  inherited Create;
  FInstanceAspect := InstanceAspect;
  FClassAspect := ClassAspect;
  FValue := 'Value';
end;

function TThingy.GetAspect: IAspect;
begin
  Result := FInstanceAspect;
end;

function TThingy.GetValue: String;
begin
  Result := FValue;
end;

procedure TThingy.SetValue(const Value: String);
begin
  FValue := Value;
end;

{ Main }

procedure Main;
var
  Temp: TInterfacedObject;
  ClassAspect: IAspect;
  ClassInterceptor: IInterceptor;
  InstanceAspect: IAspect;
  InstanceInterceptor: IInterceptor;
  Thingy1: IThingy;
  Thingy2: IThingy;
begin
  {$Region 'How to do this with the Spring DI container?'}
  Temp := TAspect.Create;
  ClassAspect := Temp as IAspect;
  ClassInterceptor := Temp as IInterceptor;

  Temp := TAspect.Create;
  InstanceAspect := Temp as IAspect;
  InstanceInterceptor := Temp as IInterceptor;
  Thingy1 := TThingy.Create(InstanceAspect, ClassAspect);
  Thingy1 := TProxyGenerator.CreateInterfaceProxyWithTarget(Thingy1, [ClassInterceptor, InstanceInterceptor]);

  Temp := TAspect.Create;
  InstanceAspect := Temp as IAspect;
  InstanceInterceptor := Temp as IInterceptor;
  Thingy2 := TThingy.Create(InstanceAspect, ClassAspect);
  Thingy2 := TProxyGenerator.CreateInterfaceProxyWithTarget(Thingy2, [ClassInterceptor, InstanceInterceptor]);
  {$EndRegion}

  Thingy1.InstanceAspect.Setting := ' intercepted by instance aspect 1';
  Thingy2.InstanceAspect.Setting := ' intercepted by instance aspect 2';

  Thingy1.Value := 'Value 1';
  Thingy2.Value := 'Value 2';

  WriteLn(Format('Thingy1.Value: %s', [Thingy1.Value]));
  WriteLn(Format('Thingy2.Value: %s', [Thingy2.Value]));
end;

begin
  try
    Main;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
  if DebugHook &lt;&gt; 0 then
  begin
    WriteLn('Press enter...');
    ReadLn;
  end;
end.
</code></pre>

<p>Output:</p>

<pre><code>Thingy1.Value: Value 1 intercepted by instance aspect 1 intercepted by class aspect
Thingy2.Value: Value 2 intercepted by instance aspect 2 intercepted by class aspect
Press enter...
</code></pre>