Hyperf 初體驗-AOP 切面

  • 2019 年 12 月 17 日
  • 筆記

Hyperf 初體驗-AOP 切面

什麼是 AOP

再說 AOP 之前,肯定都知道 OOP 是什麼,面向對象編程。那麼 AOP 就是 面向切面編程

  • 通過預編譯方式或運行期動態代理等技術實現程序功能的統一維護的一種技術。
  • OOP 是針對業務處理過程的實體及其屬性和行為進行抽象和封裝,以獲得更加清晰高效的邏輯單元劃分
  • AOP 則是針對業務處理過程中的切面進行提取,它所面對的是處理過程的某個步驟或某個階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果

簡單來說 切面就是 方法運行的前後執行的操作

如何定義切面

繼承 AbstractAspect 類,每一個切面類差不多包含如下內容

<?php  namespace AppAspect;    use AppServiceSomeClass;  use AppAnnotationSomeAnnotation;  use HyperfDiAnnotationAspect;  use HyperfDiAopAbstractAspect;  use HyperfDiAopProceedingJoinPoint;    /**   * @Aspect   */  class FooAspect extends AbstractAspect  {      // 要切入的類,可以多個,亦可通過 :: 標識到具體的某個方法,通過 * 可以模糊匹配      public $classes = [          SomeClass::class,          'AppServiceSomeClass::someMethod',          'AppServiceSomeClass::*Method',      ];        // 要切入的註解,具體切入的還是使用了這些註解的類,僅可切入類註解和類方法註解      public $annotations = [          SomeAnnotation::class,      ];        public function process(ProceedingJoinPoint $proceedingJoinPoint)      {          // 切面切入後,執行對應的方法會由此來負責          // $proceedingJoinPoint 為連接點,通過該類的 process() 方法調用原方法並獲得結果          // 在調用前進行某些處理          $result = $proceedingJoinPoint->process();          // 在調用後進行某些處理          return $result;      }  }

切入類

假設我要把 IndexController@index 進行切面

<?php    namespace AppAspect;    use AppControllerIndexController;  use HyperfDiAnnotationAspect;  use HyperfDiAopAbstractAspect;  use HyperfDiAopProceedingJoinPoint;    /**   * @Aspect()   */  class IndexAspect extends AbstractAspect  {      public $classes = [          IndexController::class . '::' . 'index',      ];        public function process(ProceedingJoinPoint $proceedingJoinPoint)      {          $result = $proceedingJoinPoint->process();          return '222'.$result . 'qqq';      }  }

以上將會對 index 路由的返回值進行處理,進行改寫。

切入註解
<?php    namespace AppAspect;    use AppAnnotationUser;  use AppControllerIndexController;  use HyperfDiAnnotationAspect;  use HyperfDiAopAbstractAspect;  use HyperfDiAopProceedingJoinPoint;    /**   * @Aspect()   */  class IndexAspect extends AbstractAspect  {      public $annotations = [          User::class,      ];        public function process(ProceedingJoinPoint $proceedingJoinPoint)      {          $result = $proceedingJoinPoint->process();          //獲取註解參數          /**           * @var User $user           */          $user = $proceedingJoinPoint->getAnnotationMetadata()->class[User::class];          return '222'.$result . $user->name;      }  }

對應 控制器的內容

<?php    namespace AppController;    use AppAnnotationUser;  use HyperfHttpServerAnnotationAutoController;    /**   * @AutoController()   * @User("666666")   */  class IndexController extends Controller  {        public function index()      {          return 'Hello Hyperf!' ;      }  }

注意,被切入的類 註解,只會在第一次起作用。比如修改 控制器返回值,再次請求會返回之前的記錄。原因如下:

所有被 AOP 影響的類,都會在 ./runtime/container/proxy/ 文件夾內生成對應的 代理類緩存,服務啟動時,如果類所對應的代理類緩存存在,則不會重新生成直接使用緩存,即使 Aspect 的切入範圍發生了改變。不存在時,則會自動重新生成新的代理類緩存。 在部署生產環境時,我們可能會希望 Hyperf 提前將所有代理類提前生成,而不是使用時動態的生成,可以通過 php bin/hyperf.php di:init-proxy 命令來生成所有代理類,該命令會忽視現有的代理類緩存,全部重新生成。 基於以上,我們可以將生成代理類的命令和啟動服務的命令結合起來,php bin/hyperf.php di:init-proxy && php bin/hyperf.php start 來達到自動重新生成所有代理類緩存然後啟動服務的目的。

本地開發,我們可以直接將代理類緩存刪掉,然後再重新啟動服務即可.

(adsbygoogle = window.adsbygoogle || []).push({});