Шрифт:
4. Прежде чем продолжить обсуждение кода сервера, необходимо остановиться на понятии контекста. Это важнейшее понятие данной главы. Именно механизм контекстов обеспечивает некоторый уровень реализации парадигмы аспектно-ориентированного программирования в рамках .NET. Смысл понятия контекста будет разъясняться последовательно в процессе разбора кода рассматриваемого здесь примера и обсуждения результатов экспериментов с этим кодом. Здесь обсудим связь между контекстом и доменом приложения.
5. Все объекты, живущие в некотором домене приложения, разбиваются на непересекающиеся группы. Грубо говоря, в одну группу попадают объекты, имеющие сходные запросы на использование сервисов. Все объекты одной группы живут в одном контексте, а объекты из разных групп живут в разных контекстах.
6. В каждом домене приложения имеется контекст по умолчанию, в который попадают все объекты, классы которых не являются производными от класса ContextBoundObject. Таким классам нельзя приписать какой-либо пользовательский атрибут. Точнее, экземпляры таких классов не могут воспользоваться связанными с этими атрибутами сервисами. Напротив, экземпляры классов, производных от класса ContextBoundObject, привязаны к конкретным контекстам (кроме контекста по умолчанию) и могут пользоваться связанными с такими контекстами сервисами.
7. Однако у объектов, живущих в контексте по умолчанию, имеется одно большое преимущество. Это преимущество состоит в том, что в любом контексте данного домена приложения можно использовать прямую ссылку на объект, живущий в контексте по умолчанию. Если же вызывается объект из какого-либо другого контекста и этот вызов пересекает границу контекста, то вызывающая сторона использует прокси для вызываемого объекта, сам вызов преобразуется в прокси в сообщение, которое уже в вызываемом контексте вновь преобразуется в вызов, который и исполняется.
8. Очевидно, что описанный здесь механизм приводит к значительным накладным расходам. Однако именно при использовании такого сложного механизма появляется возможность перехвата сообщений, кодирующих вызовы объектов, привязанных к контекстам. После перехвата вызова можно выполнить некоторый сервис. Аналогичную процедуру можно выполнять, перехватывая результаты, возвращаемые вызывающей стороне.
9. Теперь продолжим обсуждение кода сервера.
10. Класс Tах (как и класс Account) привязан к контексту (он наследует классу ContextBoundObject). Это дает возможность экземплярам данного класса использовать сервисы синхронизации и трассировки вызовов (последнее верно только для вызовов, приходящих извне данного контекста). Именно для этого классу Tах приписаны атрибуты синхронизации и трассировки вызовов.
Дополнительные комментарии, касающиеся класса Tах:
? В конструкторе класса Tах активируется новый экземпляр класса News, ссылка на который запоминается в поле _news. Для доступа к этой ссылке предусмотрено публичное свойство news (только для чтения),
? При выполнении конструктора класса Tах на консоль сервера выводится информация об идентификаторе контекста, в котором будет жить новый объект, хеш текущего потока и его тип (поток из пула потоков или нет). Эти данные будут использованы при проведении экспериментов,
? Метод Notify класса Tах выводит на консоль полученное уведомление и в свою очередь отсылает полученное уведомление экземпляру класса News. Здесь же на консоль выводится хеш текущего потока и его тип.
11. Определение класса News во многом похоже на определение класса Tах. Достаточно только отметить, что этот класс является последним в цепочке рассылки уведомлений, что приводит к упрощению кода.
12. Класс AccountApp содержит функцию Main и определяет консольное серверное приложение. Этот класс не претерпел никаких изменений по сравнению с соответствующим классом, описанным в предыдущей главе.
Атрибут трассировки вызовов
Прежде чем привести код этого атрибута, вернемся к понятию контекста. Контекст формируется только тогда, когда это необходимо, т. е. тогда, когда появляется первый объект, который будет жить в этом контексте.
Необходимость создания нового контекста определяется в результате сопоставления требований к сервисам со стороны нового объекта, и наличных сервисов, доступных в старом контексте (в контексте, из которого был сделан запрос на формирование нового объекта). Если старый контекст удовлетворяет требованиям нового объекта, то этот новый объект размещается в старом контексте и получает возможность использовать связанные с ним сервисы. В противном случае создается новый контекст, с которым связывается некоторый набор сервисов, запрашиваемых новым объектом.