概念
1、Aspect-Oriented Programming(面向切面编程),AOP就是对OOP(面向对象编程)的一种功能扩展。 2、需要将核心业务与公共业务分离。
AOP优势
1、将通用功能从业务逻辑中抽离出来,可以省略大量重复代码,有利于代码的操作和维护。 2、模块化开发,降低软件架构的复杂度。
静态AOP
采用装饰器模式或者代理模式实现。
抽象类与实现类:
public interface IInfoProcessor
{
void ReadInfo(string info);
}
public class InfoProcessor : IInfoProcessor
{
public InfoProcessor()
{
Console.WriteLine("InfoProcessor 构造函数执行了");
}
public void ReadInfo(string info)
{
Console.WriteLine($"主要业务逻辑,接收到一条信息或请求:{info}");
}
}
装饰器模式实现:
public class InfoProcessorDecorator : IInfoProcessor
{
private IInfoProcessor _infoProcessor { get; set; }
public InfoProcessorDecorator(IInfoProcessor infoProcessor)
{
this._infoProcessor = infoProcessor;
}
public void ReadInfo(string info)
{
this.BeforeProceed(info);
this._infoProcessor.ReadInfo(info);
this.AfterProceed(info);
}
private void BeforeProceed(string info)
{
Console.WriteLine("方法执行前");
}
private void AfterProceed(string info)
{
Console.WriteLine("方法执行后");
}
}
上端调用:
public static void Execute()
{
IInfoProcessor processor = new InfoProcessor();
processor = new InfoProcessorDecorator(processor);
processor.ReadInfo("哈哈哈");
}
动态AOP
采用Castle库实现。 AOP有很多方法可以实现,Castle的一个库,用来做动态AOP 。
抽象类与实现类:
public interface IInfoProcessor
{
void ReadInfo(string info);
}
public class InfoProcessor : IInfoProcessor
{
public InfoProcessor()
{
Console.WriteLine("InfoProcessor 构造函数执行了");
}
[Log]
[Monitor]
public virtual void ReadInfo(string info)
{
Console.WriteLine($"主要业务逻辑,接收到一条信息或请求:{info}");
}
[Monitor]
public virtual void UpdateInfo(string info)
{
}
}
特性类中实现切面逻辑:
public abstract class AbstractAttributeBase : Attribute
{
public abstract void Execute();
}
public class LogAttribute : AbstractAttributeBase
{
public override void Execute()
{
Console.WriteLine("Log 切面逻辑");
}
}
public class MonitorAttribute : AbstractAttributeBase
{
public override void Execute()
{
Console.WriteLine("Monitor 切面逻辑");
}
}
继承接口,实现动态代理,并且将切面转移到特性中去(目前特性只实现了在业务逻辑之前加切面,如果要实现分别在业务逻辑的前后加逻辑,需要在特性中定义Before和After属性来实现;执行顺序可以增加Order属性来实现)
public class MyInterceptor :StandardInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.MethodInvocationTarget.IsDefined(typeof(AbstractAttributeBase), true))
{
foreach (var attr in invocation.MethodInvocationTarget.GetCustomAttributes(typeof(AbstractAttributeBase), true))
{
var log = attr as AbstractAttributeBase;
log.Execute();
}
}
invocation.Proceed();
}
public void PreProceed(IInvocation invocation)
{
Console.WriteLine("方法执行前");
}
public void PostProceed(IInvocation invocation)
{
Console.WriteLine("方法执行后");
}
}
上端调用:
public static void Execute()
{
ProxyGenerator generator = new ProxyGenerator();
MyInterceptor interceptor = new MyInterceptor();
InfoProcessor userprocessor = generator.CreateClassProxy<InfoProcessor>(interceptor);
userprocessor.ReadInfo("哈哈哈");
}
动态AOP与IOC整合
手动实现IOC,并在对象创建时整合动态的AOP功能
public class MyConstructorAttribute : Attribute
{
}
public class MyParameterAttribute : Attribute
{
public MyParameterAttribute(string shortName = null)
{
this.ShortName = shortName;
}
public string ShortName { get; set; }
}
public interface IMyIoc
{
void Register<From, To>(string shortName = null);
From Resolve<From>(string shortName = null);
}
public class MyIoc : IMyIoc
{
Dictionary<string, Type> _containerDic = new Dictionary<string, Type>();
private string GenerateKey(string abstractName, string shortName) => $"{abstractName}_@$_{shortName}";
public void Register<AFrom, BTo>(string shortName = null)
{
string key = typeof(AFrom).FullName;
key = GenerateKey(key, shortName);
if (!_containerDic.ContainsKey(key))
{
this._containerDic.Add(key, typeof(BTo));
}
}
public AFrom Resolve<AFrom>(string shortName = null)
{
return (AFrom)ResolveObject(typeof(AFrom), shortName);
}
private object ResolveObject(Type abstractType, string shortName = null)
{
string key = abstractType.FullName;
key = GenerateKey(key, shortName);
if (!_containerDic.ContainsKey(key)) return null;
Type type = this._containerDic[key];
ConstructorInfo constructorInfo =
type.GetConstructors().FirstOrDefault(c => c.IsDefined(typeof(MyConstructorAttribute), true));
if (constructorInfo == null)
constructorInfo = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First();
List<object> paramList = new List<object>();
foreach (var param in constructorInfo.GetParameters())
{
string paramShortName = "";
if (param.IsDefined(typeof(MyParameterAttribute), true))
{
paramShortName = ((MyParameterAttribute)param.GetCustomAttribute(typeof(MyParameterAttribute))).ShortName;
}
Type paramType = param.ParameterType;
object paramInstance = this.ResolveObject(paramType, paramShortName);
paramList.Add(paramInstance);
}
object instance = Activator.CreateInstance(type, paramList.ToArray());
foreach (var item in type.GetProperties())
{
}
ProxyGenerator generator = new ProxyGenerator();
MyInterceptor interceptor = new MyInterceptor();
instance = generator.CreateInterfaceProxyWithTarget(abstractType, instance, interceptor);
return instance;
}
}
上端调用:
static void Main(string[] args)
{
IMyIoc myIoc = new MyIoc();
myIoc.Register<IInfoProcessor, InfoProcessor>();
IInfoProcessor infoProcessor = myIoc.Resolve<IInfoProcessor>();
infoProcessor.ReadInfo("Hello AOP");
}
Prism.Unity中的AOP
Unity支持三方方式的AOP实现
- Interface(主流)—适用于BLL业务逻辑层的类,包括接口和实现类
- VirsualMethod—适用于ViewModel类
- MarshalByRefObject(单继承,很少用)
需要引用的库:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.19" targetFramework="net48" />
<package id="Prism.Core" version="8.0.0.1909" targetFramework="net48" />
<package id="Prism.Unity" version="8.0.0.1909" targetFramework="net48" />
<package id="Prism.Wpf" version="8.0.0.1909" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net48" />
<package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net48" />
<package id="Unity.Abstractions" version="5.11.6" targetFramework="net48" />
<package id="Unity.Configuration" version="5.11.2" targetFramework="net48" />
<package id="Unity.Container" version="5.11.8" targetFramework="net48" />
<package id="Unity.Interception" version="5.11.1" targetFramework="net48" />
<package id="Unity.Interception.Configuration" version="5.11.1" targetFramework="net48" />
</packages>
定义特性和切面
public class LogHander : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("LogHander方法执行前");
IMethodReturn methodReturn = getNext().Invoke(input, getNext);
Console.WriteLine("LogHander方法执行后");
return methodReturn;
}
}
public class MonitorHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("MonitorHandler方法执行前");
IMethodReturn methodReturn = getNext().Invoke(input, getNext);
Console.WriteLine("MonitorHandler方法执行后");
return methodReturn;
}
}
public class LogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHander { Order = this.Order };
}
}
public class MonitorHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new MonitorHandler { Order = this.Order };
}
}
实现的业务逻辑:
public interface IMenuBll
{
[LogHandlerAttribute(Order = 2)]
[MonitorHandler(Order = 1)]
void GetMenus();
}
public class MenuBll : IMenuBll
{
public void GetMenus()
{
Console.WriteLine("获取了系统菜单=============");
}
}
1、代码配置AOP
protected override Window CreateShell()
{
IUnityContainer unityContainer = Container.Resolve<IUnityContainer>();
unityContainer.AddNewExtension<Interception>().RegisterType<IMenuBll, MenuBll>();
unityContainer.Configure<Interception>().SetInterceptorFor<IMenuBll>(new InterfaceInterceptor());
unityContainer.Resolve<IMenuBll>().GetMenus();
return Container.Resolve<MainWindow>();
}
2、配置文件配置AOP
Unity.config配置文件
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="aopContainer">
<extension type="Interception"/>
<register type="My.PrismLesson.Project.BLL.IMenuBll,My.PrismLesson.Project" mapTo="My.PrismLesson.Project.BLL.MenuBll,My.PrismLesson.Project">
<interceptor type="InterfaceInterceptor"/>
<interceptionBehavior type="My.PrismLesson.Project.Behavior.LogBeforeBehavior, My.PrismLesson.Project"/>
</register>
<register type="My.PrismLesson.Project.ViewModels.LoginWindowViewModel,My.PrismLesson.Project">
<interceptor type="VirtualMethodInterceptor"/>
<interceptionBehavior type="My.PrismLesson.Project.Behavior.LogBeforeBehavior, My.PrismLesson.Project"/>
</register>
</container>
</containers>
</unity>
</configuration>
需要配置interceptionBehavior节点
public class LogBeforeBehavior : IInterceptionBehavior
{
public bool WillExecute => true;
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
MethodInfo methodInfo = input.Target.GetType().GetMethod(input.MethodBase.Name);
Console.WriteLine("LogBeforeBehavior方法执行前");
IMethodReturn methodReturn = getNext().Invoke(input, getNext);
Console.WriteLine("LogBeforeBehavior方法执行后");
return methodReturn;
}
}
protected override Window CreateShell()
{
IUnityContainer unityContainer = Container.Resolve<IUnityContainer>();
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "UnityConfig\\Unity.Config");
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
configSection.Configure(unityContainer, "aopContainer");
unityContainer.Resolve<IMenuBll>().GetMenus();
return Container.Resolve<MainWindow>();
}
3、ViewModel层实现AOP
以上的例子都是针对BLL(业务逻辑层)实现的AOP,只要ViewModel是通过IOC容器来实例化的,那么同样可以对ViewModel来实现AOP的功能。
ViewModel中要加切面的业务逻辑函数要为虚方法(virtual)
public class LoginWindowViewModel
{
public LoginWindowViewModel(Prism.Regions.IRegionManager region)
{
}
private DelegateCommand<Window> _loginCommand;
public DelegateCommand<Window> LoginCommand
{
get
{
if (_loginCommand == null)
_loginCommand = new DelegateCommand<Window>((w) =>
{
DoLogin();
});
return _loginCommand;
}
set { _loginCommand = value; }
}
public virtual void DoLogin()
{
Console.WriteLine("执行登录逻辑");
}
}
1)、配置文件配置AOP
Unity.config配置文件,配置interceptor为VirtualMethodInterceptor,采用虚方法注入,所以ViewModel中要加切面的业务逻辑函数要为虚方法(virtual)。
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="aopContainer">
<extension type="Interception"/>
<register type="My.PrismLesson.Project.ViewModels.LoginWindowViewModel,My.PrismLesson.Project">
<interceptor type="VirtualMethodInterceptor"/>
<interceptionBehavior type="My.PrismLesson.Project.Behavior.LogBeforeBehavior, My.PrismLesson.Project"/>
</register>
</container>
</containers>
</unity>
</configuration>
2)、代码配置AOP
protected override Window CreateShell()
{
IUnityContainer unityContainer = Container.Resolve<IUnityContainer>();
unityContainer.RegisterType<LoginWindowViewModel>(new Interceptor<VirtualMethodInterceptor>(),new InterceptionBehavior<LogBeforeBehavior>());
return Container.Resolve<MainWindow>();
}
|