大家平時都在用這個服務框架。簡單閱讀了下代碼,了解其原理可以方便解決一些常見hsf的問題。限於篇幅,整個分析將分幾個系列發布。第一篇將簡單介紹Hsf的啟動和各組件之間關系。
一. Hsf總體架構

這個圖很經典,想必大家都了解,Consumer,Provider,中間通過ConfigServer聯接。那么其內部是如何實現的呢?請看下文。
二. 容器啟動,jboss為例
HSF使用基於equinox(OSGi框架的eclipse實現,http://www.eclipse.org/equinox/)的OSGi,啟動流程

1. /opt/xxxx/jboss/server/default/conf/xmdesc/org.jboss.deployment.MainDeployer-xmbean.xml指定sar優先加載:
- 050:.deployer,050:-deployer.xml,100:.aop,100:-aop.xml,150:.sar,150:-service.xml,200:.beans,250:.rar,300:-ds.xml,350:.har,400:.jar,400:.ejb3,400:.par,500:.war,…
2. taobao-hsf.sar/META-INF/jboss-service.xml 指定初始化類:
- <server>
- <mbeancode="com.xxxx.hsf.thirdcontainer.jboss.HSFContainerDelegator"name="hsf:service=containerdelegator">
- </mbean>
- </server>
3. 設置Jboss的class loader給HSF,以便HSF訪問Jboss的類:
- HSFContainer.setThirdContainerClassLoader(jbossClassloader);
4. 啟動hsf容器
- HSFContainer.start(null);
4.1 尋找HSF的plugins
4.2 配置Equinox
- FrameworkProperties.setProperty("osgi.syspath", searchPath);
- …..
4.3 啟動 Equinox
- EclipseStarter.run(new String[] { "-configuration","hsf.configuration" }, null);
這里HSF使用了OSGi的Declarative Service(http://www.ibm.com/developerworks/cn/opensource/os-ecl-osgids/index.html)方式來啟動,典型配置如下:
OSGI下的配置文件
- <?xml version="1.0"encoding="UTF-8"?>
- <component name="ConfigurationComponent">
- <service>
- <provide
- interface="com.xxxx.hsf.configuration.service.ConfigurationService"/>
- </service>
- <implementation
- class="com.xxxx.hsf.configuration.component.ConfigurationComponent"/>
- </component>:
有點類似spring的DI,完成整個容器的啟動,這里hsf用到的service都會初始化完成,但是基本不干啥事。
4.4 OSGi容器初始化后,拿到OSGi上下文,讓jboss容器和OSGi容器可以相互訪問
- context = EclipseStarter.getSystemBundleContext();
5. 將hsf暴露的類注冊到jboss的classloader中,方便后續app中使用,典型的比如HSFSpringProviderBean和HSFSpringConsumerBean
- Map<String,Class<?>> exportedClasses = HSFContainer.getExportedClasses();
- for (String className : exportedClasses.keySet()) {
- jbossRepo.cacheLoadedClass(className, exportedClasses.get(className),jbossClassloader);
- }
三. Provider啟動
當APP啟動時,會用spring加載hsf的配置文件,典型provider如下:
- <beanclass="com.taobao.hsf.app.spring.util.HSFSpringProviderBean" init-method="init">
- <propertyname="serviceInterface">
- <value>com.xxxx.ump.core.service.PromotionReadService</value>
- </property>
- <propertyname="serviceName">
- <value>PromotionReadService</value>
- </property>
- <propertyname="target">
- <ref bean="promotionReadService"/>
- </property>
……
因為容器初始化時已經將HSF的類注冊到了jboss的classloader中,所以在spring中可以找到HSFSpringProviderBean類定義,開始provider的初始化。
Provider角度看,類圖如下:

ProcessService是核心控制流程類,掌管發布和消費的入口。從provider端來看,基本流程如下:
1.根據服務類型,注冊服務提供者,保證服務在本機的唯一性,關聯業務層和通訊層。在這里會做應用服務器的初始化,服務線程池分配(如果配置)。最終的TBRemotingRPCProtocolComponent.registerProvider代碼如下:
- // 僅啟動一次HSF SERVER
- …….
- providerServer.startHSFServer();
- ……
- // 注冊對象到HSFServer上
- providerServer.addMetadata(metadata.getUniqueName(), metadata);
- providerServer.addWorker(metadata.getUniqueName(),metadata.getTarget());
應用服務器初始化后,本地hsf端口12200打開,可以接受請求。在這一步,我們可以通過配置修改hsf的運行期參數,比如端口,業務線程數等。
2.通過Publisher將服務注冊到configServer上
四. Consumer啟動
當消費者啟動時,我們會這樣配置:
- <beanid="shopReadServiceImpl"class="com.xxxx.hsf.app.spring.util.HSFSpringConsumerBean" init-method="init">
- <property name="interfaceName">
- <value>com.xxxx.shopservice.core.client.ShopReadService</value>
- </property>
同樣通過jboss的classloader我們可以找到HSFSpringConsumerBean這個類定義,開始consumer的初始化。
從consumer角度看,類圖如下:

同樣通過ProcessService的consume方法生成一個調用的代理類。流程如下:
1. 使用jdk動態代理,生成調用遠程HSF服務的代理
- InvocationHandler handler = newHSFServiceProxy(metadata);
- Object proxyObj = Proxy.newProxyInstance(getClass().getClassLoader(), newClass[] { interfaceClass }, handler);
生成的代理類叫HSFServiceProxy,其invoke方法使用TBRemotingRPCProtocalComponent組件調用通訊層接口,發送請求。
2. 通過metadataService訂閱服務信息,包括:
a. 通過diamond訂閱服務路由規則和流量規則,路由規則即調用哪些機器,hsf可以限制consumer的調用機器范圍,流量規則即流控策略,hsf可以通過推送規則限流。
b. 通過configServer的client訂閱服務地址信息,這里可以拿到所有提供該service的機器地址,consumer根據之前獲得的路由規則和訪問策略(默認隨機)來決定請求哪台機器。
五. 小結
本文簡單分析了hsf容器的啟動,后續將分析具體的consume和provide過程