大家好,最近项目正式发布挺忙的,所以这篇东西是拖得挺久的啦。好了,废话不多说,进入正题吧。
NHibernate Facility包括有两个项目:
1)Castle.Facilities.NHibernateExtension
这里有主要有两个Attribute和一个Session管理器。
SessionFlushAttribute:用于方法指定session的flush方式
public virtual Person CreatePerson(string name)
{


UsesAutomaticSessionCreationAttribute:用于类指定使用的session自动管理器使用哪个session factory(配置文件中指定)。
public class PersonDao
{


SessionManager:会话管理器,这是一个PerThread class(LocalDataStoreSlot),用一个堆栈来保存当前会话,在下面介绍的AutomaticSessionInterceptor中会用到这个管理器。
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
// _slot是一个“内存槽”,这个槽是用来装一个Stack的,
//这样做用来确保每个线程在_slot只共享一个Stack,他用来
//储存Session
Stack stack = (Stack) Thread.GetData(_slot);
if (stack == null)
{
stack = new Stack();
Thread.SetData(_slot, stack);
}
return stack;
}
}
2)Castle.Facilities.NHibernateIntegration
NHibernate Facility的核心在这里,这里用到了前面介绍的Castle.Services.Transaction(实践3)和Castle.Facilities.AutomaticTransactionManagement(实践4)。首先,先不说原理,我们来看一下怎么使用。
【使用篇】
第一步:NHibernate Facility配置
































第二步:建立好NHibernate的映射和持久类文件。这里和普通使用nhb没什么不同的地方。
第三步:在DAO中使用上面介绍的UsesAutomaticSessionCreationAttribute:
public class BlogDao
{
public BlogDao() {}
[SessionFlush(FlushOption.Auto)]
public virtual Blog CreateBlog( String name )
{
ISession session = SessionManager.CurrentSession;
Blog blog = new Blog();
blog.Name = name;
blog.Items = new ArrayList();
session.Save(blog);
return blog;
}
}
第四步:容器初始化
container.AddFacility("transaction", new TransactionFacility());
container.AddFacility("nhibernate", new NHibernateFacility());
container.AddComponent("blog.dao", typeof(BlogDao));
第五步:使用
dao.CreateBlog(string.Format("test-{0}", new Random().Next()));
使用过程中,CreateBlog会自动根据指定的session factory新建factory,并调用factory生产session来执行任务,最后根据指定的flush模式来flush。
如果你要使用自动事务,可以这样:
[UsesAutomaticSessionCreation("nhibernate.factory.1")]
public class BlogDao
{


[Transaction(TransactionMode.Requires)]
[SessionFlush(FlushOption.Auto)]
public virtual Blog CreateBlog( String name )
{
ISession session = SessionManager.CurrentSession;
Blog blog = new Blog();
blog.Name = name;
blog.Items = new ArrayList();
session.Save(blog);
return blog;
}


}
事务管理也是自动的,会自动根据是否发生异常来Commit或者Rollback。
这样使用之后,你完全不用写一句OpenSession()或者BeginTrans()又或者是Commit()等等,因为这都被容器自动化管理了。而且可以很方便的使用多个数据库连接,只需要改变一下UsesAutomaticSessionCreationAttribute中的factory id就可以了。Cool吗?
【原理篇】
1、SessionKeeper : Castle.Services.Transaction.ISynchronization
事务的同步化对象,这里用于关闭相应的ISession。
2、ResourceSessionAdapter : Castle.Services.Transaction.IResource
这里Castle.Services.Transaction.ITransaction包装了一个NHibernate.ITransaction作为资源,他是一个“对象适配器”,把NHibernate.ITransaction适配为Castle.Services.Transaction.IResource,用于NHibernate.ITransaction提交和回滚。
上面两个对象都是Castle.Services.Transaction(实践3有详细介绍)里面的,NHibernate Facility用他们协助管理、同步事务。在拦截器AutomaticSessionInterceptor中,如果方法体声明了事务特性,他们将被使用到。
3、SessionFactoryActivator : Castle.MicroKernel.ComponentActivator.AbstractComponentActivator
NHibernate Facility在配置ISessionFactory的时候,根据xml配置文件初始化一个NHibernate.Cfg.Configuration,并把这个Configuration作为ISessionFactory组件的一个ExtendedProperties,当请求ISessionFactory的时候,Activator会把ExtendedProperties里面的Configuration取出来,并调用BuildSessionFactory来生产出一个ISessionFactory。这样就可以根据不同的ID(配置时候指定)来请求不同的ISessionFactory了,上面说使用多数据库的时候就是改变一下id,这下明白了吧

ComponentModel model = new ComponentModel(id, typeof(ISessionFactory), null);
// 把配置对象作为组件的扩张属性
model.ExtendedProperties.Add(ConfiguredObject, cfg );
// 组件生存方式为单例
model.LifestyleType = LifestyleType.Singleton;
// 指定Activator
model.CustomComponentActivator = typeof( SessionFactoryActivator );
// 加入到容器
Kernel.AddCustomComponent( model );
4、NHibernateTransactionManager : Castle.Services.Transaction.DefaultTransactionManager
这是一个事务管理器,在TransactionInterceptor中用管理器创建Castle.Services.Transaction.ITransaction并加入管理器,在AutomaticSessionInterceptor 中检测到有事务打开,则执行上面提到的1、2点包装一个NHibernate.ITransaction,并开始事务。
5、TransactionInterceptor 与 AutomaticSessionInterceptor
这两个拦截器是NHibernate Facility的核心,下面详细分析。
我们从注册一个NHibernate Facility开始,看他是如何实现这种自动化管理的。
注册Facility的时候,我们不但向容器注册了NHibernate Facility,而且也注册了Transaction Facility。当使用了Transactional和UsesAutomaticSessionCreation特性,这两个facility会同时发生作用。
NHibernate Facility执行初始化动作,片断如下:
IConfiguration factoriesConfig = FacilityConfig.Children["factory"];
if (factoriesConfig == null)
{
throw new ConfigurationException(
"You need to configure at least one factory to use the NHibernateFacility");
}
// 加入一个组件初始化处理流,所有声明了UsesAutomaticSessionCreationAttribute的都植入拦截器
Kernel.ComponentModelBuilder.AddContributor( new AutomaticSessionInspector() );
// 上面植入的拦截器
Kernel.AddComponent( "nhibernate.session.interceptor", typeof(AutomaticSessionInterceptor) );
// 加入事务管理器
Kernel.AddComponent( "nhibernate.transaction.manager", typeof(ITransactionManager), typeof(NHibernateTransactionManager) );
foreach(IConfiguration factoryConfig in FacilityConfig.Children)
{
if (!"factory".Equals(factoryConfig.Name))
{
throw new ConfigurationException("Unexpected node " + factoryConfig.Name);
}
// 配置session factory,配置过程请看上面第三点
ConfigureFactories(factoryConfig);
}
TransactionFacility会在所有使用了事务特性的方法上面植入拦截器,上面提到的NHibernateTransactionManager 就是在这里发挥作用的。拦截器片断如下:
ITransaction transaction = _manager.CreateTransaction( transactionAtt.TransactionMode, transactionAtt.IsolationMode );
if (transaction == null)
{
return invocation.Proceed(args);
}
object value = null;
// 开始事务
transaction.Begin();
try
{
// 执行方法体处理,这里会被AutomaticSessionInterceptor拦截
value = invocation.Proceed(args);
// 正常则提交事务
transaction.Commit();
}
catch(Exception ex)
{
// 发生异常回滚事务
transaction.Rollback();
throw ex;
}
finally
{
// 释放事务资源
_manager.Dispose(transaction);
}
AutomaticSessionInterceptor拦截器分析:
String key = ObtainSessionFactoryKeyFor(invocation.InvocationTarget);
// 根据标识id判断当前处理是否和session管理器的当前活动数据库相同
if (SessionManager.IsCurrentSessionCompatible(key))
{
// 执行处理
return invocation.Proceed(args);
}
// 获取session factory,上面讲的SessionFactoryActivator会发挥作用
ISessionFactory sessionFactory = ObtainSessionFactoryFor(key);
// 打开一个session
ISession session = sessionFactory.OpenSession();
// 把session和key标识加入管理器
SessionManager.Push(session, key);
// 获取session的flush模式
FlushOption flushOption = ExtractFlushOption(invocation.MethodInvocationTarget);
ConfigureFlushMode(flushOption, session);
// 当前是否有活动事务,如果有则开始事务
if (EnlistSessionIfHasTransactionActive(key, session))
{
try
{
// 执行处理
return invocation.Proceed(args);
}
finally
{
// 从管理器从移除sesion
SessionManager.Pop(key);
}
}
try
{
// 不带事务的处理
return invocation.Proceed(args);
}
finally
{
// flush
if (flushOption == FlushOption.Force)
{
session.Flush();
}
// 关闭session
session.Close();
// 移除sesion
SessionManager.Pop(key);
}
好了,分析就到此为止吧。是不是有点混乱


因为是实践性的东西,我希望多以代码的方式剖析给大家看。哪里讲得不对的,希望大家多提宝贵意见,下次实践我们再见咯~~3q~~

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构