基本上是如下的代码块就可以确认Cat的客户端的逻辑了:
一、Cat.newTransaction() 时,
1、将调用DefaultMessageProducer的newTransaction(String type, String name)方法。
I、初次调用时,将会调用DefaultMessageManager类中的setup()方法,目的是初始化Context ctx;类。ctx = new Context("Unknown", m_hostName, "");ctx = new Context(m_domain.getId(), m_hostName, m_domain.getIp());
II、Context类中包含 MessageTree m_tree; Stack<Transaction> m_stack; 属性,首次初始化该类,便是初始化对应的m_tree = new DefaultMessageTree(); m_tree.setDomain(domain); 等。以及初始化m_stack.m_stack = new Stack<Transaction>();
III、MessageTree类的数据结构,包含了对应的:private Message m_message; 以及一些其他的private String m_messageId;等等属性。
IIII、此时我们初始化了对应的Context ctx后,便将并将当前的ctx类,放入到当前DefaultMessageManager的ThreadLocal属性中。m_context.set(ctx); private ThreadLocal<DefaultMessageManager.Context> m_context = new ThreadLocal<Context>()
OK,此时我们首次初始化的环节基本做完了。
2、setup()方法执行完成后,则 new 对应的Transaction(),DefaultTransaction transaction = new DefaultTransaction(type, name, m_manager);
new DefaultTransaction()时,则传递了对应的DefaultMessageManager给到Transaction中。
DefaultTransaction类的主要属性是:private List<Message> m_children; private MessageManager m_manager;等
3、执行m_manager.start(transaction, false); 执行 m_manage.start()方法时,会执行ctx.start()方法,执行ctx.start()方法时的具体逻辑为,
判断该context中的m_stack是否为空,为空则表示当前是首次添加Transaction到context中,则此时将context中的m_tree.setMessage(transaction);
并将改context中的m_stack.push(transaction); 也就是将Transaction添加到Context的message属性中,且添加到对应的m_stack中。
II、那么当第二次newTransaction并执行start()方法时,由于此时m_stack已经不在为空,所以此时只需要将transaction添加到m_stack中即可。而不再赋值message属性为当前的transaction。
只有首次添加的Transaction到context中时,才会添加到context的message属性中。
除了将对应的Transaction添加到堆栈外,还会判断该if (!(transaction instanceof ForkedTransaction)) transaction 是否 instanceof ForkedTransaction,如果是,则将该Transaction也添加到对应上一个Transaction的child当中。
这块逻辑debug后可知:当你实例化第二个Transaction时,也就是DefaultTransaction时,此时instanceof ForkedTransaction是为true的。也就是所有的Transaction最终都会添加到父的Transaction的child当中。最终第一个Transaction的child就是一堆大的子集。
此时DefaultMessageProducer中new Transaction()并实例化完成,则此时return出来即可。
二、当我们执行Cat.logEvent()时。
1、调用DefaultMessageProducer的logEvent()方法。主要做两件事,1、Event event = newEvent(type, name); 2、event.addData(nameValuePairs);event.setStatus(status); event.complete(); 主要是执行complete()
I、判断m_manager.hasContext()是否初始过,未初始化则执行:m_manager.hasContext。已经初始化过则不在初始化Context。
II、DefaultEvent event = new DefaultEvent(type, name, m_manager);
实例化完对应的DefaultEvent后,则执行event.complete()方法。
2、event.complete()。主要对应代码是执行:m_manager.add(this);
也就是将该DefaultEvent自身,添加到对应的m_manage.add()当中。
I、查看该m_manage.add()的代码,此处代码主要的操作是,Transaction parent = m_stack.peek(); 从当前context的m_stack属性中,peek()查看堆栈顶部的对象,但不从堆栈中移除它。
II、得到当前堆栈顶部的Transaction对象后,则将该Event添加到该Transaction的m_children属性当中。private List<Message> m_children;
此时Event便是成为了当前该Transaction的一个m_children的子集。
三、那么当我们调用Transaction的compleate()方法时,主要执行的操作是什么呢?
1、执行Transaction.compleate()方法时,主要操作是,Transaction current = m_stack.pop(); 从当前context的stack堆栈中移除顶部这个Transaction并做一些check操作。
2、如果该Transaction.compleate()时,该Transaction本身就是堆栈的最后一个栈帧,则此时表示当前该线程ThreadLocal的Context中的MessageTree m_tree;中的Message(Transaction)
已经是在执行最终的Transaction的complete()提交了。
也就是该Context任务也就是完成了。也可以说是该线程本批次的整个的Context都已经完成了。此时则需要进行提交即可了。
将该Context中的MessageTree m_tree属性,执行一下copy。MessageTree tree = m_tree.copy(); 然后, manager.flush(tree, true);
manage.flush()主要逻辑是:MessageSender sender = m_transportManager.getSender(); 然后 sender.send(tree); 。也就是通过TCPSocketSend将该MessageTree发送出去即可。
发送完成后,则一系列操作完成,此时m_context.remove(); 也就是清除当前该DefaultMessageManager中private ThreadLocal<DefaultMessageManager.Context> m_context = new ThreadLocal<Context>()
m_context所对应的context的引用关系。此时一整个链路算是上传完成。
简单总结一下对应的操作则是:
Context中包含了MessageTree 和 Stack<Transaction>
MessageTree中的属性message主要对应的是初始的第一个Transaction。Transaction中包含了List<Message> m_children。
在对应的Transaction中的Cat.logevent等操作。全部都会记录到对应的Transaction下的m_children属性中。
而如果是实例化了多个Transaction,则多个Transaction都是在对应的Context中的Stack中存储的,Event和Transaction的关联是通过从Stack中取最上层的堆栈中Transaction来进行的绑定。
当一个Transaction执行完成调用complete后,则会移除该Transaction在Stack中的位置。
当该Transaction移出后,Stack中为空了,表示当前是Stack中的最后一个Transaction,则此时表明当前整个线程对应的执行是完毕了。则此时提交该MessageTree,flush 刷新并发送到远端。主要是发送该MessageTree下的message(Transaction)。
flush后,则ThreadLocal<Context> m_context = new ThreadLocal<Context>(); m_context.remove() ,清除对应的context的引用。