AspectTrack模块简介
AspectTrack模块主要是根据AOP思想架构的一个面向切面的程序代码追踪模块,它可以跟踪每一个方法的调用,在调用前阻断该方法,亦或是更改其传入的实参,更改其返回值等!可以用于调用日志打印,系统运行监控等需求!
使用AspectTrack
自定义切面代理
要使用AspectTrack,首先必须新建自定义的切面代理,切面代理必须满足以下条件:
1.继承至 AspectProxy
2.扩展接口 IAspectTrackObject
介于过程较繁琐,推荐使用快捷创建方式:
Project界面右键 -> Create -> HTFramework -> AspectProxy Script
如下图,我自定义了一个名为PlayerAttackProxy的切面代理,IPlayerAttackProxy接口为其代理的所有方法:
public class PlayerAttackProxy<T> : AspectProxy<T> where T : IPlayerAttackProxy
{
public PlayerAttackProxy(T realObject) : base(realObject) { }
public override object[] BeforeInvoke(MethodBase method, object[] args)
{
GlobalTools.LogInfo("进入方法:" + method.Name);
return args;
}
public override void AfterInvoke(MethodBase method, object returnValue)
{
GlobalTools.LogInfo("离开方法:" + method.Name);
}
}
public interface IPlayerAttackProxy : IAspectTrackObject
{
void Attack(int power);
void Hit(int hurt);
}
实现切面代理
我们新建一个类Player,使其实现IPlayerAttackProxy接口:
public class Player : MonoBehaviour, IPlayerAttackProxy
{
int code;
private void Awake()
{
code = GetHashCode();
}
public void Attack(int power)
{
GlobalTools.LogInfo(code + " 攻击:[攻击力 " + power + "]");
}
public void Hit(int hurt)
{
GlobalTools.LogInfo(code + " 被击:[伤害 " + hurt + "]");
}
public void Track()
{
GlobalTools.LogInfo(" 追踪目标:" + GetType().Name + " " + code);
}
private void Start()
{
Attack(100);
Hit(50);
Track();
}
}
常规调用
然后我们在编辑器中挂载Player脚本,运行!结果如我们所料:
切面代理调用
接下来我们想要对Player的Attack方法和Hit方法进行追踪,当然这也是我们一开始的初衷,修改Player类的Start方法:
private void Start()
{
//创建切面代理
PlayerAttackProxy<IPlayerAttackProxy> proxy = new PlayerAttackProxy<IPlayerAttackProxy>(this);
//创建追踪者
IPlayerAttackProxy proxyObj = Main.m_AspectTrack.CreateTracker(proxy);
proxyObj.Attack(100);
proxyObj.Hit(50);
proxyObj.Track();
}
然后我们在编辑器中挂载Player脚本,运行!结果如我们所料:
如你所见,Player中的Attack方法和Hit方法,每次调用都将会被PlayerAttackProxy捕获到,BeforeInvoke将于方法正式调用前被呼叫,AfterInvoke将于方法正式调用后被呼叫。
修改方法实参
想要修改方法调用时传入的实参,只需修改BeforeInvoke传入的参数并传出便可:
public override object[] BeforeInvoke(MethodBase method, object[] args)
{
GlobalTools.LogInfo("进入方法:" + method.Name);
//将所有int数据放大到10000
for (int i = 0; i < args.Length; i++)
{
if (args[i] is int)
{
args[i] = 10000;
}
}
return args;
}
运行!
获取方法返回值
方法的返回值可以从AfterInvoke中获取:
public override void AfterInvoke(MethodBase method, object returnValue)
{
GlobalTools.LogInfo("离开方法:" + method.Name);
GlobalTools.LogInfo("方法:" + method.Name + " 返回值 " + (returnValue == null ? "null" : returnValue.ToString()));
}
运行!
拦截方法调用
PlayerAttackProxy的InterceptCall字段决定了方法是否被拦截,不过需要注意的是,这里只能拦截void返回值的方法,如若方法有非空返回值,那么拦截了它的调用之后,将不太好处理之后引发的一系列麻烦:
private void Start()
{
//创建切面代理
PlayerAttackProxy<IPlayerAttackProxy> proxy = new PlayerAttackProxy<IPlayerAttackProxy>(this);
IPlayerAttackProxy proxyObj = Main.m_AspectTrack.CreateTracker(proxy);
//拦截所有void返回值方法的调用
proxy.InterceptCall = true;
proxyObj.Attack(100);
proxyObj.Hit(50);
proxyObj.Track();
}
运行!
启用与禁用切面代理模块
AspectTrack将可以很方便的调试某些复杂模块,或者完成某些重复性高的统一功能,这将取决于你如何使用它,不过,使用它的代价并不低,如果想要在正式发布的项目中去掉整个切面代理的功能,不需要改动任何代码,只需要一句话关闭它就可以了!
Main.m_AspectTrack.IsEnableAspectTrack = false;