Я пересматривал то, что я сделал, чтобы заставить StructureMap работать с UoW на Http и UoW на задание кварца, и я решил поделиться своим решением здесь.
Итак, идея заключалась в том, что я хотел использовать гибридную область StructureMap, чтобы получить экземпляр UoW при наличии контекста http, а также получить другой экземпляр UoW для каждого потока, когда нет контекста http (например, когда срабатывает задание кварца). Нравится:
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
UoW для http работал нормально. Проблема заключалась в UoW на поток.
Вот что происходит. Когда запускается задание quratz, оно вытягивает поток из пула потоков и начинает выполнение задания, используя этот поток. Когда работа начинается, я запрашиваю UoW. StructureMap ищет под локальным хранилищем этот поток, чтобы вернуть UoW, но поскольку он не может его найти, он создает экземпляр и сохраняет его в локальном хранилище потока. Я получаю UoW, затем выполняю Begin, Commit, Dispose, и все в порядке.
Проблема возникает, когда поток извлекается из пула потоков, который ранее использовался для запуска задания (и использовал UoW). Здесь, когда вы запрашиваете UoW, StructureMap просматривает кеш (локальное хранилище потока), находит UoW и возвращает его вам. Но проблема в том, что UoW утилизирован!
Таким образом, мы не можем использовать UoW для каждого потока для кварцевых заданий, потому что сами потоки не удаляются и содержат старые кэшированные удаленные UoW. В основном жизненный цикл потока не соответствует жизненному циклу кварцевого задания. Вот почему я создал свой собственный жизненный цикл для кварцевого задания.
Сначала я создал свой собственный гибридный класс жизненного цикла http-quartz:
public class HybridHttpQuartzLifecycle : HttpLifecycleBase<HttpContextLifecycle, QuartzLifecycle>
{
public override string Scope { get { return "HybridHttpQuartzLifecycle"; } }
}
Затем я создал свой класс QuartzLifecyle:
public class QuartzLifecycle : ILifecycle
{
public void EjectAll()
{
FindCache().DisposeAndClear();
}
public IObjectCache FindCache()
{
return QuartzContext.Cache;
}
public string Scope { get { return "QuartzLifecycle"; } }
}
Затем мне нужно создать некоторый контекстный класс, например HttpContext для Quartz, для хранения информации, связанной с контекстом. Итак, я создал класс QuartzContext. Когда запускается кварцевое задание, JobExecutionContext для этого задания должен быть зарегистрирован в QuartzContext. Затем фактический кеш (MainObjectCache) для экземпляров StructureMap будет создан под этим конкретным JobExecutionContext. Таким образом, после завершения выполнения задания кеш также исчезнет, и у нас не будет проблем с удалением UoW в кеше.
Кроме того, поскольку _jobExecutionContext является ThreadStatic, когда мы когда-либо запрашиваем кеш из QuartzContext, он будет возвращать кеш из JobExecutionContext, который сохраняется для того же потока. Поэтому, когда несколько заданий выполняются одновременно, их JobExecutionContexts сохраняются отдельно, и у нас будут отдельные кеши для каждого выполняемого задания.
public class QuartzContext
{
private static readonly string _cacheKey = "STRUCTUREMAP-INSTANCES";
[ThreadStatic]
private static JobExecutionContext _jobExecutionContext;
protected static void Register(JobExecutionContext jobExecutionContext)
{
_jobExecutionContext = jobExecutionContext;
_jobExecutionContext.Put(_cacheKey, new MainObjectCache());
}
public static IObjectCache Cache
{
get
{
return (IObjectCache)_jobExecutionContext.Get(_cacheKey);
}
}
}
У меня есть абстрактный класс BaseJobSingleSession, от которого происходят другие задания. Этот класс расширяет класс QuartzContext. Вы можете видеть, что я регистрирую JobExecutionContext, когда задание запускается.
abstract class BaseJobSingleSession : QuartzContext, IStatefulJob
{
public override void Execute(JobExecutionContext context)
{
Register(context);
IUnitOfWork unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
try
{
unitOfWork.Begin();
// do stuff ....
unitOfWork.Commit();
}
catch (Exception exception)
{
unitOfWork.RollBack();
}
finally
{
unitOfWork.Dispose();
}
}
}
Наконец, я определил жизненный цикл UoW:
For<IUnitOfWork>().LifecycleIs(new HybridHttpQuartzLifecycle()).Use<UnitOfWork>();
(Для жизненного цикла и классов контекста я изучил исходный код StructureMap, чтобы понять идею.)
Поделитесь своими идеями, комментариями и предложениями:>
person
kaptan
schedule
12.07.2011