'Spring4D Container Interception a-la Aspect Oriented Programming (AOP)
Goals:
- In the Delphi programming language.
- An aspect that intercepts all virtual methods.
- A class whose constructor requires arguments.
- A Dependency Injection (DI) container that BOTH
- Creates an instance of the class, passing the correct arguments to the constructor.
- Applies the aspect to the instance so that all calls to virtual methods on the instance are intercepted.
I have made an attempt to do this with the Spring4D Container and Interception abstractions:
The below code outputs nothing. I would like similar code that outputs:
Intercepted one
Intercepted two
Intercepted three
unit Main;
interface
uses
Spring.Container,
Spring.Interception,
Spring.Services;
procedure Run;
type
TAspect = class(TInterfacedObject, IInterceptor)
public
procedure Intercept(const Invocation: IInvocation);
end;
TDependency = class(TObject)
procedure two; virtual;
end;
TTarget = class(TObject)
var FDependency: TDependency;
constructor Create(const Dependency: TDependency);
procedure one; virtual;
procedure three; virtual;
end;
implementation
procedure Run;
begin
GlobalContainer.RegisterType<TAspect>;
GlobalContainer.RegisterType<TDependency>.InterceptedBy<TAspect>;
GlobalContainer.RegisterType<TTarget>.InterceptedBy<TAspect>;
GlobalContainer.Build;
var Target := ServiceLocator.GetService<TTarget>;
Target.one;
end;
procedure TAspect.Intercept(const Invocation: IInvocation);
begin
Writeln('Intecepted ' + Invocation.Method.Name);
Invocation.Proceed;
end;
procedure TDependency.two;
begin
end;
constructor TTarget.Create(const Dependency: TDependency);
begin
inherited Create;
FDependency := Dependency;
end;
procedure TTarget.one;
begin
FDependency.two;
three;
end;
procedure TTarget.three;
begin
end;
end.
I tried something like this, and it intercepts ALL calls to virtual methods, but it doesn't meet all the goals listed above because it doesn't go through the DI container.
var Aspect: IInterceptor := TAspect.Create;
var Target := TProxyGenerator.CreateClassProxy<TTarget>([Aspect]);
I also tried using the container, but delegating to something that calls TProxyGenerator, and that intercepts ALL calls to virtual methods, but it doesn't meet all the goals listed above because it can only use the zero argument constructor (i.e. no constructor injection).
Solution 1:[1]
Interceptors via InterceptedBy only get applied by the container to interface-based services as proxies. This is simply because a) there is no ambiguity in how to manage the lifetime of such and b) all method calls go through the proxy opposed to class based services where only the virtual methods get intercepted.
When this gets applied to the code above you will get output for one and two but not for three because that method gets called from within the TTarget instance.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Stefan Glienke |
