Castle Windsor zamiast Spring
Poprzednia wersja NGinn została zbudowana w oparciu o kontener Spring. I to było dobre, Spring jest naprawdę świetnym narzędziem z doskonałą dokumentacją, przykładami oraz funkcjonalnością. Ale okazało się że wiele komponentów które wykorzystuję w NGinn bazuje na innym kontenerze – Castle Windsor. Ponieważ używanie dwóch różnych kontenerów w jednym projekcie to trochę kiepski pomysł, postanowiłem przejść na Castle Windsor. Pierwsze próby były trudne, bo Windsor jest o wiele słabiej udokumentowany niż Spring a poza tym ma ewidentnie skromniejsze możliwości jeśli chodzi o konfigurację komponentów. Ale ma też dobre cechy – jest bardzo ‘lekki’ i nadaje się dobrze do konfiguracji programistycznej (Spring głównie poprzez XML). W dodatku jest dla niego rozszerzenie o nazwie Binsor, pozwalające konfigurować komponenty w oparciu o język Boo (Binsor jest przykładem DSL, czyli Domain Specific Language, zbudowanego w oparciu o Boo). Boo jest także wykorzystywany jako podstawowy język skryptowania procesów w NGinn – zatem decyzja mogła być tylko jedna: wchodzę w to. I na razie nie żałuję, choć pojawiło sie kilka trudności na horyzoncie – przede wszystkim brak możliwości wystawienia komponentów z kontenera poprzez .Net remoting tak jakbym chciał. Ale myślę że da się to łatwo przeskoczyć.
A co na horyzoncie: wykorzystanie prawdziwego ESB do przekazywania komunikatów w NGinn – flirtuję z projektem Rhino Service Bus. To on właśnie wymaga Castle Windsora. A poniżej można zobaczyć jak wygląda konfiguracja NGinn w Boo:
import System.IO
import Castle.Facilities.FactorySupport from Castle.MicroKernel
import Castle.Facilities.Startable from Castle.MicroKernel
import Rhino.ServiceBus.Impl from Rhino.ServiceBus
import NGinnBPM.Lib.Interfaces
import NGinnBPM.Lib.Interfaces.MessageBus
import NGinnBPM.Services
import NGinnBPM.Lib.Services
import NGinnBPM.Dao
import System.Collections.Generic
cfg = Kernel.Resolve(NGinnBPM.Lib.Util.DefaultConfigProvider)
baseDir = cfg.ResolveVariable("ng.configdir")
endp = cfg.ResolveVariable("NGinn.MessageQueue")
connstr = cfg.ResolveVariable("NGinn.ConnectionString")
Facility FactorySupportFacility
Facility StartableFacility
Facility ("remoting", Castle.Facilities.Remoting.RemotingFacility, {
@isServer: true,
@registryUri: "nginn.kernel.rem",
@remotingConfigurationFile: "NGinnBPM.Engine.WindsorHost.exe.config"
})
Facility("rhino.esb", RhinoServiceBusFacility, {
bus: {
@endpoint: endp,
@threadCount: 1
},
messages: {
add: {@name: "NGinnBPM.Runtime.Events", @endpoint: endp}
}
})
Component("TaskInstanceFactory", ITaskInstanceFactory, TaskInstanceFactory)
Component("TaskDefinitionFactory", ITaskDefinitionFactory, TaskDefinitionFactory)
Component("ProcessScriptManager", IProcessScriptManager, NGinnBPM.Services.Scripting.BooScript.BooProcessScriptManager, LifestyleType.Singleton,
BaseDirectory: "${baseDir}\\temp\\BooProcessScriptManager")
Component("TaskInstanceRepository", ITaskInstanceRepository, RawSqlTaskInstanceRepository, LifestyleType.Singleton,
ConnectionString: connstr)
Component("MessageBus", IMessageBus, NGinnBPM.Services.MessageBus.SqlMessageHub, LifestyleType.Singleton,
Endpoint: "sql://nginn/MQueue", ConnectionStrings: {"nginn": connstr})
Component("PackageRepository", IProcessPackageRepository, NGinnBPM.Services.FSProcessPackageRepository, LifestyleType.Singleton,
BaseDirectory: "${baseDir}\\PackageRepository")
Component("MessageCorrelationResolver", IMessageCorrelationIdResolver, NGinnBPM.Dao.RawSqlMessageCorrelationIdResolver, LifestyleType.Singleton,
ConnectionString: connstr)
Component("LockManager", IProcessInstanceLockManager, LocalProcessInstanceLockManager, LifestyleType.Singleton)
Component("Environment", INGEnvironment, NGinnBPM.Runtime.NGEnvironment, LifestyleType.Singleton)
Component("NGEngine", NGinnBPM.Runtime.NGEngine)
Konfigurując nasze komponenty w pliku konfiguracyjnym, czy jest to XML czy Boo, zyskujemy ważną rzecz – nie wprowadzamy zależności w kodzie, nawet gdy komponenty pochodzą z jakichś zewnętrznych assembly. Czyli nie musimy już mieć w kodzie miejsca które odwołuje się do wszystkich wykorzystywanych bibliotek, takie miejsce jest tylko w konfiguracji. I nie myślmy za dużo o tym że Boo to też kod, tylko w innym języku.
2 Responses “Castle Windsor zamiast Spring”
Castle Windsora używa także NHibernate, który jest częścią składową NGinna
Mimo wszystko proponowałbym przyjrzeć się nieco projektowi StructureMap
No tak, a ja naiwnie myślałem że Castle Windsor kończy temat, przynajmniej na razie