Castle.DynamicProxy的NET Core和Framework的AOP实施
Castle.DynamicProxy
- 拦截类,虚成员
- 拦截接口
- 不指定实现进行代理CreateInterfaceProxyWithoutTarget
- 指定实现进行代理CreateInterfaceProxyWithTarget
- CreateInterfaceProxyWithTargetInterface
- 异步方法代理
- 代理类
- 代理接口
远程处理中的代理要求您从MarshalByRefObject派生类,但如果您无法更改类的基类,这是不切实际的。DynamicProxy我们可以在不更改基类的情况下代理我们的类,尽管我们需要类成员是virtual
的才能使用此代码。
借鉴
拦截类,虚成员
Castle DynamicProxy 提供了两种创建类代理的方法:CreateClassProxyWithTarget
和 CreateClassProxy
。以下是这两种方法的解释和对比:
-
CreateClassProxyWithTarget:
CreateClassProxyWithTarget
方法用于创建一个代理对象,该对象包装了一个已经存在的目标对象实例。这意味着你可以为目标对象提供一个实例,并且所有的方法调用(包括非虚方法)都会通过拦截器,然后转发到目标对象。- 这种方式下,你可以拦截并修改目标对象的行为,包括非虚方法和属性的访问。
- 它允许你传递一个目标对象实例和一组拦截器,代理对象将使用这些拦截器来拦截对目标对象的调用。
- 例如,如果你有一个类
ProductRepository
和一个拦截器LoggerInterceptor
,你可以这样创建代理:ProxyGenerator generator = new ProxyGenerator(); IInterceptor loggerIntercept = new LoggerInterceptor(); ProductRepository target = new ProductRepository(); ProductRepository proxy = generator.CreateClassProxyWithTarget(target, loggerIntercept);
- 这种方法适用于需要代理非虚方法或字段的场景,且要求目标类是可继承的。
-
CreateClassProxy:
CreateClassProxy
方法用于创建一个代理对象,该对象不需要一个实际的目标对象实例。它在运行时动态生成一个代理类,这个类继承自指定的类,并重写其中的虚方法。- 这种方式下,只有目标类中的虚方法可以被拦截和修改。
- 你只需要传递一个拦截器实例,代理对象将拦截对目标类的所有虚方法的调用。
- 例如,如果你有一个类
ProductRepository
和一个拦截器LoggerInterceptor
,你可以这样创建代理:ProxyGenerator generator = new ProxyGenerator(); IInterceptor loggerIntercept = new LoggerInterceptor(); ProductRepository proxy = generator.CreateClassProxy<ProductRepository>(loggerIntercept);
- 这种方法适用于目标类中的方法是虚方法,并且你不需要代理非虚方法的场景。
总结来说,CreateClassProxyWithTarget
允许你代理一个已经存在的对象实例,包括非虚方法,而 CreateClassProxy
只能代理目标类中的虚方法。选择哪种方法取决于你的具体需求,是否需要代理非虚方法,以及是否已经有一个目标对象实例。
我们将创建一个拦截器,顾名思义,它将用于拦截动态代理对我们对象的调用,在这种情况下,我们将把调用的方法/属性记录到Console中。
public class Interceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Before target call {invocation.Method.Name}" );
try
{
invocation.Proceed();
}
catch (Exception e)
{
Console.WriteLine($"Target exception {ex.Message}");
throw;
}
finally
{
Console.WriteLine($"After target call {invocation.Method.Name}");
}
}
}
使用者
public class MyClass
{
public virtual bool Flag { get; set; }
public virtual void Execute()
{
Console.WriteLine("Execute method called");
}
}
创建代理
var proxy = new ProxyGenerator()
.CreateClassProxy<MyClass>(
new Interceptor());
proxy.Flag = true;
proxy.Execute();
输出
Before target call set_Flag
After target call set_Flag
Before target call Execute
Execute method called
After target call Execute
拦截接口
在这种情况下,代理基于接口,只需调用“目标”对象属性/方法。因此,这种调用转发意味着目标对象不需要将方法/属性标记为虚拟。
CreateInterfaceProxyWithoutTarget
和 CreateInterfaceProxyWithTarget
是 Castle DynamicProxy 库中用于创建代理对象的两个方法,它们的主要区别在于是否需要一个目标对象(target object)以及它们生成代理对象的方式。
-
CreateInterfaceProxyWithoutTarget
:- 这个方法用于创建一个代理对象,该对象不需要一个实际的目标对象实例。它在运行时动态生成一个实现了指定接口的对象,并且所有的方法调用都会被拦截器拦截。
- 这意味着你可以为一个接口创建一个代理,而不需要实现该接口的任何类。
- 如果接口方法要求返回值,你需要在拦截器中指定返回值。
-
CreateInterfaceProxyWithTarget
:- 这个方法用于创建一个代理对象,该对象包装了一个已经存在的目标对象实例。
- 它允许你为目标对象提供一个实现了接口的实例,并且所有的方法调用都会通过拦截器,然后转发到目标对象。
- 这种方式下,目标对象的实现方法不需要是虚方法(virtual),因为代理对象不是通过继承来覆盖方法,而是通过委托来调用方法。
总结来说,CreateInterfaceProxyWithoutTarget
适用于不需要实际目标对象,而是希望动态创建一个实现接口的对象的场景,而 CreateInterfaceProxyWithTarget
适用于已经有了一个实现了接口的对象,希望通过代理来增强或修改其行为的场景。
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
void DoWork();
}
public class Person : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public void DoWork()
{
Console.WriteLine("I am working!");
}
}
不指定实现进行代理CreateInterfaceProxyWithoutTarget
var proxy = new ProxyGenerator()
.CreateInterfaceProxyWithoutTarget<IPerson>(
new Interceptor());
proxy.FirstName = "Scooby";
proxy.LastName = "Doo";
不指定实现进行代理的话不能调用Proceed,需要注释掉invocation.Proceed();
指定实现进行代理CreateInterfaceProxyWithTarget
只有Person被代理
var proxy = (IPerson)new ProxyGenerator()
.CreateInterfaceProxyWithTarget(
typeof(IPerson),
new Person(),
new Interceptor());
proxy.FirstName = "Scooby";
proxy.LastName = "Doo";
CreateInterfaceProxyWithTargetInterface
Castle DynamicProxy 提供了 CreateInterfaceProxyWithTargetInterface
方法,用于创建接口代理对象。这个方法与 CreateInterfaceProxyWithTarget
相似,但有一些关键的区别:
-
IChangeProxyTarget 接口支持:
CreateInterfaceProxyWithTargetInterface
方法允许拦截器实现IChangeProxyTarget
接口,这使得在拦截过程中可以动态地更改目标对象。这意味着在方法调用过程中,拦截器可以决定使用不同的目标对象来处理调用,而不是始终使用创建代理时指定的原始目标对象。
-
缓存使用:
CreateInterfaceProxyWithTargetInterface
在使用缓存方面更为高效。它更好地利用了缓存机制,可以减少代理对象的创建次数,提高性能。这一点在性能敏感的应用中尤为重要。
-
类型共享:
- 根据搜索结果中的示例代码,使用
CreateInterfaceProxyWithTargetInterface
创建的代理对象会共享相同的类型,而使用CreateInterfaceProxyWithTarget
创建的代理对象则不会。这可以通过比较两个代理对象的类型是否相等来验证。在示例中,使用CreateInterfaceProxyWithTargetInterface
创建的两个代理对象的类型是相同的,而使用CreateInterfaceProxyWithTarget
创建的两个代理对象的类型是不同的。
- 根据搜索结果中的示例代码,使用
总结来说,CreateInterfaceProxyWithTargetInterface
提供了更灵活的拦截器支持和更高效的缓存使用,这使得它在需要动态更改目标对象或关注性能的场景中更为合适。而 CreateInterfaceProxyWithTarget
则适用于那些不需要动态更改目标对象的场景。
异步方法代理
使用Nuget简化异步代理
install-package Castle.Core.AsyncInterceptor
代理类
var generator2 = new ProxyGenerator();
var interceptor2 = new AsyncInterceptor();
var proxy2 = generator.CreateClassProxyWithTarget<AsyncModule>(new AsyncModule(), interceptor2);
await proxy2.PerformAsyncAction();await proxy2.PerformAsyncFunc().Dump();
public class AsyncModule
{
public virtual async Task PerformAsyncAction()
{
await Task.Delay(1000);
Console.WriteLine("Async action performed.");
}
public virtual async Task<int> PerformAsyncFunc()
{
await Task.Delay(1000);
return 10;
}
}
拦截器
public class AsyncInterceptor : IAsyncInterceptor
{
public void InterceptAsynchronous(Castle.DynamicProxy.IInvocation invocation)
{
// 在异步方法执行前的操作
Console.WriteLine($"Before async method: {invocation.Method.Name}");
// 调用异步方法
invocation.Proceed();
// 等待异步方法完成
var task = (Task)invocation.ReturnValue;
task.ContinueWith(t =>
{
// 在异步方法执行后的操作
Console.WriteLine($"After async method: {invocation.Method.Name}");
});
}
public void InterceptAsynchronous<TResult>(Castle.DynamicProxy.IInvocation invocation)
{
// 在异步方法执行前的操作
Console.WriteLine($"Before async method: {invocation.Method.Name}");
// 调用异步方法
invocation.Proceed();
// 等待异步方法完成
var task = (Task<TResult>)invocation.ReturnValue;
task.ContinueWith(t =>
{
// 在异步方法执行后的操作
Console.WriteLine($"After async method: {invocation.Method.Name}");
});
}
public void InterceptSynchronous(Castle.DynamicProxy.IInvocation invocation)
{
// 同步方法的拦截逻辑
Console.WriteLine($"Before sync method: {invocation.Method.Name}");
invocation.Proceed();
Console.WriteLine($"After sync method: {invocation.Method.Name}");
}
}
效果
代理接口
var generator = new ProxyGenerator();
var interceptor = new AsyncInterceptor();
var proxy = generator.CreateInterfaceProxyWithTargetInterface<IAsyncService>(new AsyncService(), interceptor);
// 调用异步方法,拦截器中的逻辑将被执行
await proxy.PerformAsyncAction();
await proxy.PerformAsyncFunc().Dump();
public interface IAsyncService
{
Task PerformAsyncAction();
Task<int> PerformAsyncFunc();
}
public class AsyncService : IAsyncService
{
public async Task PerformAsyncAction()
{
await Task.Delay(1000);
Console.WriteLine("Async action performed.");
}
public async Task<int> PerformAsyncFunc()
{
await Task.Delay(1000);
return 10;
}
}
效果