Castle实践5-NHibernate Facility

 大家好,最近项目正式发布挺忙的,所以这篇东西是拖得挺久的啦。好了,废话不多说,进入正题吧。 13.gif

NHibernate Facility包括有两个项目:
1)Castle.Facilities.NHibernateExtension
        这里有主要有两个Attribute和一个Session管理器。
        SessionFlushAttribute:用于方法指定session的flush方式

[SessionFlush(FlushOption.Auto)]
public   virtual  Person CreatePerson( string  name)
{ dot.gifdot.gif }

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

[UsesAutomaticSessionCreation( " nhibernate.factory " )]
public   class  PersonDao
{ dot.gifdot.gif }

        SessionManager:会话管理器,这是一个PerThread class(LocalDataStoreSlot),用一个堆栈来保存当前会话,在下面介绍的AutomaticSessionInterceptor中会用到这个管理器。

static  Stack CurStack
{
    [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配置

None.gif <? xml version="1.0" encoding="utf-8"  ?>
None.gif
< configuration >
None.gif    
< facilities >
None.gif        
< facility  id ="nhibernate" >
None.gif            
<!--  数据库一  -->
None.gif            
< factory  id ="nhibernate.factory.1" >
None.gif                
< settings >
None.gif                    
< item  key ="hibernate.connection.provider" > NHibernate.Connection.DriverConnectionProvider </ item >
None.gif                    
< item  key ="hibernate.connection.driver_class" > NHibernate.Driver.SqlClientDriver </ item >
None.gif                    
< item  key ="hibernate.connection.connection_string" > Server=localhost;Database=Test;Uid=sa;Pwd=123 </ item >
None.gif                    
< item  key ="hibernate.dialect" > NHibernate.Dialect.MsSql2000Dialect </ item >
None.gif                
</ settings >
None.gif                
< resources >
None.gif                    
< resource  assembly ="Demo"  name ="Demo.Entities.Blog.hbm.xml"   />
None.gif                    
< resource  assembly ="Demo"  name ="Demo.Entities.BlogItem.hbm.xml"   />
None.gif                
</ resources >
None.gif            
</ factory >
None.gif            
<!--  数据库二  -->
None.gif            
< factory  id ="nhibernate.factory.2" >
None.gif                
< settings >
None.gif                    
< item  key ="hibernate.connection.provider" > NHibernate.Connection.DriverConnectionProvider </ item >
None.gif                    
< item  key ="hibernate.connection.driver_class" > NHibernate.Driver.SqlClientDriver </ item >
None.gif                    
< item  key ="hibernate.connection.connection_string" > Server=localhost;Database=Test2;Uid=sa;Pwd=123 </ item >
None.gif                    
< item  key ="hibernate.dialect" > NHibernate.Dialect.MsSql2000Dialect </ item >
None.gif                
</ settings >
None.gif                
< resources >
None.gif                    
< resource  assembly ="Demo"  name ="Demo.Entities.Order.hbm.xml"   />
None.gif                
</ resources >
None.gif            
</ factory >
None.gif        
</ facility >
None.gif    
</ facilities >
None.gif
</ configuration >

第二步:建立好NHibernate的映射和持久类文件。这里和普通使用nhb没什么不同的地方。
第三步:在DAO中使用上面介绍的UsesAutomaticSessionCreationAttribute:

[UsesAutomaticSessionCreation( " nhibernate.factory.1 " )]
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;
    }
}

第四步:容器初始化

IWindsorContainer container  =   new  WindsorContainer( " ../../CastleConfig.xml " );
container.AddFacility(
" transaction " new  TransactionFacility());
container.AddFacility(
" nhibernate " new  NHibernateFacility());
container.AddComponent(
" blog.dao " typeof (BlogDao));

第五步:使用

BlogDao dao  =  (BlogDao)container[ " blog.dao " ];
dao.CreateBlog(
string .Format( " test-{0} " new  Random().Next()));

使用过程中,CreateBlog会自动根据指定的session factory新建factory,并调用factory生产session来执行任务,最后根据指定的flush模式来flush。
如果你要使用自动事务,可以这样:

[Transactional]
[UsesAutomaticSessionCreation(
" nhibernate.factory.1 " )]
public   class  BlogDao
{
dot.gifdot.gif
    [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;
    }
dot.gifdot.gif
}

事务管理也是自动的,会自动根据是否发生异常来Commit或者Rollback。
这样使用之后,你完全不用写一句OpenSession()或者BeginTrans()又或者是Commit()等等,因为这都被容器自动化管理了。而且可以很方便的使用多个数据库连接,只需要改变一下UsesAutomaticSessionCreationAttribute中的factory id就可以了。Cool吗?05.gif


【原理篇】

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,这下明白了吧 13.gif。当然ISessionFactory的请求是Facility本身做的事,不用你管,要是你想直接用ISessionFactory,那也可以直接向容器索取,同样的你只需要知道一个ID。

//  声明一个服务接口为ISessionFactory的ComponentModel
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执行初始化动作,片断如下:
//  获取session factory配置
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拦截器分析:
//  获取当前的方法使用的数据库的标识id
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);
}

好了,分析就到此为止吧。是不是有点混乱 noidea.gif。因为这个Facility和其他好几个Facility结合一起用,关系比较复杂啦。建议大家如果想了解原理的话,还是结合我的分析自己跟踪一下源码的处理吧。 45.gif



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

转载于:https://www.cnblogs.com/laiwen/archive/2005/09/07/231643.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值