一直忙于撸码,难得有时间,研究了下AOP,与大家分享一下,也便于以后查看。( ̄▽ ̄)~*
因为.NET CORE中集成的IOC容器是Castle,日常大家常用的是Autofac,所以本人只研究了下.NET默认的Remoting实现方式,Castle实现方式和Autofac实现方式。其中,Castle有两个插件,Castle.Windsor(IOC容器)和Castle.Core(核心),Autofac的拦截器是使用的Castle.Core的动态代理。
AOP(Aspect Oriented Programming):面向切面(方面)编程,是OOP的延续,用来在不修改代码的情况下,动态的添加功能,将核心逻辑与非核心逻辑分开。其中,记录日志便是AOP最普遍的使用场景之一。
DI(Dependency Injection)依赖注入,实际上是IOC(控制翻转)的一种实现方式,之所以叫依赖注入,是因为调用者和被调用者的依赖关系是通过第三方注入的,这个第三方通常说的便是IOC容器。IOC是一种思想,依赖倒置原则提倡程序要依赖于抽象,不要依赖于具体实现,以便降低耦合,而控制实现接口的,通常还是调用者,调用者和具体实现之间还是存在依赖关系,现在把这个控制权交给第三方,这便是IOC思想。在这里讲这些内容,是因为实现动态代理,往往需要依托于IOC容器。
AOP的拦截器有两种实现方式:动态代理和静态代理
是在程序运行中,动态的添加切入点,这便是通常需要用到IOC容器的原因。
优缺点:效率相对于静态代理要低,但灵活性强,不需要额外的编译。
我们所讲的三种方式,都是动态代理实现的。
是在程序预编译阶段插进去的。
优缺点:相对于动态代理,性能要高,但灵活性较差,需要额外的编译。
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Text;
using System.Threading.Tasks;
///
/// 默认实现方式(Remoting方式)
///
namespace DefaultDemo
{
class Program
{
static void Main(string[] args)
{
var per = new Proxy(new King()).GetTransparentProxy() as King;
if (per != null)
{
var str = per.RuleTheCastle("fffff");
}
Console.ReadKey();
}
}
///
/// 基本类型
///
class King : MarshalByRefObject
{
public string RuleTheCastle(string str)
{
str = "hello word," + str;
return str;
}
}
public class Proxy : RealProxy where T : new()
{
private object _obj;
public Proxy(object obj)
: base(typeof(T))
{
_obj = obj;
}
public override IMessage Invoke(IMessage msg)
{
IDictionary oProperties = msg.Properties;
object oMethodName = null;
if (oProperties.Contains("__MethodName"))
{
oMethodName = oProperties["__MethodName"];
}
Console.WriteLine("方法名:{0}", oMethodName);
//入参
object[] oArguments;
if (oProperties.Contains("__Args"))
{
oArguments = oProperties["__Args"] as object[];
}
else
{
oArguments = new object[0];
}
foreach (var oArgument in oArguments)
{
Console.WriteLine("入参:{0}", oArgument);
}
//调用和出参
object oReturnValue = ((IMethodCallMessage)msg).MethodBase.Invoke(_obj, oArguments);
Console.WriteLine("出参:{0}", oReturnValue);
return new ReturnMessage(oReturnValue, null, 0, null, null);
}
}
}
using Castle.Core;
using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
public interface IKing
{
string RuleTheCastle(string name);
}
class King : IKing
{
public string Name { get; set; }
public int Age { get; set; }
public string RuleTheCastle(string name)
{
Console.WriteLine("方法已执行");
return "Hello Word," + name;
}
}
2、添加一个安装类RepositoriesInstaller
,需要继承IWindsorInstaller
接口,在里面注册组件
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For().ImplementedBy().LifestyleSingleton()
);
}
}
IWindsorContainer container = new WindsorContainer();
container.Install(new RepositoriesInstaller());
var king = container.Resolve();
string ret = king.RuleTheCastle("tzj");
container.Dispose();
LoggingInterceptor
,并让他继承IInterceptor
接口 public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
//类型
var type = invocation.TargetType;
//对象
var oObject = invocation.InvocationTarget;
//方法
string strMethodName = invocation.Method.Name;
Console.WriteLine("调用的方法是:" + strMethodName);
//入参
var oArguments = invocation.Arguments;
if (oArguments != null && oArguments.Length > 0)
{
for (int i = 0; i < oArguments.Length; i++)
{
Console.WriteLine("入参{0}:{1}", i, oArguments[i]);
}
}
//执行此方法,正式调用方法
//执行之前,可获取入参
//执行成功之后,可获取出参
invocation.Proceed();
//输出参数和ref只能通过对比入参来实现
//出参
var oReturnValue = invocation.ReturnValue;
Console.WriteLine("出参:" + oReturnValue);
}
catch (Exception ex)
{
//不管是被拦截方法中报错,还是拦截方法中报错,都会走这里
Console.WriteLine("错误信息:" + ex.ToString());
}
}
}
2.在实现类上添加对应的拦截器属性,需要注意的是,这个实现类必须是受本IOC容器控制的
[Interceptor(typeof(LoggingInterceptor))]
Component.For()
这样便完成了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Castle.Core;
using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
namespace CastleDemo
{
class Program
{
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
container.Install(new RepositoriesInstaller());
var king = container.Resolve();
string ret = king.RuleTheCastle("tzj");
Console.WriteLine(ret);
container.Dispose();
Console.ReadKey();
}
}
public interface IKing
{
string RuleTheCastle(string name);
}
//切面的类必须是受本容器控制的
[Interceptor(typeof(LoggingInterceptor))]
class King : IKing
{
public string Name { get; set; }
public int Age { get; set; }
public string RuleTheCastle(string name)
{
Console.WriteLine("方法已执行");
return "Hello Word," + name;
}
}
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For(),
Component.For().ImplementedBy().LifestyleSingleton()
);
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
//类型
var type = invocation.TargetType;
//对象
var oObject = invocation.InvocationTarget;
//方法
string strMethodName = invocation.Method.Name;
Console.WriteLine("调用的方法是:" + strMethodName);
//入参
var oArguments = invocation.Arguments;
if (oArguments != null && oArguments.Length > 0)
{
for (int i = 0; i < oArguments.Length; i++)
{
Console.WriteLine("入参{0}:{1}", i, oArguments[i]);
}
}
//执行此方法,正式调用方法
//执行之前,可获取入参
//执行成功之后,可获取出参
invocation.Proceed();
//输出参数和ref只能通过对比入参来实现
//出参
var oReturnValue = invocation.ReturnValue;
Console.WriteLine("出参:" + oReturnValue);
}
catch (Exception ex)
{
//不管是被拦截方法中报错,还是拦截方法中报错,都会走这里
Console.WriteLine("错误信息:" + ex.ToString());
}
}
}
}
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
这块与上面类似,直接贴代码了
private static IContainer Container { get; set; }
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType().As();
Container = builder.Build();
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve();
writer.RuleTheCastle("aaa");
}
Console.Read();
}
}
public interface IKing
{
string RuleTheCastle(string name);
}
public class King : IKing
{
public string Name { get; set; }
public int Age { get; set; }
public string RuleTheCastle(string name)
{
Console.WriteLine("方法已执行");
return "Hello Word," + name;
}
}
拦截器也类似
[Intercept(typeof(LoggingInterceptor))]
启用类代理,这种方式需要切面类的权限是public,并且方法是virtual方法
builder.RegisterType().As().EnableClassInterceptors();
启用接口代理
builder.RegisterType().As().EnableInterfaceInterceptors();
builder.RegisterType();
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AutofacDemo
{
class Program
{
private static IContainer Container { get; set; }
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType();
//EnableClassInterceptors 启用类代理 要求方法是virtual
//builder.RegisterType().As().EnableClassInterceptors();
//EnableInterfaceInterceptors 启用接口代理
builder.RegisterType().As().EnableInterfaceInterceptors();
Container = builder.Build();
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve();
writer.RuleTheCastle("aaa");
}
Console.Read();
}
}
public interface IKing
{
string RuleTheCastle(string name);
}
//切面的类必须是受本容器控制的
[Intercept(typeof(LoggingInterceptor))]
public class King : IKing
{
public string Name { get; set; }
public int Age { get; set; }
public string RuleTheCastle(string name)
{
Console.WriteLine("方法已执行");
return "Hello Word," + name;
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
//类型
var type = invocation.TargetType;
//对象
var oObject = invocation.InvocationTarget;
//方法
string strMethodName = invocation.Method.Name;
Console.WriteLine("调用的方法是:" + strMethodName);
//入参
var oArguments = invocation.Arguments;
if (oArguments != null && oArguments.Length > 0)
{
for (int i = 0; i < oArguments.Length; i++)
{
Console.WriteLine("入参{0}:{1}", i, oArguments[i]);
}
}
//执行此方法,正式调用方法
//执行之前,可获取入参
//执行成功之后,可获取出参
invocation.Proceed();
//输出参数和ref只能通过对比入参来实现
//出参
var oReturnValue = invocation.ReturnValue;
Console.WriteLine("出参:" + oReturnValue);
}
catch (Exception ex)
{
//不管是被拦截方法中报错,还是拦截方法中报错,都会走这里
Console.WriteLine("错误信息:" + ex.ToString());
}
}
}
}
文章中,有些地方没写那么细,不过注释中大部分都有,等我有时间再往细加,还望见谅。(✪ω✪)
第一次正式写博客,如果哪有问题,还请大佬们不惜赐教。(〃‘▽’〃)