AOP的底层已经封装好了以后,我们就要开始针对应用层写具体的业务逻辑了。
也就是说我们需要有个类继承于AopPRoxyBase,并且重写其After,Bofore以达到我们的拦截记录的功能。代码如下:
public class TransactionProxy : AopProxyBase { public TransactionProxy(MarshalByRefObject obj, Type type) : base(obj, type) { } public override void Before(System.Runtime.Remoting.Messaging.IMessage requestMsg, AopMethodAttribute[] attrs) { } public override void After(System.Runtime.Remoting.Messaging.IMessage requestMsg, System.Runtime.Remoting.Messaging.IMessage Respond, AopMethodAttribute[] attrs) { foreach (var attr in attrs) { if (attr is LogicRollBackTransAttribute) { return; } } var args = requestMsg.Properties["__Args"] as object[]; string methodName = requestMsg.Properties["__MethodName"] as string; CustomTransaction customTrans = null; List<object> list = new List<object>(); customTrans = CallContext.GetData(TransKey.CustomTransKey) as CustomTransaction; if (customTrans != null) { list.AddRange(args); TransactionUnit unit = APPTransactionManage.Instance.GetRollBackInfo(methodName); if (unit != null) { unit.Argments = list; unit.Mark = customTrans.Mark; } customTrans.Compensation.Add(unit); TransQueueManage.Instance.Push ( new Model.BankTransLog { Mark = unit.Mark, MethodName = methodName, ParamsConfig = JsonHelper.ToJson(unit.Argments), Status = 0, Type = 0 } ); CallContext.SetData(TransKey.CustomTransKey, customTrans); var outArgs = Respond.Properties["__OutArgs"] as object[]; IDbTransaction dbTrans; foreach (var attr in attrs) { if (attr is DbTransAttribute || attr is LogicTransAttribute) { if (outArgs != null) { foreach (var arg in outArgs) { if (arg is IDbTransaction) { dbTrans = arg as IDbTransaction; if (customTrans != null) { customTrans.AddDbTransaction(dbTrans); } } } } } } } } }View Code
在After的地方,我们可以看到,我们做了一次LogicRollBackTransAttribute的判定,避免在回调的时候,又再走一次拦截和记录的流程。
同时做了DbTransAttribute和LogicTransAttribute的判定。因为我把事务分为两类,一类是db本身自己控制的,可以直接rollback的,一类是logic的,需要我们去手动通过逻辑回滚的。代码如下:
[AttributeUsage(AttributeTargets.Method)] public class LogicTransAttribute : AopMethodAttribute { public string MethodName { get; set; } public LogicTransAttribute() { } public LogicTransAttribute(string name) { this.MethodName = name; } }[AttributeUsage(AttributeTargets.Method)] public class DbTransAttribute : AopMethodAttribute { }View Code
同时可以看到,我把每一个函数的调用作为一个单元,用TransactionUnit类来保存,代码如下:
public class TransactionUnit { public object InstanceObject; /// <summary> /// 执行的方法 /// </summary> public MethodInfo Forward; /// <summary> /// 失败回滚的方法 /// </summary> public MethodInfo Rollback; /// <summary> /// 参数 /// </summary> public IList<object> Argments; /// <summary> /// 唯一标识 /// </summary> public string Mark; }View Code
因为,一个事务里面,可能包含了多次操作redis,或者多次操作db,为了保证线程安全,同时又需要避开锁,我用了CallContext将一个线程里面的一段事务,保存在其线程上下文中。在保存一个完整的TransactionUnit的时候,不可能每一次都去通过反射去取MethodInfo,所以又增加了一段初始化和字典来保存其MethodInfo。代码如下:
public class AppTransactionManage { private Dictionary<string, TransactionUnit> _transMaps; static AppTransactionManage() { } private AppTransactionManage() { if (this._transMaps == null) { this._transMaps = new Dictionary<string, TransactionUnit>(); } } private static AppTransactionManage _instance; public static AppTransactionManage Instance { get { if (_instance == null) { _instance = new AppTransactionManage(); } return _instance; } } public TransactionUnit GetRollBackInfo(string methodName) { if (this._transMaps == null) throw new ArgumentNullException("not init"); if (this._transMaps.ContainsKey(methodName)) { return this._transMaps[methodName]; } return null; } public void Init(params string[] assembly) { this.Init(2, assembly); } public void Init(int threadNum, params string[] assembly) { if (assembly != null) { foreach (string s in assembly) { var ass = Assembly.Load(s); if (ass != null) { var types = ass.GetTypes(); foreach (var type in types) { var transAttr = type.GetCustomAttribute(typeof(TransactionAttribute), false) as TransactionAttribute; if (transAttr != null) { var methods = type.GetMethods(); foreach (var method in methods) { var forwardTrans = method.GetCustomAttribute(typeof(LogicTransAttribute), false) as LogicTransAttribute; var rollbackTrans = method.GetCustomAttribute(typeof(LogicRollBackTransAttribute), false) as LogicRollBackTransAttribute;
新闻热点
疑难解答