Webman AOP
v0.0.1
版本
2025-11-28
版本更新时间
2
安装
4
star
基于 Webman 框架实现的高性能、高可用的 AOP 插件,无依赖任何三方SDK实现。
特性
- ✅ 标准 AOP 切面类型:支持 Before、After、Around、AfterReturning、AfterThrowing
- ✅ 运行时代理:高性能的动态代理实现,无需生成文件
- ✅ 高可用:完善的错误处理和日志记录
- ✅ 符合 Webman 规范:使用 Bootstrap 接口和中间件机制
- ✅ PHP 8 Attributes:使用原生属性标记切面
- ✅ 优先级支持:多个切面按优先级执行
- ✅ 类级别和方法级别:支持两种级别的切面
- ✅ 抽象基类:提供 AbstractAspect 基类,简化切面开发
安装
通过 Composer 安装:
composer require x2nx/webman-aop
配置
配置文件:config/plugin/x2nx/webman-aop/app.php
<?php
return [
// 是否启用 AOP
'enable' => true,
// 扫描目录
'scan_dirs' => [
app_path(),
],
// 排除目录
'exclude_dirs' => [
'vendor',
'runtime',
'config',
'public',
],
];
使用方式
方法级别切面
<?php
namespace app\controller\v1\customer;
use X2nx\WebmanAop\Attribute\Aspect;
use X2nx\WebmanAop\Aspect\LogAspect;
class IndexController
{
#[Aspect(LogAspect::class)]
public function index()
{
// 方法逻辑
}
}
类级别切面
<?php
namespace app\controller\v1\customer;
use X2nx\WebmanAop\Attribute\Aspect;
use X2nx\WebmanAop\Aspect\LogAspect;
#[Aspect(LogAspect::class)]
class IndexController
{
// 所有公共方法都会应用 LogAspect
public function index() {}
public function detail() {}
}
多个切面(按优先级)
<?php
use X2nx\WebmanAop\Attribute\Aspect;
use X2nx\WebmanAop\Aspect\LogAspect;
use app\aspect\CacheAspect;
#[Aspect(LogAspect::class, [], 100)] // 优先级 100,后执行
#[Aspect(CacheAspect::class, [], 50)] // 优先级 50,先执行
class IndexController
{
// 切面执行顺序:CacheAspect -> LogAspect -> 原方法
}
创建自定义切面
方式一:实现 AspectInterface 接口
<?php
namespace app\aspect;
use X2nx\WebmanAop\Contract\AspectInterface;
use X2nx\WebmanAop\JoinPoint;
class CacheAspect implements AspectInterface
{
public function before(JoinPoint $joinPoint): void
{
// 前置通知:在目标方法执行前执行
}
public function after(JoinPoint $joinPoint): void
{
// 后置通知:在目标方法执行后执行(无论是否抛出异常)
}
public function around(JoinPoint $joinPoint, callable $proceed): mixed
{
// 环绕通知:可以控制目标方法的执行
// 可以修改参数、返回值,或决定是否执行目标方法
return $proceed();
}
public function afterReturning(JoinPoint $joinPoint, mixed $result): void
{
// 返回后通知:在目标方法正常返回后执行
}
public function afterThrowing(JoinPoint $joinPoint, \Throwable $exception): void
{
// 异常后通知:在目标方法抛出异常后执行
}
}
方式二:继承 AbstractAspect 基类(推荐)
<?php
namespace app\aspect;
use X2nx\WebmanAop\Contract\AbstractAspect;
use X2nx\WebmanAop\JoinPoint;
use support\Cache;
class CacheAspect extends AbstractAspect
{
public function before(JoinPoint $joinPoint): void
{
// 前置:检查缓存
$cacheKey = $this->getCacheKey($joinPoint);
if ($cached = Cache::get($cacheKey)) {
$joinPoint->setReturnValue($cached);
$joinPoint->setData('from_cache', true);
}
}
public function around(JoinPoint $joinPoint, callable $proceed): mixed
{
// 如果从缓存获取,直接返回
if ($joinPoint->getData('from_cache')) {
return $joinPoint->getReturnValue();
}
// 执行目标方法
$result = $proceed();
// 保存缓存
$cacheKey = $this->getCacheKey($joinPoint);
Cache::set($cacheKey, $result, 3600);
return $result;
}
protected function getCacheKey(JoinPoint $joinPoint): string
{
$method = $joinPoint->getFullMethodName();
$args = $joinPoint->getArgs();
return 'aop_cache:' . md5($method . serialize($args));
}
}
AOP 通知类型说明
Before(前置通知)
在目标方法执行之前执行,可以:
- 记录日志
- 参数验证
- 权限检查
- 缓存检查
public function before(JoinPoint $joinPoint): void
{
// 在目标方法执行前执行
Log::info('Before method execution');
}
After(后置通知)
在目标方法执行之后执行(无论是否抛出异常),可以:
- 清理资源
- 记录执行时间
- 释放锁
public function after(JoinPoint $joinPoint): void
{
// 无论是否抛出异常,都会执行
Log::info('After method execution');
}
Around(环绕通知)
可以完全控制目标方法的执行,可以:
- 修改参数
- 修改返回值
- 决定是否执行目标方法
- 实现缓存、事务等
public function around(JoinPoint $joinPoint, callable $proceed): mixed
{
// 前置逻辑
$this->beforeLogic();
// 执行目标方法(可以修改参数)
$result = $proceed();
// 后置逻辑(可以修改返回值)
return $this->afterLogic($result);
}
AfterReturning(返回后通知)
在目标方法正常返回后执行(不抛出异常时),可以:
- 记录返回值
- 处理返回结果
- 发送通知
public function afterReturning(JoinPoint $joinPoint, mixed $result): void
{
// 只在正常返回时执行
Log::info('Method returned', ['result' => $result]);
}
AfterThrowing(异常后通知)
在目标方法抛出异常后执行,可以:
- 记录异常
- 错误处理
- 发送告警
public function afterThrowing(JoinPoint $joinPoint, \Throwable $exception): void
{
// 只在抛出异常时执行
Log::error('Method threw exception', [
'exception' => get_class($exception),
'message' => $exception->getMessage()
]);
}
通知执行顺序
当多个切面应用到同一个方法时,执行顺序如下:
- 所有切面的 Before 通知(按优先级顺序)
- 所有切面的 Around 通知(按优先级顺序,形成链式调用)
- 目标方法执行
- 所有切面的 AfterReturning 通知(如果正常返回)
- 所有切面的 AfterThrowing 通知(如果抛出异常)
- 所有切面的 After 通知(无论是否抛出异常)
JoinPoint API
// 获取目标对象
$target = $joinPoint->getTarget();
// 获取类名和方法名
$className = $joinPoint->getClassName();
$methodName = $joinPoint->getMethodName();
$fullMethodName = $joinPoint->getFullMethodName();
// 获取和设置参数
$args = $joinPoint->getArgs();
$joinPoint->setArgs($newArgs);
$arg = $joinPoint->getArg(0);
$joinPoint->setArg(0, $value);
// 执行原方法
$result = $joinPoint->proceed();
// 获取返回值和异常
$returnValue = $joinPoint->getReturnValue();
$exception = $joinPoint->getException();
// 数据存储(用于切面之间传递数据)
$joinPoint->setData('key', $value);
$value = $joinPoint->getData('key', $default);
$allData = $joinPoint->getAllData();
完整示例
缓存切面
<?php
namespace app\aspect;
use X2nx\WebmanAop\Contract\AbstractAspect;
use X2nx\WebmanAop\JoinPoint;
use support\Cache;
class CacheAspect extends AbstractAspect
{
public function before(JoinPoint $joinPoint): void
{
$cacheKey = $this->getCacheKey($joinPoint);
if ($cached = Cache::get($cacheKey)) {
$joinPoint->setReturnValue($cached);
$joinPoint->setData('from_cache', true);
}
}
public function around(JoinPoint $joinPoint, callable $proceed): mixed
{
if ($joinPoint->getData('from_cache')) {
return $joinPoint->getReturnValue();
}
$result = $proceed();
$cacheKey = $this->getCacheKey($joinPoint);
Cache::set($cacheKey, $result, 3600);
return $result;
}
protected function getCacheKey(JoinPoint $joinPoint): string
{
return 'aop_cache:' . md5($joinPoint->getFullMethodName() . serialize($joinPoint->getArgs()));
}
}
事务切面
<?php
namespace app\aspect;
use X2nx\WebmanAop\Contract\AbstractAspect;
use X2nx\WebmanAop\JoinPoint;
use support\Db;
class TransactionAspect extends AbstractAspect
{
public function around(JoinPoint $joinPoint, callable $proceed): mixed
{
Db::beginTransaction();
try {
$result = $proceed();
Db::commit();
return $result;
} catch (\Throwable $e) {
Db::rollBack();
throw $e;
}
}
}
许可证
MIT