当前位置: 技术文章>> magento2中的Proxy代理模式详解

文章标题:magento2中的Proxy代理模式详解
  • 文章分类: Magento
  • 15674 阅读
系统学习magento二次开发,推荐小册:《Magento中文全栈二次开发 》

本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。


magento2中的proxy是一种设计模式,比较难于理解,本篇内容将为大家介绍magento2中的代理模式:proxy

当对象创建成本很高,并且类的构造函数占用了大量资源时,就会使用代理类。为了避免不必要的性能影响,

Magento使用Proxy类将给定的类型变成它们的延迟加载版本。

在所有Magento di.xml文件中快速查找\Proxy</argument>字符串可以发现该字符串出现了一百多次。

可以说,Magento在其代码中广泛使用代理。

<MAGENTO_DIR>/module-customer/etc/di.xml下的类型定义是使用代理的一个很好的例子:

<type name="Magento\Customer\Model\Session">
    <arguments>
        <argument name="configShare" xsi:type="object">Magento\Customer\Model\Config\Share\Proxy</argument>
        <argument name="customerUrl" xsi:type="object">Magento\Customer\Model\Url\Proxy</argument>
        <argument name="customerResource" xsi:type="object">Magento\Customer\Model\ResourceModel\Customer\Proxy</argument>
        <argument name="storage" xsi:type="object">Magento\Customer\Model\Session\Storage</argument>
        <argument name="customerRepository" xsi:type="object">Magento\Customer\Api\CustomerRepositoryInterface\Proxy</argument>
    </arguments>
</type>

如果我们查看Magento\Customer\Model\Session类型的构造函数,我们可以看到四个参数

(configShare、customerUrl、customerResource和customerRepository)中,

没有一个在PHP文件中声明为Proxy。它们是通过di.xml重写的。

这些代理类型还不真正存在,因为Magento依赖注入(di)编译过程创建了它们。

它们是在生成的目录下自动生成的。

编译后,可以在生成的/code/Magento/Customer/Model/Url/Proxy.php

文件下轻松找到Magento\Customer\Model\Url\Proxy.php类型。

让我们局部来看一下:

<?php
class Proxy extends\ Magento\ Customer\ Model\ Url implements\ Magento\ Framework\ ObjectManager\ NoninterceptableInterface {
    public function __construct(\Magento\ Framework\ ObjectManagerInterface $objectManager, $instanceName = '\\Magento\\Customer\\Model\\Url', $shared = true) {
        $this - > _objectManager = $objectManager;
        $this - > _instanceName = $instanceName;
        $this - > _isShared = $shared;
    }
    public function __sleep() {
        return ['_subject', '_isShared', '_instanceName'];
    }
    public function __wakeup() {
        $this - > _objectManager = \Magento\ Framework\ App\ ObjectManager::getInstance();
    }
    public function __clone() {
        $this - > _subject = clone $this - > _getSubject();
    }
    protected function _getSubject() {
        if (!$this - > _subject) {
            $this - > _subject = true === $this - > _isShared ? $this - > _objectManager - > get($this - > _instanceName) : $this - > _objectManager - > create($this - > _instanceName);
        }
        return $this - > _subject;
    }
    public function getLoginUrl() {
        return $this - > _getSubject() - > getLoginUrl();
    }
    public function getLoginUrlParams() {
        return $this - > _getSubject() - > getLoginUrlParams();
    }
}

Proxy类的组成显示了它包装原始Magento\Customer\Model\Url类型的机制。这意味着,在整个Magento中,

每次请求Magento\Customer\Model\Url类型时,

Magento\Customer\Module\Url\Proxy都会被传递。与原始类型的__construct方法(可能会影响性能)不同,

自动生成代理的__construction方法是轻量级的。这消除了可能的性能瓶颈。_getSubject方法用于在调用任何原始类型的公共方法时,

实例化/延迟加载原始类型。

例如,对getLoginUrl方法的调用将通过代理。

Magento生成的每个代理都实现了Magento\Framework\ObjectManager\NoninterceptableInterface。

尽管接口本身是空的,但它被用作标识代理的标记,

我们不需要为其生成拦截器(插件)。

class Customer {
    public
    function __construct(\Magento\ Customer\ Model\ Url\ Proxy $customerUrl) { //...    }}

然而,这种做法是一种糟糕的做法。正确执行此操作的方法是使用原始Magento\Customer\Model\Url类型指定__construct,

然后按如下方式添加di.xml:

<type name="Magelicious\Core\Model\Customer">
    <arguments>
        <argument name="customerUrl" xsi:type="object">Magento\Customer\Model\Url\Proxy</argument>
    </arguments>
</type>

推荐文章