hyperf中@aspect切面不生效,需检查切面类是否在scan目录、带#[aspect]注解且非abstract/final,运行di:dump验证是否被扫描;代理类未生成则需确认aspectcontainer注册并清缓存;目标方法未拦截须核对切入规则是否精确匹配。

Hyperf中Aspect切面不生效?检查@Aspect类是否被正确扫描
Hyperf的AOP依赖注解扫描,如果切面类没被自动加载,@Pointcut和@Around等注解就完全不会触发。默认情况下,Hyperf只扫描app/Aspect目录下的类,且该类必须满足两个条件:带有@Aspect注解、类名以Aspect结尾(如UserOperationAspect)。
常见错误是把切面放在app/Service/Aspect/这种非标准路径下,或类名写成UserAspectHandler——Hyperf会直接忽略它。
- 确保切面类路径为
app/Aspect/xxxAspect.php - 类顶部必须声明
@Aspect,且不能漏掉use Hyperf\Di\Annotation\Aspect; - 在
config/autoload/annotations.php中确认scan配置已包含app/Aspect目录
如何匹配带自定义注解的方法?用@Pointcut写对表达式
Hyperf的@Pointcut不支持直接写@MyAnnotation这种语法,必须用execution + annotation组合。比如你想拦截所有标有@NeedAudit的方法,表达式得写成:
@Pointcut(
"execution(public * App\Controller\*->*(*)) && annotation(App\Annotation\NeedAudit)"
)
注意三点:第一,annotation()括号里填的是**完整命名空间+类名**,不是短名;第二,execution部分要足够宽泛但又不能太宽——写成*->*()可能误伤框架内部方法;第三,Hyperf 3.x 要求annotation必须是类注解(@Target("CLASS"))或方法注解(@Target("METHOD")),不能是参数或属性注解。
- 自定义注解类必须加
@Retention(RetentionType.RUNTIME),否则运行时读不到 - 如果想同时匹配类上和方法上的
@NeedAudit,得写两个@Pointcut,Hyperf不支持||逻辑或 - 表达式里的空格和括号必须严格匹配,多一个空格会导致解析失败且无报错
@Around方法里怎么拿到被拦截方法的注解值?
Hyperf的@Around回调函数签名是public function process(ProceedingJoinPoint $proceedingJoinPoint),它本身不暴露注解实例。你需要手动从反射中提取:
$method = $proceedingJoinPoint->getOriginalMethod();
$annotation = $method->getAnnotation(\App\Annotation\NeedAudit::class);
if ($annotation && $annotation->level === 'high') {
// 执行审计逻辑
}
这里容易出错的是:getAnnotation()返回null时直接调用属性会报错;另外,如果注解用了@Repeatable,得用getAnnotations()并遍历。
- 别用
$proceedingJoinPoint->getMethod()->getAnnotation(),因为getMethod()返回的是代理方法,反射信息可能不全 - 如果注解字段是
array类型,Hyperf默认不自动转换,需手动json_decode($annotation->rules, true) - 获取类级注解要用
$proceedingJoinPoint->getClass()->getAnnotation()
为什么annotations配置项不起作用?它根本不是给切面用的
很多人在config/autoload/annotations.php里配annotations数组,以为能控制哪些注解参与AOP扫描——其实这个配置只影响AnnotationCollector的静态收集行为,和@Pointcut的运行时匹配完全无关。切面匹配靠的是PHP反射+表达式解析,不走这个配置项。
真正影响切面行为的是scan下的paths和ignore_annotations(后者用于排除某些注解不被收集,但也不影响@Pointcut)。
-
annotations配置项只在你主动调用AnnotationCollector::getAnnotationsByClass()时才生效 - 想调试切面是否匹配成功,可在
@Around里加var_dump($proceedingJoinPoint->getMethodName()),而不是查日志 - Hyperf 2.2+ 开始,
ignore_annotations默认包含Doctrine\ORM\Mapping\*等ORM注解,避免干扰AOP性能
最常被忽略的一点:切面方法必须是public,且不能有类型声明冲突(比如void返回值但process里忘了return $proceedingJoinPoint->process();),否则整个请求会静默失败。











