多应用架构

最后更新: 2026-01-27 11:02:47

多应用架构

Unicode Framework 支持多应用架构,允许在单个项目中运行多个独立的应用程序。这对于需要同时提供 Web 前端、管理后台、API 服务等的项目非常有用。

概述

多应用架构允许您在一个框架实例中运行多个应用,每个应用有自己独立的:

  • 控制器
  • 模型
  • 路由
  • 配置
  • 视图
  • 应用目录结构

    app/
    ├── index/          # 默认应用(Web 前端)
    │   ├── config/
    │   ├── controller/
    │   ├── model/
    │   ├── view/
    │   └── route.php
    ├── admin/          # 管理后台应用
    │   ├── config/
    │   ├── controller/
    │   ├── model/
    │   └── route.php
    └── api/            # API 应用
        ├── config/
        ├── controller/
        ├── model/
        └── route.php
    

    应用结构

    标准应用目录

    每个应用应包含以下目录和文件:

    app/{app-name}/
    ├── config/         # 应用配置(可选)
    │   └── app.php
    ├── controller/     # 控制器
    │   └── Index.php
    ├── model/          # 模型(可选)
    │   └── User.php
    ├── view/           # 视图(可选)
    │   └── index/
    │       └── index.tpl
    └── route.php       # 应用路由
    

    命名空间规范

    应用的命名空间遵循以下规则:

    // 控制器命名空间
    App\{AppName}\Controller\{ControllerName}
    

    // 示例 App\Index\Controller\UserController App\Admin\Controller\UserController App\Api\Controller\UserController

    // 模型命名空间 App\{AppName}\Model\{ModelName}

    // 示例 App\Index\Model\User App\Admin\Model\User

    路由策略

    框架支持三种路由策略来区分不同的应用:

    1. 路径策略(Path Strategy)

    通过 URL 路径前缀区分应用。

    配置 (config/app.php):
    return [
        'multi_app' => [
            'enabled' => true,
            'resolution_strategy' => 'path', // 路径策略
        ],
    ];
    
    路由示例:
    // app/index/route.php
    Route::get('/users', [UserController::class, 'index']);
    // 访问:/index/users
    

    // app/admin/route.php Route::get('/users', [UserController::class, 'index']); // 访问:/admin/users

    // app/api/route.php Route::get('/users', [UserController::class, 'index']); // 访问:/api/users

    默认应用:
    // config/app.php
    return [
        'default_app' => 'index',
        // ...
    ];
    

    // 访问根路径 / 会自动路由到 index 应用 Route::get('/', [IndexController::class, 'index']); // 访问:/

    2. 域名策略(Domain Strategy)

    通过域名区分应用。

    配置:
    return [
        'multi_app' => [
            'enabled' => true,
            'resolution_strategy' => 'domain',
            'domain_mapping' => [
                'www.example.com' => 'index',
                'admin.example.com' => 'admin',
                'api.example.com' => 'api',
            ],
        ],
    ];
    
    路由示例:
    // app/index/route.php
    Route::get('/users', [UserController::class, 'index']);
    // 访问:www.example.com/users
    

    // app/admin/route.php Route::get('/users', [UserController::class, 'index']); // 访问:admin.example.com/users

    3. 子域名策略(Subdomain Strategy)

    通过子域名区分应用(自动从子域名提取应用名)。

    配置:
    return [
        'multi_app' => [
            'enabled' => true,
            'resolution_strategy' => 'subdomain',
        ],
    ];
    
    路由示例:
    // 子域名 admin.example.com 自动映射到 app/admin
    // 子域名 api.example.com 自动映射到 app/api
    

    应用配置

    全局配置

    config/app.php 中配置多应用相关设置:

    return [
        // 默认应用
        'default_app' => 'index',
    

    // 默认控制器 'default_controller' => 'Index',

    // 默认方法 'default_action' => 'index',

    // 多应用配置 'multi_app' => [ 'enabled' => true, 'resolution_strategy' => 'path', // path, domain, subdomain 'domain_mapping' => [ // 域名策略时使用 ], ], ];

    应用级配置

    每个应用可以有自己独立的配置文件 app/{app-name}/config/app.php

    // app/admin/config/app.php
    return [
        'name' => 'Admin Panel',
        'default_controller' => 'Dashboard',
        'default_action' => 'index',
    ];
    

    应用级配置会覆盖全局配置。

    应用上下文

    框架提供了 AppContext 类来管理当前应用上下文。

    获取当前应用信息

    use Unicode\Framework\MultiApp\AppContext;
    

    // 获取当前应用名称 $appName = AppContext::getAppName(); // 'index', 'admin', 'api'

    // 获取当前应用路径 $appPath = AppContext::getAppPath(); // '/path/to/app/index'

    // 获取路由前缀 $prefix = AppContext::getRoutePrefix(); // '/index', '/admin', '/api'

    // 检查是否有应用上下文 if (AppContext::hasApp()) { // 当前在多应用模式下 }

    在控制器中使用

    namespace App\Index\Controller;
    

    use Unicode\Framework\Http\Request; use Unicode\Framework\MultiApp\AppContext;

    class IndexController { public function index(Request $request): array { return [ 'app_name' => AppContext::getAppName(), 'app_path' => AppContext::getAppPath(), ]; } }

    路由定义

    框架级路由

    在项目根目录的 route.php 中定义的路由对所有应用都有效:

    // route.php
    use Unicode\Framework\Route\Route;
    

    // 健康检查(所有应用共享) Route::get('/health', function() { return ['status' => 'ok']; }, 'framework.health');

    应用级路由

    app/{app-name}/route.php 中定义的路由只对该应用有效:

    // app/index/route.php
    use Unicode\Framework\Route\Route;
    

    Route::get('/users', [UserController::class, 'index'], 'index.users.index');

    路由优先级

    应用级路由优先于框架级路由。如果路径冲突,应用级路由会覆盖框架级路由。

    控制器开发

    控制器命名

    // app/index/controller/UserController.php
    namespace App\Index\Controller;
    

    use Unicode\Framework\Http\Request;

    class UserController { public function index(Request $request): array { return ['users' => []]; } }

    跨应用调用

    不同应用之间的控制器是独立的,不能直接调用。如果需要共享逻辑,应该:

  • 使用服务类(推荐)
  • // src/Service/UserService.php
    namespace App\Service;
    

    class UserService { public function getAllUsers(): array { // 共享的业务逻辑 } }

    // 在各个应用的控制器中使用 use App\Service\UserService;

    class UserController { public function index(Request $request): array { $service = new UserService(); return ['users' => $service->getAllUsers()]; } }

  • 使用模型(数据层共享)
  • // app/index/model/User.php 和 app/admin/model/User.php
    // 可以共享同一个模型类,或者继承基础模型
    

    最佳实践

    1. 应用职责划分

    // index 应用:面向用户的 Web 前端
    app/index/
    ├── controller/
    │   ├── HomeController.php
    │   ├── ProductController.php
    │   └── CartController.php
    └── route.php
    

    // admin 应用:管理后台 app/admin/ ├── controller/ │ ├── DashboardController.php │ ├── UserManageController.php │ └── ProductManageController.php └── route.php

    // api 应用:RESTful API app/api/ ├── controller/ │ ├── UserController.php │ └── ProductController.php └── route.php

    2. 共享资源

    对于需要在多个应用间共享的资源:

  • 模型:可以放在 src/Model/ 或各应用独立
  • 服务类:放在 src/Service/
  • 工具类:放在 src/Utils/
  • 中间件:放在 src/Middleware/
  • 3. 配置管理

    // 全局配置:config/app.php
    // 应用配置:app/{app-name}/config/app.php
    

    // 读取配置 config('app.name'); // 全局配置 config('app.name', null, 'admin'); // 应用配置(如果支持)

    4. 路由组织

    // app/index/route.php - Web 前端路由
    Route::get('/', [HomeController::class, 'index']);
    Route::get('/products', [ProductController::class, 'index']);
    

    // app/admin/route.php - 管理后台路由 Route::middleware([AdminAuthMiddleware::class], function() { Route::get('/dashboard', [DashboardController::class, 'index']); Route::get('/users', [UserManageController::class, 'index']); });

    // app/api/route.php - API 路由 Route::group('/api/v1', function() { Route::get('/users', [UserController::class, 'index']); Route::post('/users', [UserController::class, 'store']); });

    5. 环境区分

    // 开发环境:所有应用都可用
    // 生产环境:可以禁用某些应用
    

    // config/app.php return [ 'multi_app' => [ 'enabled' => true, 'available_apps' => ['index', 'api'], // 只启用部分应用 ], ];

    常见问题

    Q: 如何在不同应用间共享数据?

    A: 使用数据库、缓存或共享服务类。不同应用是独立的,不能直接共享内存数据。

    Q: 应用之间可以互相调用控制器吗?

    A: 不建议。应该通过服务类或模型来共享逻辑。

    Q: 如何为不同应用配置不同的中间件?

    A: 在各自应用的 route.php 中定义中间件。

    Q: 默认应用如何配置?

    A: 在 config/app.php 中设置 default_app,访问根路径 / 时会路由到默认应用。

    Q: 路由缓存对多应用有效吗?

    A: 是的。路由缓存会包含所有应用的路由,在生产环境下自动启用。

    相关文档

  • 路由系统 - 路由详细说明
  • 配置管理 - 配置系统使用
  • 控制器开发 - 控制器最佳实践