Write once, run anywhere
概述
环境:LNMP(CentOS7.2 + Nginx1.10 + MariaDB10.0 + PHP5.6),Laravel5.1,Yar;
用户Api项目:项目名:example_user_api(example可替换为具体公司的名字,代表公司的user项目,下同),域名:api.user.example.com,对应数据:user;
订单Api项目:项目名:example_order_api,域名:api.order.example.com,对应数据:order;
订单项目:项目名:example_order,域名:order.example.com;
正文
作为一名PHP后端开发工程师,时常感受到来自项目deadline的压力,而且还有需求在开发过程中的变更。
如何应对需求的变更和来自项目deadline的压力,那就要考虑系统的架构了,然后,才是编码——为何这样说,我喜欢用一个比喻解释,大厦的架构搭建好了,垒砖就容易多了。
系统架构从项目的角度来讲有两个方面,一方面是项目与项目之间的搭配,另一方面是项目本身的分层。
本文主要讲项目与项目之间的搭配这一方面的架构,也就是实现Write once, run anywhere的基础。先下结论:项目与项目之间通过RPC接口调用。
如环境描述和项目清单所述,环境为LNMP,用户相关项目有用户Api项目,订单相关项目有订单Api项目和订单项目。
读者或许有疑问了,这里用户相关的只有一个项目,为何订单相关的项目有两个,它们之间有什么区别?其实,这就是Write once, run anywhere的关键。
用户Api项目能够为订单项目提供Rpc服务,订单Api项目更是主要是为订单项目提供Rpc服务,这两者本身都是没有界面的,这也是它们为何被定义为Api项目的原因。而订单项目通过调用用户Api项目和订单Api项目的Rpc服务,为用户提供查看、修改等操作自己订单的服务,因此是有界面的。
然而,这也不足以要把订单划分成订单Api项目和订单项目两个项目。进一步的原因是订单Api项目不仅用于(用户查询、修改订单等操作的)订单项目,也可以为公司内部的ERP系统提供订单相关的Rpc服务。
代码
Talk is easy, show me the code.
用户Api项目,有t_user表,其对应的Model为User,文件名为User.php,内容如下:
<?php
namespace App\Model;
use DB;
use Log;
use Redis;
/**
* 用户表
* @author los_gsy
*/
class User {
/**
* 查询一条记录,根据id
* @param int $id
* @return null | object
*/
static public function getById($id) {
$result = DB::connection('user')->table('user')
->where('id', $id)
->first();
if (!$result) {
Log::warning(__METHOD__ . ': $param = ' . var_export(func_get_args(), true));
}
return $result;
}
}
通过Controller封装成Rpc服务,这里取文件名为ModelController.php,内容如下:
<?php
namespace App\Http\Controllers\Rpc;
use App\Http\Controllers\Controller;
use App\Model\User;
use Illuminate\Http\Request;
use Log;
use Yar_Server;
/**
* 模型
* @author los_gsy
*/
class ModelController extends Controller {
/**
* 构造函数
*/
public function __construct(Request $req) {
parent::__construct();
}
/**
* 用户
*/
public function user(Request $req) {
$service = new Yar_Server(new User());
$service->handle();
}
}
类似的,订单Api项目,有t_order表,其对应的Model为Order,文件名为Order.php,内容如下:
<?php
namespace App\Model;
use DB;
use Log;
use Redis;
/**
* 订单表
* @author los_gsy
*/
class Order {
/**
* 查询一条记录,根据id
* @param int $id
* @return null | object
*/
static public function getById($id) {
$result = DB::connection('order')->table('order')
->where('id', $id)
->first();
if (!$result) {
Log::warning(__METHOD__ . ': $param = ' . var_export(func_get_args(), true));
}
return $result;
}
}
通过Controller封装成Rpc服务,这里同样取文件名为ModelController.php,内容如下:
<?php
namespace App\Http\Controllers\Rpc;
use App\Http\Controllers\Controller;
use App\Model\Order;
use Illuminate\Http\Request;
use Log;
use Yar_Server;
/**
* 模型
* @author los_gsy
*/
class ModelController extends Controller {
/**
* 构造函数
*/
public function __construct(Request $req) {
parent::__construct();
}
/**
* 订单
*/
public function order(Request $req) {
$service = new Yar_Server(new Order());
$service->handle();
}
}
订单项目,在这里用户需要查询自己的一个订单详情,于是通过调用用户Api项目和订单Api项目的Rpc服务来实现,代码如下:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Yar_Client;
/**
* 订单
* @author los_gsy
*/
class OrderController extends Controller {
/**
* 构造函数
*/
public function __construct(Request $req) {
parent::__construct();
}
/**
* tmp
* @param Request $req
*/
public function tmp(Request $req) {
//定义变量
$oUser = new Yar_Client('http://api.user.example.com/Rpc/Model/user');
$oOrder = new Yar_Client('http://api.order.example.com/Rpc/Model/order');
//查询用户和订单
$user = $oUser->getById(1);
$order = $oOrder->getById(1);
//打印用户和订单信息
var_export($user);
var_export($order);
}
}
结尾
Write once, run anywhere主要的思路就如上所述,以及代码示例了。仅用于学习参考,如果是生产使用,还需考虑安全、性能等因素。
刚开始在简书上写日志,不足之处,还请各位不吝赐教。