01.03 深入浅出:Swoole单例模式及依赖注入进行Redis底层类库封装


深入浅出:Swoole单例模式及依赖注入进行Redis底层类库封装

  • redis安装及php-redis扩展安装
  • 初步使用
  • 封装基类 – 单例模式
  • 优化封装 – 依赖注入
  • 从配置加载
  • 从自定义配置加载
    本文将一步一步的从redis的安装一直到easySwoole使用高度封装的底层类库,并进行优化提高代码的维护性,可以直接看最后的优化结果
  • 第一部分 redis安装及php-redis扩展安装

    redis的安装很简单,直接到redis官网下载,这里使用的是redis4.0.12,下载后直接make && make install即可,
    进入到redis的文件夹的src目录,运行一个redis服务,其默认端口是6379:

    <code>./redis-server/<code>

    运行一个redis客户端

    <code>./redis-cli/<code>

    安装php-redis也很简单,从github把扩展下载下来解压,然后

    <code>phpize
    ./configure
    make && make install/<code>

    即可,如果想要configure到指定的php版本就指定phpize的目录并在config的时候prefix到指定的php配置文件,安好之后再php.ini加上redis.so即可。

    第二部分 初步使用

    直接在源码中进行redis的连接:

    <code>/**
    * Created by bingxiong.
    * Date: 12/19/18
    * Time: 6:38 PM
    * Description:
    */

    namespace App\\HttpController\\Api;

    use \\EasySwoole\\Core\\Component\\Di;
    // 使用封装的redis基类
    use App\\Lib\\Redis\\Redis;

    class Index extends Base
    {
    public function getRedis(){
    $redis = new \\Redis();
    $redis->connect("127.0.0.1",6379, 5);
    $redis->set("bing",19249);
    return $this->writeJson(200,'OK',$redis->get("bing"));
    }

    }/<code>

    显然我们不可能这样使用,需要对其进行二次封装

    第三部分 创建Redis的基类

    基类创建在App->Lib->Redis->redis.php

    <code>
    /**
    * Created by bingxiong.
    * Date: 12/21/18
    * Time: 12:44 AM
    * Description:
    */

    namespace App\\Lib\\Redis;

    // 使用单例模式
    use EasySwoole\\Config;
    use EasySwoole\\Core\\AbstractInterface\\Singleton;

    class Redis
    {
    use Singleton;

    public $redis = "";

    private function __construct()
    {
    //判断扩展有没有安装
    if(!extension_loaded('redis')){
    throw new \\Exception("redis.so文件不存在");
    }
    try{
    $this->redis = new \\Redis();
    $result = $this->redis->connect("127.0.0.1",6379,3);
    } catch (\\Exception $e){
    throw new \\Exception("redis服务异常");
    }

    if($result === false){
    throw new \\Exception("redis连接失败");
    }
    }

    /**
    * 重写get友好的返回key不存在的情况
    * @param $key
    * @return bool|string
    */
    public function get($key){
    if(empty($key)){
    return '';
    }

    return $this->redis->get($key);
    }

    }/<code>

    说明:
    使用了单例模式:用于为一个类生成一个唯一的对象。最常用的地方是数据库连接。 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类。1、一个类只能有一个实例 2、它必须自行创建这个实例 3、它必须自行向整个系统提供这个实例
    有了基类之后,配置和连接的任务就从基类的构造函数加载了,之前的代码就变成了

    <code>/**
    * Created by bingxiong.
    * Date: 12/19/18
    * Time: 6:38 PM
    * Description:
    */

    namespace App\\HttpController\\Api;


    use \\EasySwoole\\Core\\Component\\Di;
    // 使用封装的redis基类
    use App\\Lib\\Redis\\Redis;

    class Index extends Base
    {
    public function getRedis(){
    $result = Redis::getInstance()->get('bing');

    return $this->writeJson(200,'OK',$result);
    }

    }/<code>

    第四部分 依赖注入

    依赖注入:一个对象提供另一个对象的依赖关系,是一种设计模式,好处就是有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
    easyswool使用依赖注入非常的简单,在easyswoolevent的文件中

    <code>public static function mainServerCreate(ServerManager $server,EventRegister $register): void
    {
    Di::getInstance()->set('MYSQL',\\MysqliDb::class,Array (
    'host' => '127.0.0.1',
    'username' => 'root',
    'password' => 'root',
    'db'=> 'imooc_video',
    'port' => 8889,
    'charset' => 'utf8')
    );
    Di::getInstance()->set('REDIS',Redis::getInstance());

    }/<code>

    上面的是我数据库的配置,下面getInstance中实例化了刚才封装的基类

    实例化di再getInstance就可以了

    <code>/**
    * Created by bingxiong.
    * Date: 12/19/18
    * Time: 6:38 PM
    * Description:

    */

    namespace App\\HttpController\\Api;


    use \\EasySwoole\\Core\\Component\\Di;
    // 使用封装的redis基类
    use App\\Lib\\Redis\\Redis;

    class Index extends Base
    {

    public function getRedis(){
    // 3使用依赖注入
    $result = Di::getInstance()->get('REDIS')->get('bing');
    return $this->writeJson(200,'OK',$result);
    }

    }/<code>

    第5部分 从配置加载

    在配置文件中添加,或者用你喜欢的方式配置

    <code>'REDIS' => [
    'host' => '127.0.0.1',
    'port' => 6379,
    'time_out' => 3
    ]/<code>

    然后基类改写成

    <code>/**
    * Created by bingxiong.
    * Date: 12/21/18
    * Time: 12:44 AM
    * Description:
    */

    namespace App\\Lib\\Redis;

    // 使用单例模式
    use EasySwoole\\Config;

    use EasySwoole\\Core\\AbstractInterface\\Singleton;

    class Redis
    {
    use Singleton;

    public $redis = "";

    private function __construct()
    {
    //判断扩展有没有安装
    if(!extension_loaded('redis')){
    throw new \\Exception("redis.so文件不存在");
    }
    try{
    //从配置加载REDIS - 提高维护性
    $redisConfig = Config::getInstance()->getConf("REDIS");
    $this->redis = new \\Redis();
    $result = $this->redis->connect($redisConfig['host'],$redisConfig['port'],$redisConfig['time_out']);
    } catch (\\Exception $e){
    throw new \\Exception("redis服务异常");
    }

    if($result === false){
    throw new \\Exception("redis连接失败");
    }
    }

    /**
    * 重写get友好的返回key不存在的情况
    * @param $key
    * @return bool|string
    */
    public function get($key){
    if(empty($key)){
    return '';
    }
    return $this->redis->get($key);
    }

    }/<code>

    第6部分 从自定义配置加载

    由于可能有很多配置,把配置都放在这个文件的话会显得很臃肿,因此我们将每个配置文件比如redis mysql elasticsearch的配置单独抽离出来单独管理,这样有更好的维护性

    所以在根目录创建config->redis.php,在这里直接返回redis的配置

    <code>/**
    * Created by bingxiong.
    * Date: 12/21/18
    * Time: 2:10 AM
    * Description: redis相关配置
    */

    return ['host' => '127.0.0.1', 'port' => 6379, 'time_out' => 3];/<code>

    然后自定义载入配置文件,创建了一个loadConf方法,这个方法在easyswoole的文档中有,所以最终的

    EasySwooleEvent.php

    <code>/**
    * Created by PhpStorm.
    * User: yf
    * Date: 2018/1/9
    * Time: 下午1:04
    */

    namespace EasySwoole;

    use App\\Lib\\Redis\\Redis;
    use \\EasySwoole\\Core\\AbstractInterface\\EventInterface;
    use EasySwoole\\Core\\Component\\Di;
    use \\EasySwoole\\Core\\Swoole\\ServerManager;
    use \\EasySwoole\\Core\\Swoole\\EventRegister;
    use \\EasySwoole\\Core\\Http\\Request;
    use \\EasySwoole\\Core\\Http\\Response;
    use \\EasySwoole\\Core\\Utility\\File;

    Class EasySwooleEvent implements EventInterface {

    public static function frameInitialize(): void
    {
    // TODO: Implement frameInitialize() method.
    date_default_timezone_set('Asia/Shanghai');
    self::loadConf(EASYSWOOLE_ROOT.'/Config');

    }

    public static function loadConf($ConfPath)
    {
    $Conf = Config::getInstance();
    $files = File::scanDir($ConfPath);
    foreach ($files as $file) {
    $data = require_once $file;
    $Conf->setConf(strtolower(basename($file, '.php')), (array)$data);
    }
    }

    /**
    * 使用依赖注入加载
    * @param ServerManager $server
    * @param EventRegister $register
    */
    public static function mainServerCreate(ServerManager $server,EventRegister $register): void
    {
    Di::getInstance()->set('MYSQL',\\MysqliDb::class,Array (
    'host' => '127.0.0.1',
    'username' => 'root',
    'password' => 'root',
    'db'=> 'imooc_video',
    'port' => 8889,
    'charset' => 'utf8')
    );
    Di::getInstance()->set('REDIS',Redis::getInstance());

    }

    public static function onRequest(Request $request,Response $response): void
    {
    // TODO: Implement onRequest() method.
    }

    public static function afterAction(Request $request,Response $response): void
    {
    // TODO: Implement afterAction() method.
    }
    }/<code>

    redis.php 这是redis的基类
    /**

    • Created by bingxiong.
    • Date: 12/21/18
    • Time: 12:44 AM
    • Description:
      */

    namespace App\\Lib\\Redis;

    // 使用单例模式
    use EasySwoole\\Config;
    use EasySwoole\\Core\\AbstractInterface\\Singleton;

    class Redis
    {
    use Singleton;

    <code>public $redis = "";

    private function __construct()
    {
    //判断扩展有没有安装
    if(!extension_loaded('redis')){
    throw new \\Exception("redis.so文件不存在");
    }
    try{
    // 从自己的配置加载
    $redisConfig = Config::getInstance()->getConf("redis");
    $this->redis = new \\Redis();
    $result = $this->redis->connect($redisConfig['host'],$redisConfig['port'],$redisConfig['time_out']);
    } catch (\\Exception $e){
    throw new \\Exception("redis服务异常");
    }

    if($result === false){
    throw new \\Exception("redis连接失败");
    }
    }

    /**
    * 重写get友好的返回key不存在的情况
    * @param $key
    * @return bool|string
    */

    public function get($key){
    if(empty($key)){
    return '';
    }
    return $this->redis->get($key);
    }/<code>

    }
    最终实现

    <code>/**
    * Created by bingxiong.
    * Date: 12/19/18
    * Time: 6:38 PM
    * Description:
    */

    namespace App\\HttpController\\Api;

    use \\EasySwoole\\Core\\Component\\Di;

    class Index extends Base
    {
    public function getRedis(){
    // 使用依赖注入
    $result = Di::getInstance()->get('REDIS')->get('bing');
    return $this->writeJson(200,'OK',$result);
    }

    }/<code>

    本文作者熊冰,个人网站Bing的天涯路),转载请注明出处。


    分享到:


    相關文章: