1. 程式人生 > >dubbo-php-framework的客戶端api解析(一)

dubbo-php-framework的客戶端api解析(一)

從這篇,我們開始分析客戶端的側的流程,所謂客戶端就是指dubbo-php-frame框架中consumer端,我們結合demo來看看consumer的呼叫流程,下面程式碼路徑為dubbo-php-framework-master/demo/demo-consumer/server/Consumer.php

<?php
$APP_SRC_PATH = __DIR__;
$fsofApiPath = dirname(dirname(dirname($APP_SRC_PATH))).DIRECTORY_SEPARATOR.'api'.DIRECTORY_SEPARATOR.'FSOFApi.php';
require_once($fsofApiPath);//載入api檔案,檔案路徑為dubbo-php-framework-master/api/FSOFApi.php
FSOFApi::configure('demo-consumer', $APP_SRC_PATH);//FSOFApi的初始化,傳入的引數為app名字和consumer端目錄

require_once('log4php/Logger.php');
Logger::configure(dirname(dirname(__FILE__)).'/config/log4php.xml');
date_default_timezone_set('PRC');

//php框架呼叫php提供的服務
$service = 'com.fenqile.example.DemoService';
$proxy = FSOFApi::newProxy($service, 3);
$ret = $proxy->invoke("sayHello","zhangsan");
echo "ret:$ret".PHP_EOL;

從這個程式碼可以看出,核心呼叫邏輯是在FSOFApi::newProxy和proxy的invoke中完成的,我們就從FSOFApi類開始解析。

class FSOFApi
{
	private static $__FSOF_CONSUMER_APP_NAME__ = NULL;
	private static $__FSOF_CONSUMER_APP_SRC_PATH__ = NULL;

    /**
     * 設定Consumer執行上下文環境,在使用fsof_consumer時,該函式要最先呼叫
     * @param $appName consumer app的名字
     * @param $appSrcPath consumer app src原始碼的絕對路徑
     */
	public static function configure($appName, $appSrcPath)
	{
		self::$__FSOF_CONSUMER_APP_NAME__ = $appName;
		self::$__FSOF_CONSUMER_APP_SRC_PATH__ = $appSrcPath;
	}

    /**
     *
     *    獲取指定provider服務的proxy物件
     * @param $service  service配置檔案中的key 例:com.alibaba.test.TestService      必選
     * @param int $ioTimeout 連線超時時間和接收資料超時時間 單位 s;支援小數0.5 500ms
     * @return \com\fenqile\fsof\consumer\proxy\Proxy|null
     */
	public static function newProxy($service ,$ioTimeout = 3)
	{
		$s = NULL;
		if(empty(self::$__FSOF_CONSUMER_APP_NAME__) || empty(self::$__FSOF_CONSUMER_APP_SRC_PATH__))//判斷引數有效性
		{
            \Logger::getLogger(__CLASS__)->error("appName or appSrcPath not set,please use FSOFApi::configure() for set.");
            return null;
		}
		else
		{
			if(!is_numeric($ioTimeout) || $ioTimeout <= 0) //判斷超時時間設定,在分散式呼叫中,超時時間必須得有,防止介面超時引起的雪崩
			{
				$ioTimeout = 3;
			}

            $consumerFile = dirname(__DIR__).DIRECTORY_SEPARATOR.'consumer'.DIRECTORY_SEPARATOR.'FSOFConsumer.php';
            //載入FSOFConsumer
            require_once($consumerFile);
            $app_setting = array('app_name' => self::$__FSOF_CONSUMER_APP_NAME__, 'app_src' => self::$__FSOF_CONSUMER_APP_SRC_PATH__);
            FSOFConsumer::init($app_setting);//初始化Consumer框架資訊,細節後續分析
            $s = ProxyFactory::getInstance($service, $ioTimeout);//獲取Proxy例項資訊,細節後續分析
		}
		return $s;
	}
}

我們接著分析FSOFConsumer的init過程,這裡主要是完成了consumer端對於一些必須庫和檔案的載入,consumer端也有自己的配置,這裡也有配置檔案的解析。

​
class FSOFConsumer
{
    /**
     * @var  boolean  Has [FSOFConsumer::init] been called?
     */
    protected static $_init = FALSE;

    protected static $_initSetting;
    
    public static function init(array $settings = NULL)
    {
        if (self::isConsumerInit())
        {
            // Do not allow execution twice
            return;
        }
        \Logger::getLogger(__CLASS__)->info("consumer cfg:".json_encode($settings, true));

        $consumerRoot = __DIR__;
		$fsofBootPath = dirname($consumerRoot);

        //載入commom
        $fsofCommonPath = $fsofBootPath.DIRECTORY_SEPARATOR.'common';
        require_once($fsofCommonPath.DIRECTORY_SEPARATOR.'BootStrap.php');

        //載入registry
        $fsofRegistryPath = $fsofBootPath.DIRECTORY_SEPARATOR.'registry';
        require_once($fsofRegistryPath.DIRECTORY_SEPARATOR.'BootStrap.php');

        //檢查輸入引數app_src
        if ((!isset($settings['app_src'])) || (!isset($settings['app_name'])))
		{
            throw new \Exception("FSOFConsumer::init傳入的app的src路徑引數不準確");
        }        
        $consumerConfigFile = $settings['app_src'];
        $consumerConfigFile = rtrim($consumerConfigFile, DIRECTORY_SEPARATOR);
        $consumerConfigFile = $consumerConfigFile.DIRECTORY_SEPARATOR.'consumer'.DIRECTORY_SEPARATOR.$settings['app_name'].'.consumer';
        if (file_exists($consumerConfigFile))
        {
        	try 
        	{
                $consumerConfig = parse_ini_file($consumerConfigFile, true);     
            } 
            catch (\Exception $e) 
            {
                throw new \Exception("consumer配置檔案有誤[".$consumerConfigFile."]");
            }
        }
		else
		{
			$consumerConfig = array();
		}

		self::$_initSetting = $settings;

        //註冊consumer框架的autoLoader
        self::registerConsumerFrameAutoLoader($consumerRoot);

        //註冊consumer的動態代理工廠
        ProxyFactory::setConsumerConfig($consumerConfig, $consumerConfigFile, $settings);

        // FSOFConsumer is now initialized
		self::$_init = TRUE;
    }

    private static function registerConsumerFrameAutoLoader($consumerRoot)
    {
        if (!self::isConsumerInit())
        {
            //註冊框架頂層名稱空間到自動載入器
            require_once $consumerRoot.DIRECTORY_SEPARATOR.'FrameAutoLoader.php';
            FrameAutoLoader::setRootNS('com\fenqile\fsof\consumer', $consumerRoot);
            FrameAutoLoader::setRootNS('com\fenqile\fsof\consumer\app', $consumerRoot.DIRECTORY_SEPARATOR.'app');
            FrameAutoLoader::setRootNS('com\fenqile\fsof\consumer\fsof', $consumerRoot.DIRECTORY_SEPARATOR.'fsof');
            FrameAutoLoader::setRootNS('com\fenqile\fsof\consumer\proxy', $consumerRoot.DIRECTORY_SEPARATOR.'proxy');
            FrameAutoLoader::setRootNS('com\fenqile\fsof\consumer\client', $consumerRoot.DIRECTORY_SEPARATOR.'client');
            spl_autoload_register(__NAMESPACE__.'\FrameAutoLoader::autoload');
        }
    }

    public static function getInitSetting()
    {
        return  self::$_initSetting;
    }
    
    public static function isConsumerInit()
    {
        return  self::$_init;
    }

}

​