Swoft 2.x 详解Bean

什么是Bean呢?

  • Swoft中Bean是一个类的对象实例
  • 每个被Swoft管理的PHP对象称之为Bean
  • Swoft提供了一个IoC容器来初始化对象和获取对象,用来解决对象之间的依赖管理。

以前当我们要调用一个类的时候是需要先使用new关键字对类进行实例化后才能使用,现在有了Bean,当Swoft启动的时候就给实例化并一直存在,当你使用时不再需要再去new,这样可以节省资源

以JavaBean为例:JavaBean是一种Java语言编写的可重用组件,为了编写JavaBean类必须是具体的和公共的,并且具有无参构造器。JavaBean通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,并通过setget方法获取。总所周知,属性名符合这种模式,其它Java类可以通过自省(反射)机制发现和操作这些JavaBean的属性。

什么是IoC容器呢?

Swoft为应用提供了一个完整的IoC容器作为依赖管理方案,是Swoft AOP功能、RPC模块等功能的实现基础。

如果对IoC容器不是非常理解的话,请参见《IoC控制反转》

IoC容器主要解决了三个问题:

  1. 避免手工管理对象之间的依赖嵌套
  2. 对象的依赖关系不再在编译期间确定,提供了运行起改变行为的更多弹性。
  3. 对象可以不再依赖具体实现,而是依赖抽象的接口或是抽象类实现。

什么是Bean容器呢?

容器是一个巨大的工厂,用来存放和管理Bean生命周期。

Bean定义

Bean有两种定义方式:注解、数组配置

  1. 通过数组定义
  2. 通过注解定义:注解定义使用PHP文档注解,在类上做标记,通过解析类注解,实现不同的功能。

例如:中间件的定义中

$ vim /app/Middlewares/ActionTestMiddleware.php
<?php
namespace App\Middlewares;

use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Swoft\Bean\Annotation\Bean;
use Swoft\Http\Message\Middleware\MiddlewareInterface;


/**
 * @Bean()
 * @uses      ActionTestMiddleware
 */
class ActionTestMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $response = $handler->handle($request);
        return $response->withAddedHeader('Middleware-Action-Test', 'success');
    }
}

Bean通过类级别注解@Bean定义,Bean定义后程序可以直接通过App::getBean()获取一个Bean实例。

注解使用

@Bean 注解

命名空间:use Swoft\Bean\Annotation\Bean;

源码分析:

$ vim vendor/swoft/framework/src/Bean/Annotation/Bean.php
<?php
namespace Swoft\Bean\Annotation;
/**
 * bean注解
 *
 * @Annotation
 * @Target("CLASS")
 * @uses      Bean
 */
class Bean
{
    /**
     * bean名称
     * @var string
     */
    private $name = "";
    /**
     * bean类型
     * @var int
     */
    private $scope = Scope::SINGLETON;
    /**
     * referenced bean, default is null
     * @var string
     */
    private $ref = "";
    /**
     * Bean constructor.
     * @param array $values
     */
    public function __construct(array $values)
    {
        if (isset($values['value'])) {
            $this->name = $values['value'];
        }
        if (isset($values['name'])) {
            $this->name = $values['name'];
        }
        if (isset($values['scope'])) {
            $this->scope = $values['scope'];
        }
        if (isset($values['ref'])) {
            $this->ref = $values['ref'];
        }
    }
    /**
     * 获取bean名称
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }
    /**
     * 获取bean类型
     * @return int
     */
    public function getScope()
    {
        return $this->scope;
    }
    /**
     * return name of referenced bean
     * @return string
     */
    public function getRef(): string
    {
        return $this->ref;
    }
}

打开源码,可以看到Bean构造函数可传入一个关联数组的参数。

public function __construct(array $values)
{
    if (isset($values['value'])) {
        $this->name = $values['value'];
    }
    if (isset($values['name'])) {
        $this->name = $values['name'];
    }
    if (isset($values['scope'])) {
        $this->scope = $values['scope'];
    }
    if (isset($values['ref'])) {
        $this->ref = $values['ref'];
    }
}

构造器参数

  • name 定义Bean别名,缺省默认类名。
  • scope 注入Bean类型,默认单例Scope::SINGLETON/Scope::PROTOTYPE
  • ref 指定引用Bean,用于定义在接口上指定使用哪个接口实现。

使用注意

  • @Bean里面只能使用双引号
  • @Bean()是指注入的Bean名称使用包含命名空间的类名。
  • @Bean("userModel")@Bean(name="userModel")含义是一样的
  • @Bean(name="beanName", scope=Scope::SINGLETON) 默认注入的Bean都是单例,使用scope属性设置其类型。

@Inject

命名空间:use Swoft\Bean\Annotation\Inject;
源码分析:

$ vim vendor/swoft/framework/src/Bean/Annotation/Inject.php
<?php
namespace Swoft\Bean\Annotation;
/**
 * inject注解
 *
 * @Annotation
 * @Target({"PROPERTY","METHOD"})
 *
 * @uses      Inject
 */
class Inject
{
    /**
     * 注入bean名称
     * @var string
     */
    private $name = "";
    /**
     * Inject constructor.
     * @param array $values
     */
    public function __construct(array $values)
    {
        if (isset($values['value'])) {
            $this->name = $values['value'];
        }
        if (isset($values['name'])) {
            $this->name = $values['name'];
        }
    }
    /**
     * 获取bean名称
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }
}

构造函数:

  • name 定义属性注入的Bean名称,缺省属性自动为类型名称。

使用注意:

  • @Inject格式与@Bean基本一样,注意通过注解目前不支持构造函数参数注入。
  • @Inject() 默认注入该属性,对应的包含命名空间的类型名Bean。
  • @Inject(name="${logger}")@Inject("${logger}")注入名称为logger的Bean到属性
  • @Inject(name="${config.user.stelin.steln}")注入properties中配置的值,可以层级和直接直接。

使用示例:

/**
 * 别名注入.
 * @Inject("httpRouter")
 * @var \Swoft\Http\Server\Router\HandlerMapping
 */
private $router;

/**
 * 别名注入.
 * @Inject("application")
 * @var Application
 */
private $application;

/**
 * 注入逻辑层
 * @Inject()
 * @var IndexLogic
 */
private $logic;

操作Bean

App::getBean()提供服务定位器式的依赖管理方式,用于可以通过访问服务定位器获取特定的实例,服务定位器解决了“实例构造,实例间依赖管理,具体实现类选择”的问题,并对用户屏蔽相关细节。

Container->set()方法是App::getBean()底层实际创建Bean的方法,原理是通过反射和各种注解提供的信息和方法构造Bean的一个代理对象。

use Swoft\App;
App::getBean("name");
//例如
$logic = App::getBean(UserLogic::class);
use Swoft\Core\ApplicationContext;
ApplicationContext::getBean('name');
use Swoft\Bean\BeanFactory;
// App/ApplicationContext/BeanFactory都可从容器中得到Bean
BeanFactory::getBean('name');
use Swoft\Bean\BeanFactory;
// hasBean 某个bean是否存在
BeanFactory::hasBean("name");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值