Hibernate 4.0 新特性之 Service(Registry)
已經遷移到 Hibernate Core 4.0 的用戶(非JPA)可能已經注意到,以前大家熟知的構造 SessionFactory 的方法已經不推薦使用了:
Configuration configuration = new Configuration(); SessionFactory sf = configuration.buildSessionFactory();
在 Hibernate ORM 4 里面推薦的方式是 org.hibernate.cfg.Configuration#buildSessionFactory(ServiceRegistry serviceRegistry), 需要先構造一個 ServiceRegistry 對象。
那么, 神馬是 ServiceRegistry?
顧名思義, ServiceRegistry 是 Service 的注冊表, 它為Service提供了一個統一的加載 / 初始化 / 存放 / 獲取機制.
首先來看看一個整體的類圖:
整個 ServiceRegistry 結構和我們大家了解的 Classloader 的代理結構類似, 只不過和 Classloader 的首先代理給父節點,父節點找不到再從本級的 Classloader 中查找的策略不同,ServiceRegistry 是先從本級節點查找,找不到再去父親中查找。
可以看到hibernate里面的 ServiceRegistry實際上是由三層(范圍)組成的:
- BootstrapServiceRegistry
主要提供 Classloading 和 Service loading 服務, 供全局使用.
- ServiceRegistry
標準的ServiceRegistry, 同樣服務于全局, 在初始化這個Registry中的服務的時候,可能需要使用到BootstrapServiceRegistry中的服務.
- SessionFactoryServiceRegistry
于SessionFactory相關聯(一對一的關系), 這里面的Services在初始化的時候需要訪問SessionFactory.
所以, BootstrapServiceRegistry 中主要包括全局都要使用的基礎服務, 而 ServiceRegistry 主要包括在 BootstrapServiceRegistry 之上的, 和Hibernate 相關的服務, 例如配置文件解析, JDBC, JNDI 等.
而, SessionFactoryServiceRegistry 則是和sessionfactory相關的了, 包括2LC的region factory, event listener等.
這里面的層級關系, 對于 service registry的client來說是完全透明的, 你可以直接調用getService 去獲取你需要的service, 而不用去關心你在哪個層級上, 如同 classloader.
Service
那么,什么是 Service ? 簡單的來說,Service 就是一個功能,它由一個接口(Service Role)和一個實現類組成.
Service 在Hibernate里面并不是一個新的概念,在以前的版本里面,我們已經有了這些東西,而這次,是通過把這些服務的提供者(類),給抽取成一個個的Service,從而可以用統一的方式進行訪問/加載/初始化等.
下圖列出了所有的Hibernate中內置的Services, 詳細介紹請參考:
Building ServiceRegistry
在本文的開頭即說過, 現在標準的構造一個SessionFactory的做法是傳遞一個ServiceRegistry實例給Configuration#buildSessionFactory方法, 那么, 這里就需要我們首先創建一個 ServiceRegistry的實例.
最簡單的做法是:
StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder(); ServiceRegistry serviceRegistry = serviceRegistryBuilder.build(); SessionFactory sf = configuration.buildSessionFactory(serviceRegistry);
讓我們來繼續分析這里面究竟發生了什么.
如上文所介紹的, ServiceRegistry是一個代理結構, 那么, 實際上是需要分別創建 BootstrapServiceRegistry, ServiceRegistry 和 SessionFactoryServiceRegistry.
BootstrapServiceRegistry
org.hibernate.service.ServiceRegistryBuilder 有兩個構造函數, 一個是接受一個 BootstrapServiceRegistry實例作為參數, 另外一個是無參的, 在內部自己構造一個 org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl的實例.
如同上面所講的, 事實上我們是先build了一個 BootstrapServiceRegistry 的.
而Hibernate也如你所愿的提供了 org.hibernate.boot.registry.BootstrapServiceRegistryBuilder.
通過這個builder類, 我們可以通過調用如下的方法來對一些基礎服務進行擴展:
- with(Integrator integrator)
- with(ClassLoader classLoader)
- withStrategySelector
(關于這里的擴展的詳細解釋敬請期待下一篇)
現在我們有了 BootstrapServiceRegistryBuilder 和 ServiceRegistryBuilder , 那么很自然的, 會想到是不是也有一個 SessionFactoryServiceRegistryBuilder 呢?
很遺憾, 沒有!
是的, 不過我們提供了 org.hibernate.service.spi.SessionFactoryServiceRegistryFactory, 它是一個位于 ServiceRegistry 中的標準service.
這主要是因為它的全部工作就是創建一個沒啥意思的 org.hibernate.service.internal.SessionFactoryServiceRegistryImpl 實例, 也沒啥可擴展的地方, 所以自然也就不需要一個builder了.
那么, 如果你非得要替換到這個默認的實現, 或者, 更進一步, 例如你想要替換掉某一個Service的標準實現, 異或, 你想把自己寫的service也添加到service registry當中呢?
更進一步來看看Service
首先, BootstrapServiceRegistry中所提供的service是固定的, 無法增減, 除非你提供一個自己的 org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl 實現類, 但是并不推薦.
從org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl#locateServiceBinding 方法中我們可以看到BootStrapServiceRegistry所提供的標準服務.
publicServiceBinding locateServiceBinding(Class serviceRole) { if ( ClassLoaderService.class.equals( serviceRole ) ) { return (ServiceBinding ) classLoaderServiceBinding; } else if ( StrategySelector.class.equals( serviceRole) ) { return (ServiceBinding ) strategySelectorBinding; } else if ( IntegratorService.class.equals( serviceRole ) ) { return (ServiceBinding ) integratorServiceBinding; } return null; }
推薦的擴展位置是 ServiceRegistry, 在這里, 你可以增加你自定義的service, 替換標準的service實現等等.
ServiceRegistry 中所提供的標準服務是定義在 org.hibernate.service.StandardServiceInitiators 當中:
public class StandardServiceInitiators { public static ListLIST = buildStandardServiceInitiatorList(); private static List buildStandardServiceInitiatorList() { final List serviceInitiators = new ArrayList (); serviceInitiators.add( ConfigurationServiceInitiator.INSTANCE ); serviceInitiators.add( ImportSqlCommandExtractorInitiator.INSTANCE ); serviceInitiators.add( JndiServiceInitiator.INSTANCE ); serviceInitiators.add( JmxServiceInitiator.INSTANCE ); serviceInitiators.add( PersisterClassResolverInitiator.INSTANCE ); serviceInitiators.add( PersisterFactoryInitiator.INSTANCE ); serviceInitiators.add( ConnectionProviderInitiator.INSTANCE ); serviceInitiators.add( MultiTenantConnectionProviderInitiator.INSTANCE ); serviceInitiators.add( DialectResolverInitiator.INSTANCE ); serviceInitiators.add( DialectFactoryInitiator.INSTANCE ); serviceInitiators.add( BatchBuilderInitiator.INSTANCE ); serviceInitiators.add( JdbcEnvironmentInitiator.INSTANCE ); serviceInitiators.add( JdbcServicesInitiator.INSTANCE ); serviceInitiators.add( RefCursorSupportInitiator.INSTANCE ); serviceInitiators.add( SchemaManagementToolInitiator.INSTANCE ); serviceInitiators.add( MutableIdentifierGeneratorFactoryInitiator.INSTANCE); serviceInitiators.add( JtaPlatformInitiator.INSTANCE ); serviceInitiators.add( TransactionFactoryInitiator.INSTANCE ); serviceInitiators.add( SessionFactoryServiceRegistryFactoryInitiator.INSTANCE ); return Collections.unmodifiableList( serviceInitiators ); } }
可以看到, 每一個標準服務都被封裝成了 StandardServiceInitiator, 那么什么是 ServiceInitiator 呢?
ServiceInitiator
org.hibernate.service.spi.ServiceInitiator
定義了一個 Service 的加載器, 這個接口里面只有一個方法
/** * Obtains the service role initiated by this initiator. Should be unique within a registry * * @return The service role. */ public ClassgetServiceInitiated();
而org.hibernate.service.StandardServiceInitiator 繼承了 org.hibernate.service.spi.ServiceInitiator 并提供了另外一個方法:
/** * Initiates the managed service. * * @param configurationValues The configuration values in effect * @param registry The service registry. Can be used to locate services needed to fulfill initiation. * * @return The initiated service. */ public R initiateService(Map configurationValues, ServiceRegistryImplementor registry);
認同下圖所示, ServiceInitiator定義了一個Service的接口 以及如何初始化這個service.
所以, 當有了ServiceInitiator之后, 可以通過調用org.hibernate.boot.registry.StandardServiceRegistryBuilder 的方法添加到注冊表中:
- addInitiator(StandardServiceInitiator initiator)
- addService(final Class serviceRole, final Service service)
hibernate在初始化這些service的時候, 會先初始化內置的, 所以, 如果你想要替換以后的標準service的話, 只需要原樣調用上面兩個方法之一就行了.
Hibernate 還提供了一些接口來供Service的創建者來使用(具體如何使用請參考javadoc,在此就不重復了):
- org.hibernate.service.spi.Configurable
- org.hibernate.service.spi.Manageable
- org.hibernate.service.spi.ServiceRegistryAwareService
- org.hibernate.service.spi.InjectService
- org.hibernate.service.spi.Startable
- org.hibernate.service.spi.Stoppable
- org.hibernate.service.spi.Wrapped
至此, 已經把ServiceRegistry中的大部分內容介紹完了, 希望大家對此有個感性的認識. 在以后的blog中, 我會按照從bootstrap, standard, sessionfactory的順序把各個service registry中提供的標準服務一一解釋, 我會盡量的從代碼級別來解釋為什么這樣設計, 和如何使用.
原文出處:http://in.relation.to/Bloggers/HibernateORMServiceRegistry