YII2集成GOAOP,实现面向方面编程!

引言:
  软件开发的靶子是要对世界的一对因素或者音讯流建立模型,实现软件系统的工程需要将系统分解成能够创制和管理的模块。于是应运而生了以连串模块化特性的面向对象程序设计技术。模块化的面向对象编程卓殊地提高了软件系统的可读性、复用性和可扩张性。向目的方法的症结在于选拔对象作为模块的重要单元,并将对象与系统的装有行止联系起来。对象变成问题领域和总括过程的显要要素。但面向对象技术并不曾从精神上缓解软件系统的可复用性。创设软件系统时,现实问题中存在着诸多横切关注点,比如安全性检查、日志记录、性能监控,非凡处理等,它们的兑现代码和此外业务逻辑代码混杂在联名,并疏散在软件不同地点(直接把拍卖这个操作的代码参加到每个模块中),这毋庸置疑破坏了OOP的”单一任务”原则,模块的可重用性会大大降低,这使得软件系统的可维护性和复用性受到巨大限制。这时候传统的OOP设计反复利用的策略是出席相应的代办(Proxy)层来形成系统的机能要求,但诸如此类的拍卖肯定使系统总体增加了一个层次的撤并,复杂性也随之增多,从而给人过分沉重的感到。因此暴发了面向方面编程(AOP)技术。这种编程格局抽取出散落在软件系统所在的横切关注点代码,并模块化,归整到联合,这样进一步进步软件的可维护性、复用性和可扩充性。

AOP简介:
AOP: Aspect Oriented Programming 面向切面编程。
  面向切面编程(也叫面向方面):Aspect Oriented
Programming(AOP),是近期软件开发中的一个看好。利用AOP可以对工作逻辑的依次部分开展隔离,从而使得业务逻辑各部分之间的耦合度降低,提升程序的可重用性,同时提高了开销的效用。
  AOP是OOP的持续,是(Aspect Oriented
Programming)的缩写,意思是面向切面(方面)编程。
  紧要的效果是:日志记录,性能总括,安全控制,事务处理,非凡处理等等。
  重要的用意是:将日志记录,性能统计,安全控制,事务处理,相当处理等代码从事情逻辑代码中划分出来,通过对这么些作为的分别,我们盼望得以将它们独立到非指点业务逻辑的主意中,进而改变这多少个行为的时候不影响工作逻辑的代码。
  可以由此预编译形式和运行期动态代理实现在不修改源代码的境况下给程序动态统一添加效果的一种技术。AOP实际是GoF设计形式的接轨,设计格局孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种对象的一种实现。
即便把应用程序想成一个立体结构来说,OOP的利刃是纵向切入系统,把系统划分为众五个模块(如:用户模块,随笔模块等等),而AOP的利刃是横向切入系统,提取各种模块可能都要重新操作的一对(如:权限检查,日志记录等等)。总而言之,AOP是OOP的一个实用补充。
在意:AOP不是一种技术,实际上是编程思想。凡是适合AOP思想的技术,都得以看作是AOP的实现。

AOP 的基本概念:
在面向对象编程中,类,对象,封装,继承,多态等概念是描述面向对象思想紧要术语。与此类似,在面向方面编程中,同样存在着一些基本概念:
       联结点(JointPoint)
:一个联结程序执行过程中的一个特定点。典型的联结点有:调用一个艺术;方法执行这多少个历程本身;类初步化;对象初阶化等。联结点是
AOP 的主题概念之一,它用来定义在先后的哪儿通过 AOP 参与新的逻辑。
        切入点(Pointcut)
:一个切入点是用来定义某一个通报该什么时候实施的一组联结点。通过定义切入点,我们得以规范地控制程序中什么组件接到什么通告。下边我们提到,一个超人的联结点是模式调用,而一个独立的切入点就是对某一个类的四处方法调用的会见。通常大家会通过组建复杂的切入点来支配布告什么日期被执行。
        通知(Advice)
:在某一个一定的联结点处运行的代码称为“布告”。通知有成百上千种,比如
在联结点从前实施的放权通告(before
advice)和在联结点之后执行的后置通知(after advice) 。
       方面(Aspect)
:公告和切入点的组成叫做方面,所以,方面定义了一段程序中应当包括的逻辑,以及啥时候应该推行该逻辑。
       织入(Weaving) :织入是将方面确实插手程序代码的进程。对于静态
AOP
方案而言,织入是在编译时做到的,常常是在编译过程中扩张一个步骤。类似的,动态
AOP 方案则是在程序运行是动态织入的。
       目的(Target) :倘使一个目的的履行进程遭到某一个 AOP
的改动,那么它就叫一个对象对象。目的对象平时也称为被通报对象。
       引入(Introduction) :  
通过引入,可以在一个对象中进入新的主意或性能,以变更它的布局,这样即使该对象的类没有落实某一个接口,也可以修改它,使之变成该接口的一个贯彻。 
 

       静态和动态:静态 AOP 和动态 AOP
两者之间的区别首要在于怎么样时间织入,以及怎样织入。最早的 AOP
实现大多都是静态的。在静态 AOP 中,织入是编译过程的一个步骤。用Java
的术语说,静态 AOP
通过一贯对字节码举行操作,包括修改代码和扩张类,来完成织入过程。分明,这种办法生成的先后性能很好,因为最终的结果就是通常的
Java
字节码,在运作时不再需要特地的技巧来规定怎样时候理应进行公告。这种方法的缺点是,倘若想对下面做如何修改,即便只是进入一个新的联结点,都不可能不重新编译整个程序。AspectJ
是静态 AOP 的一个典型例证。与静态 AOP 不同,动态 AOP
中织入是在运转时动态完成的。织入具体是怎么成功的,各种实现有所不同。Spring
AOP 接纳的点子是树立代办,然后代理在适宜的时候实施文告。动态 AOP
的一个毛病就在于,其性质一般不如静态 AOP。而动态AOP
的要害优点在于可以每一日修改程序的具备方面,而不需再一次编译目的。

AOP实践:
YII2框架本身持有一个效能,叫做行为.它可以动态的为近日的类附加额外的功能,但这种效果在代码层级结构是静态的,有侵入性的。

下面以YII2框架集成go!aop库为例,介绍在YII2中什么落实AOP编程.(go!aop简介,可以参照go!aop的官网.)

鉴于YII框架拥有自己的类加载器,所在集成go!aop的时候,不可能正常的工作,所以要将其禁用掉,使用composer提供的类加载器。
正如代码所示(这里运用YII2尖端应用模板):

1、找到  spl_autoload_register([‘Yii’, ‘autoload’], true, true); 
(PROJECT_PATH/vendor/yiisoft/yii2/Yii.php) 将其禁用掉.

2、执行  composer require goaop/framework

3、修改composer.json文件,参加如下代码段:

 "autoload": {
        "psr-4": {
          "backend\\": "backend//",
          "frontend\\": "frontend//",
          "common\\": "common//"
        }
  }

4、 在frontend
目录下开创一个components是目录,并新建一个类AopAspectKernel,例如:

namespace frontend\components;
use frontend\aspects\MonitorAspect;
use Go\Core\AspectContainer;
use Go\Core\AspectKernel;
class AopAspectKernel extends AspectKernel
{
        protected function configureAop(AspectContainer $container)
        {
            $container->registerAspect(new MonitorAspect());
        }
}

 
5、在forntend目录下在新建一个类InitAopComponent,并使其落实BootstrapInterface,使其得以在YII2框架引导时被机关指点

namespace frontend\components;
use yii\base\BootstrapInterface;
class InitAopComponent implements BootstrapInterface
{
        public function bootstrap($app)
        {
            print_r(\Yii::$app->params['aop']);
            $applicationAspectKernel = AopAspectKernel::getInstance();
            $applicationAspectKernel->init(\Yii::$app->params['aop']);
        }
}

 
6、在frontend/config/params.php中新增如下代码:

 'aop' => [
        'debug' => true,
        'appDir' => dirname(__DIR__),
        'cacheDir' => dirname(__DIR__) . '/runtime/aop',
        'includePaths' => [
            dirname(__DIR__)
        ]
    ]

 
7、在frontend下边新建aspects目录,并新建类MonitorAspect,代码如下:

namespace frontend\aspects;

use Go\Aop\Aspect;
use Go\Aop\Intercept\MethodInvocation;
use Go\Lang\Annotation\Before;
class MonitorAspect implements Aspect
{
        /**
         * Method that will be called before real method
         *
         * @param MethodInvocation $invocation Invocation
         * @Before("execution(public frontend\components\AopTestComponent->*(*))")
         */
        public function beforeMethodExecution(MethodInvocation $invocation)
        {
            $obj = $invocation->getThis();
            echo 'Calling Before Interceptor for method: ',
            is_object($obj) ? get_class($obj) : $obj,
            $invocation->getMethod()->isStatic() ? '::' : '->',
            $invocation->getMethod()->getName(),
            '()',
            ' with arguments: ',
            json_encode($invocation->getArguments()),
            "<br>\n";
        }
}

 
9、修改frontend/config/main.php文件,并在components数组下增产一个key,代码如下:

 'components'=>[
        'aop' => [
            'class' => 'frontend\components\InitAopComponent'
        ]
    ]

 
10、修改frontend/config/main.php文件,并在bootstrap数组下新增aop值,代码如下:

'bootstrap'=>['log','aop']

至此,YII2整合go!aop完成…

 

相关文章