深度挖掘 Laravel 生命周期

本文首发于个人博客 深度挖掘 Laravel 生命周期,转载请注明出处。

这篇文章我们来聊聊 「Laravel 生命周期」 这个主题。虽然网络上已经有很多关于这个主题的探讨,但这个主题依然值得我们去研究和学习。

我想说的是当我们在决定使用某项技术的时候,除了需要了解它能「做什么」,其实还应当研究它是「怎么做的」。

Laravel 框架或者说任何一个 Web 项目,我们都需要理解它究竟是如何接收到用户发起的 HTTP 请求的;又是如何响应结果给用户的;在处理请求和响应的过程中都存在哪些处理值得深入学习。

所有这些内容其实都包含在 「Laravel 生命周期」 这个主题里面。

本文较长建议使用合适的 IDE 进行代码查阅;或者通过文中的链接,或是代码注释的 「@see」部分直接在 Github 畅读代码。

目录结构

  • 一 摘要
  • 二 生命周期之始末

    • 2.1 加载项目依赖
    • 2.2 创建 Laravel 应用实例

      • 2.2.1 创建应用实例
      • 2.2.2 内核绑定
      • 2.2.3 注册异常处理
      • 2.2.4 小结
    • 2.3 接收请求并响应

      • 2.3.1 解析内核实例
      • 2.3.2 处理 HTTP 请求

        • 2.3.2.1 创建请求实例
        • 2.3.2.2 处理请求

          • 2.3.2.2.1 启动「引导程序」
          • 2.3.2.2.2 发送请求至路由
    • 2.4 发送响应
    • 2.5 终止程序
  • 三 总结
  • 四 生命周期流程图
  • 参考资料

一 摘要

Laravel 生命周期(或者说请求生命周期)概括起来主要分为 3 个主要阶段:

  • 加载项目依赖
  • 创建 Laravel 应用实例
  • 接收请求并响应

而这 3 个阶段的处理都发生在入口文件 public/index.php 文件内(public/index.php 是一个新安装的 Laravel 项目默认入口文件)。

然而 index.php 文件仅包含极少的代码,但却出色的完成了一个 HTTP 请求从接收到响应的全部过程,逻辑组织的几近完美。

我们来看下入口文件实现的代码:

<?php
// 阶段一
require __DIR__.'/../vendor/autoload.php';// 阶段二
$app = require_once __DIR__.'/../bootstrap/app.php';// 阶段三
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);$response = $kernel->handle($request = Illuminate\Http\Request::capture()
);$response->send();// 其它
$kernel->terminate($request, $response);

二 生命周期之始末

2.1 加载项目依赖

现代 PHP 依赖于 Composer 包管理器,入口文件通过引入由 Composer 包管理器自动生成的类加载程序,可以轻松注册并加载项目所依赖的第三方组件库。

所有组件的加载工作,仅需一行代码即可完成:

require __DIR__.'/../vendor/autoload.php';

2.2 创建 Laravel 应用实例

创建应用实例(或称服务容器),由位于 bootstrap/app.php 文件里的引导程序完成,创建服务容器的过程即为应用初始化的过程,项目初始化时将完成包括:注册项目基础服务、注册项目服务提供者别名、注册目录路径等在内的一些列注册工作。

下面是 bootstrap/app.php 的代码,包含两个主要部分「创建应用实例」和「绑定内核至 APP 服务容器」:

<?php
// 第一部分: 创建应用实例
$app = new Illuminate\Foundation\Application(realpath(__DIR__.'/../')
);// 第二部分: 完成内核绑定
$app->singleton(Illuminate\Contracts\Http\Kernel::class,App\Http\Kernel::class
);$app->singleton(Illuminate\Contracts\Console\Kernel::class,App\Console\Kernel::class
);$app->singleton(Illuminate\Contracts\Debug\ExceptionHandler::class,App\Exceptions\Handler::class
);return $app;

2.2.1 创建应用实例

创建应用实例即实例化 Illuminate\Foundation\Application 这个服务容器,后续我们称其为 APP 容器。在创建 APP 容器主要会完成:注册应用的基础路径并将路径绑定到 APP 容器 、注册基础服务提供者至 APP 容器 、注册核心容器别名至 APP 容器 等基础服务的注册工作。

    /*** Create a new Illuminate application instance.** @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Application.php#L162:27* @param  string|null  $basePath* @return void*/public function __construct($basePath = null){if ($basePath) {$this->setBasePath($basePath);}$this->registerBaseBindings();$this->registerBaseServiceProviders();$this->registerCoreContainerAliases();}

2.2.2 内核绑定

接着将关注的焦点转移到绑定内核部分。

Laravel 会依据 HTTP 请求的运行环境的不同,将请求发送至相应的内核: HTTP 内核 或 Console 内核。无论 HTTP 内核还是 Console 内核,它们的作用都是是接收一个 HTTP 请求,随后返回一个响应,就是这么简单。

这篇文章主要研究 HTTP 内核,HTTP 内核继承自 Illuminate\Foundation\Http\Kernel 类.

在 「HTTP 内核」 内它定义了 中间件 相关数组;在 「Illuminate\Foundation\Http\Kernel」 类内部定义了属性名为 「bootstrappers」 的 引导程序 数组。

  • 中间件 提供了一种方便的机制来过滤进入应用的 HTTP 请求。
  • 「引导程序」 包括完成环境检测、配置加载、异常处理、Facades 注册、服务提供者注册、启动服务这六个引导程序。

至于 「中间件」 和 「引导程序」如何被使用的,会在后面的章节讲解。

2.2.3 注册异常处理

项目的异常处理由 App\Exceptions\Handler::class 类完成,这边也不做深入的讲解。

2.2.4 本节小结

通过上面的分析我们可以发现在「创建 Laravel 应用实例」这个阶段它做了很多的基础工作,包括但不限于:创建 APP 容器、注册应用路径、注册基础服务提供者、配置中间件和引导程序等。

2.3 接收请求并响应

在完成创建 APP 容器后即进入了第三个阶段 「接收请求并响应」。

「接收请求并响应」有关代码如下:

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);$response = $kernel->handle($request = Illuminate\Http\Request::capture()
);$response->send();

我们需要逐行分析上面的代码,才能窥探其中的原貌。

2.3.1 解析内核实例

在第二阶段我们已经将 HTTP 内核Console 内核 绑定到了 APP 容器,使用时通过 APP 容器make() 方法将内核解析出来,解析的过程就是内核实例化的过程。

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

内核实例化时它的内部究竟又做了哪些操作呢?

进一步挖掘 Illuminate\Foundation\Http\Kernel 内核的 __construct(IlluminateContractsFoundationApplication $app, \Illuminate\Routing\Router $router) 构造方法,它接收 APP 容器路由器 两个参数。

在实例化内核时,构造函数内将在 HTTP 内核定义的「中间件组」注册到 路由器,注册完后就可以在实际处理 HTTP 请求前调用这些「中间件」实现 过滤 请求的目的。

.../*** Create a new HTTP kernel instance. 创建 HTTP 内核实例* * @class Illuminate\Foundation\Http\Kernel* @param  \Illuminate\Contracts\Foundation\Application  $app* @param  \Illuminate\Routing\Router  $router* @return void*/public function __construct(Application $app, Router $router){$this->app = $app;$this->router = $router;$router->middlewarePriority = $this->middlewarePriority;foreach ($this->middlewareGroups as $key => $middleware) {$router->middlewareGroup($key, $middleware);}foreach ($this->routeMiddleware as $key => $middleware) {$router->aliasMiddleware($key, $middleware);}}
...
.../*** Register a group of middleware. 注册中间件组** @class \Illuminate\Routing\Router* @param  string  $name* @param  array  $middleware* @return $this*/public function middlewareGroup($name, array $middleware){$this->middlewareGroups[$name] = $middleware;return $this;}/*** Register a short-hand name for a middleware. 注册中间件别名** @class \Illuminate\Routing\Router* @param  string  $name* @param  string  $class* @return $this*/public function aliasMiddleware($name, $class){$this->middleware[$name] = $class;return $this;}
...

2.3.2 处理 HTTP 请求

之前的所有处理,基本都是围绕在配置变量、注册服务等运行环境的构建上,构建完成后才是真刀真枪的来处理一个「HTTP 请求」。

处理请求实际包含两个阶段:

  • 创建请求实例
  • 处理请求
// 处理请求
$response = $kernel->handle(// 创建请求实例$request = Illuminate\Http\Request::capture()
);
2.3.2.1 创建请求实例

请求实例 Illuminate\Http\Request 的 capture() 方法内部通过 Symfony 实例创建一个 Laravel 请求实例。这样我们就可以获取到用户请求报文的相关信息了。

    /*** Create a new Illuminate HTTP request from server variables.* * @class Illuminate\Http\Request* @return static*/public static function capture(){static::enableHttpMethodParameterOverride();return static::createFromBase(SymfonyRequest::createFromGlobals());}/*** Create an Illuminate request from a Symfony instance.** @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php* @param  \Symfony\Component\HttpFoundation\Request  $request* @return \Illuminate\Http\Request*/public static function createFromBase(SymfonyRequest $request){if ($request instanceof static) {return $request;}$content = $request->content;$request = (new static)->duplicate($request->query->all(), $request->request->all(), $request->attributes->all(),$request->cookies->all(), $request->files->all(), $request->server->all());$request->content = $content;$request->request = $request->getInputSource();return $request;}
2.3.2.2 处理请求

请求处理发生在 HTTP 内核 的 handle() 方法内。

    /*** Handle an incoming HTTP request.** @class Illuminate\Foundation\Http\Kernel* @param  \Illuminate\Http\Request  $request* @return \Illuminate\Http\Response*/public function handle($request){try {$request->enableHttpMethodParameterOverride();$response = $this->sendRequestThroughRouter($request);} catch (Exception $e) {$this->reportException($e);$response = $this->renderException($request, $e);} catch (Throwable $e) {$this->reportException($e = new FatalThrowableError($e));$response = $this->renderException($request, $e);}$this->app['events']->dispatch(new Events\RequestHandled($request, $response));return $response;}

handle() 方法接收一个 HTTP 请求,并最终生成一个 HTTP 响应。

继续深入到处理 HTTP 请求的方法 $this->sendRequestThroughRouter($request) 内部。

    /*** Send the given request through the middleware / router.** @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php* @param  \Illuminate\Http\Request  $request* @return \Illuminate\Http\Response*/protected function sendRequestThroughRouter($request){$this->app->instance('request', $request);Facade::clearResolvedInstance('request');$this->bootstrap();return (new Pipeline($this->app))->send($request)->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)->then($this->dispatchToRouter());}

将发现这段代码没有一行废话,它完成了大量的逻辑处理:

  • 首先,将 $request 实例注册到 APP 容器 供后续使用;
  • 之后,清除之前 $request 实例缓存;
  • 然后,启动「引导程序」;
  • 最后,发送请求至路由。
2.3.2.2.1 启动「引导程序」

记得我们在之前「2.2.2 内核绑定」章节,有介绍在「HTTP 内核」中有把「引导程序(bootstrappers)」绑定到了 APP 容器,以及这些引导程序的具体功能。

但是没有聊如何调用这些「引导程序」。

    /*** Send the given request through the middleware / router.** @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php* @param  \Illuminate\Http\Request  $request* @return \Illuminate\Http\Response*/protected function sendRequestThroughRouter($request){...// 启动 「引导程序」$this->bootstrap();...}

上面的代码块说明在 $this->bootstrap(); 方法内部有实际调用「引导程序」,而 bootstrap() 实际调用的是 APP 容器的 bootstrapWith(),来看看

... /*** The bootstrap classes for the application. 应用的引导程序** @var array*/protected $bootstrappers = [\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,\Illuminate\Foundation\Bootstrap\HandleExceptions::class,\Illuminate\Foundation\Bootstrap\RegisterFacades::class,\Illuminate\Foundation\Bootstrap\RegisterProviders::class,\Illuminate\Foundation\Bootstrap\BootProviders::class,];/*** Bootstrap the application for HTTP requests.* * @class Illuminate\Foundation\Http\Kernel* @return void*/public function bootstrap(){if (! $this->app->hasBeenBootstrapped()) {$this->app->bootstrapWith($this->bootstrappers());}}protected function bootstrappers(){return $this->bootstrappers;}
...

最终还是要看 Illuminate\Foundation\Application 的 bootstrapWith() 方法究竟如何来启动这些引导程序的。

    /*** Run the given array of bootstrap classes.* * @class  Illuminate\Foundation\Application APP 容器* @param  array  $bootstrappers* @return void*/public function bootstrapWith(array $bootstrappers){$this->hasBeenBootstrapped = true;foreach ($bootstrappers as $bootstrapper) {$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);$this->make($bootstrapper)->bootstrap($this);$this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);}}

我们看到在 APP 容器内,会先解析对应的「引导程序」(即实例化),随后调用「引导程序」的 bootstrap() 完成的「引导程序」的启动操作。

作为示例我们随便挑一个「引导程序」来看看其内部的启动原理。

这边我们选 Illuminate\Foundation\Bootstrap\LoadConfiguration::class,它的功能是加载配置文件。

还记得我们讲解「2.2 创建 Laravel 应用实例」章节的时候有「注册应用的基础路径并将路径绑定到 APP 容器」。此时,LoadConfiguration 类就是将 config 目录下的所有配置文件读取到一个集合中,这样我们就可以项目里通过 config() 辅助函数获取配置数据。

<?php
class LoadConfiguration
{/*** Bootstrap the given application.** @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php* @param  \Illuminate\Contracts\Foundation\Application  $app* @return void*/public function bootstrap(Application $app){$items = [];if (file_exists($cached = $app->getCachedConfigPath())) {$items = require $cached;$loadedFromCache = true;}$app->instance('config', $config = new Repository($items));if (! isset($loadedFromCache)) {$this->loadConfigurationFiles($app, $config);}$app->detectEnvironment(function () use ($config) {return $config->get('app.env', 'production');});date_default_timezone_set($config->get('app.timezone', 'UTC'));mb_internal_encoding('UTF-8');}/*** Load the configuration items from all of the files.** @param  \Illuminate\Contracts\Foundation\Application  $app* @param  \Illuminate\Contracts\Config\Repository  $repository* @return void* @throws \Exception*/protected function loadConfigurationFiles(Application $app, RepositoryContract $repository){$files = $this->getConfigurationFiles($app);if (! isset($files['app'])) {throw new Exception('Unable to load the "app" configuration file.');}foreach ($files as $key => $path) {$repository->set($key, require $path);}}...
}

所有 「引导程序」列表功能如下:

  • IlluminateFoundationBootstrapLoadEnvironmentVariables : 环境检测,通过 DOTENV 组件将 .env 配置文件载入到 $_ENV 变量中;
  • IlluminateFoundationBootstrapLoadConfiguration : 加载配置文件,这个我们刚刚分析过;
  • IlluminateFoundationBootstrapHandleExceptions : 异常处理;
  • IlluminateFoundationBootstrapRegisterFacades : 注册 Facades,注册完成后可以以别名的方式访问具体的类;
  • IlluminateFoundationBootstrapRegisterProviders : 注册服务提供者,我们在 「2.2.1 创建应用实例」已经将基础服务提供者注册到 APP 容器。在这里我们会将配置在 app.php 文件夹下 providers 节点的服务器提供者注册到 APP 容器,供请求处理阶段使用;
  • IlluminateFoundationBootstrapBootProviders : 启动服务
2.3.2.2.2 发送请求至路由

完成「引导程序」启动操作后,随机进入到请求处理阶段。

    /*** Send the given request through the middleware / router.** @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php* @param  \Illuminate\Http\Request  $request* @return \Illuminate\Http\Response*/protected function sendRequestThroughRouter($request){...// 发送请求至路由return (new Pipeline($this->app))->send($request)->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)->then($this->dispatchToRouter());}

在 「发送请求至路由」这行代码中,完成了:管道(pipeline)创建、将 $request 传入管道、对 $request 执行「中间件」处理和实际的请求处理四个不同的操作。

在开始前我们需要知道在 Laravel 中有个「中间件」 的概念,即使你还不知道,也没关系,仅需知道它的功能是在处理请求操作之前,对请求进行过滤处理即可,仅当请求符合「中间件」的验证规则时才会继续执行后续处理。

有关 「管道」的相关知识不在本文讲解范围内。

那么,究竟一个请求是如何被处理的呢?

我们来看看 $this->dispatchToRouter() 这句代码,它的方法声明如下:

/*** Get the route dispatcher callback. 获取一个路由分发器匿名函数** @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php* @return \Closure*/protected function dispatchToRouter(){return function ($request) {$this->app->instance('request', $request);return $this->router->dispatch($request);};}

回顾下「2.3.1 解析内核实例」章节,可知我们已经将 Illuminate\Routing\Router 对象赋值给 $this->router 属性。

通过 router 实例的 disptach() 方法去执行 HTTP 请求,在它的内部会完成如下处理:

  1. 查找对应的路由实例
  2. 通过一个实例栈运行给定的路由
  3. 运行在 routes/web.php 配置的匹配到的控制器或匿名函数
  4. 返回响应结果
<?php...//  @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Routing/Router.php
class Router implements RegistrarContract, BindingRegistrar
{    /*** Dispatch the request to the application.** @param  \Illuminate\Http\Request  $request* @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse*/public function dispatch(Request $request){$this->currentRequest = $request;return $this->dispatchToRoute($request);}/*** Dispatch the request to a route and return the response.** @param  \Illuminate\Http\Request  $request* @return mixed*/public function dispatchToRoute(Request $request){return $this->runRoute($request, $this->findRoute($request));}/*** Find the route matching a given request. 1. 查找对应的路由实例** @param  \Illuminate\Http\Request  $request* @return \Illuminate\Routing\Route*/protected function findRoute($request){$this->current = $route = $this->routes->match($request);$this->container->instance(Route::class, $route);return $route;}/*** Return the response for the given route. 2. 通过一个实例栈运行给定的路由** @param  Route  $route* @param  Request  $request* @return mixed*/protected function runRoute(Request $request, Route $route){$request->setRouteResolver(function () use ($route) {return $route;});$this->events->dispatch(new Events\RouteMatched($route, $request));return $this->prepareResponse($request,$this->runRouteWithinStack($route, $request));}/*** Run the given route within a Stack "onion" instance. 通过一个实例栈运行给定的路由** @param  \Illuminate\Routing\Route  $route* @param  \Illuminate\Http\Request  $request* @return mixed*/protected function runRouteWithinStack(Route $route, Request $request){$shouldSkipMiddleware = $this->container->bound('middleware.disable') &&$this->container->make('middleware.disable') === true;$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);// 4. 返回响应结果return (new Pipeline($this->container))->send($request)->through($middleware)->then(function ($request) use ($route) {return $this->prepareResponse(// 3. 运行在 routes/web.php 配置的匹配到的控制器或匿名函数$request, $route->run());});}

执行 $route->run() 的方法定义在 Illuminate\Routing\Route 类中,最终执行「在 routes/web.php 配置的匹配到的控制器或匿名函数」:

    /*** Run the route action and return the response.* * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Routing/Route.php* @return mixed*/public function run(){$this->container = $this->container ?: new Container;try {if ($this->isControllerAction()) {return $this->runController();}return $this->runCallable();} catch (HttpResponseException $e) {return $e->getResponse();}}

这部分如果路由的实现是一个控制器,会完成控制器实例化并执行指定方法;如果是一个匿名函数则直接调用这个匿名函数。

其执行结果会通过 Illuminate\Routing\Router::prepareResponse($request, $response) 生一个响应实例并返回。

至此,Laravel 就完成了一个 HTTP 请求的请求处理。

2.4 发送响应

经过一系列漫长的操作,HTTP 请求进入的最终章 - 发送响应值客户端 $response->send()

<?php
// @see https://github.com/laravel/laravel/blob/master/public/index.php// 阶段一
require __DIR__.'/../vendor/autoload.php';// 阶段二
$app = require_once __DIR__.'/../bootstrap/app.php';// 阶段三
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);$response = $kernel->handle($request = Illuminate\Http\Request::capture()
);// 发送响应
$response->send();// 其它
$kernel->terminate($request, $response);

发送响应由 Illuminate\Http\Response 父类 Symfony\Component\HttpFoundation\Response 中的 send() 方法完成。

    /*** Sends HTTP headers and content.* * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Response.php* @return $this*/public function send(){$this->sendHeaders();// 发送响应头部信息$this->sendContent();// 发送报文主题if (function_exists('fastcgi_finish_request')) {fastcgi_finish_request();} elseif (!\in_array(PHP_SAPI, array('cli', 'phpdbg'), true)) {static::closeOutputBuffers(0, true);}return $this;}

2.5 终止程序

程序终止,完成终止中间件的调用
// @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.phppublic function terminate($request, $response)
{$this->terminateMiddleware($request, $response);$this->app->terminate();
}// 终止中间件
protected function terminateMiddleware($request, $response)
{$middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge($this->gatherRouteMiddleware($request),$this->middleware);foreach ($middlewares as $middleware) {if (! is_string($middleware)) {continue;}list($name, $parameters) = $this->parseMiddleware($middleware);$instance = $this->app->make($name);if (method_exists($instance, 'terminate')) {$instance->terminate($request, $response);}}
}

以上便是 Laravel 的请求生命周期的始末。

三 总结

在 「创建 Laravel 应用实例」时不仅会注册项目基础服务、注册项目服务提供者别名、注册目录路径等在内的一系列注册工作;还会绑定 HTTP 内核及 Console 内核到 APP 容器, 同时在 HTTP 内核里配置中间件和引导程序。

进入 「接收请求并响应」里,会依据运行环境从 APP 容器 解析出 HTTP 内核或 Console 内核。如果是 HTTP 内核,还将把「中间件」及「引导程序」注册到 APP 容器

所有初始化工作完成后便进入「处理 HTTP 请求」阶段。

一个 Http 请求实例会被注册到 APP 容器,通过启动「引导程序」来设置环境变量、加载配置文件等等系统环境配置;

随后请求被分发到匹配的路由,在路由中执行「中间件」以过滤不满足校验规则的请求,只有通过「中间件」处理的请求才最终处理实际的控制器或匿名函数生成响应结果。

最后发送响应给用户,清理项目中的中间件,完成一个 「请求」 - 「响应」 的生命周期,之后我们的 Web 服务器将等待下一轮用户请求。

参考资料

感谢下列优秀的 Laravel 研究资料:

  • http://blog.mallow-tech.com/2...
  • http://laravel-recipes.com/re...
  • http://www.cnblogs.com/sweng/...
  • https://www.dyike.com/2017/04...
  • http://www.cnblogs.com/wxw16/...
  • http://www.php.cn/php-weiziji...
  • https://segmentfault.com/a/11...
  • https://segmentfault.com/a/11...
  • https://blog.csdn.net/cDonDon...
  • https://segmentfault.com/a/11...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

构建LAMP平台及应用系统

LANP架构指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括linux操作系统、apache网站服务器、mysql数据库服务器、PHP&#xff08;或Perl、Python&#xff09;网页编程语言。在构建LAMP平台时…

pyqt2_官网教程

sklearn实战-乳腺癌细胞数据挖掘&#xff08;博主亲自录制视频&#xff09; https://study.163.com/course/introduction.htm?courseId1005269003&utm_campaigncommission&utm_sourcecp-400000000398149&utm_mediumshare Articles You can find a collection of P…

Windows10安装WSL2和Ubuntu的过程

因为在Windows10环境中安装了2个相同的包导致冲突&#xff0c;所以想到了通过WSL2Docker的方式进行编程开发。因为Docker Desktop直接安装就行了&#xff0c;不做介绍。本文主要介绍WSL2和Ubuntu的安装过程。一.安装前的环境准备1.升级Windows系统因为低于某个版本号不支持WSL2…

Hyper-V数据文件丢失解决方案(有图有真相)

一、Hyper-V虚拟化故障概述 1、虚拟机环境故障虚拟化环境为ESXI虚拟化服务器&#xff0c;虚拟机环境&#xff0c;虚拟机的硬盘文件和配置文件放在北京某服务器托管公司的DELL MD3200存储中&#xff08;存储由5块容量为600G的硬盘组成raid磁盘阵列&#xff09;。该存储中4块硬盘…

SQL小技巧,动态输出本周各天日期

SET DATEFIRST 1; --设置周一为每周第一天 SELECT DATEFIRST;WITH w AS(SELECTCONVERT(varchar(10),T.[Date],120) AS [Date],DATENAME(weekday, T.[Date] ) AS [Week],DATEPART(WK, T.[Date]) AS WeekIndexFROM(SELECTDATEADD(DAY, number, DATEADD(wk, DATEDIFF(wk, 0, get…

开源的价值观与文化的传递

| 作者&#xff1a;Sharan Foga, Apache 软件基金会董事&#xff08;2021 届、2022 届&#xff09;&#xff0c;曾亲身来到 2019 中国开源年会&#xff08;COSCon19&#xff09;以本文内容发表主题演讲。| 翻译&#xff1a;刘天栋.Ted&#xff0c;徐红伟.stronghx| 审阅&#x…

用python来更改小伙伴的windows开机密码,不给10块不给开机

今天教大家用python脚本来控制小伙伴们windows电脑的开机密码。没错就是神不知鬼不觉&#xff0c;用random()随机生成的密码&#xff0c;只有你自己知道哦~ 代码呢分两部分&#xff0c;一部分是client端跟server端两个。你只需要想办法让小伙伴运行你的client端脚本就OK啦。不过…

el-upload 防止选择上传重复文件

<el-uploadref"uploadRef"multipledragaction"":auto-upload"false":file-list"msgPara.MsgFileList":on-change"handleFileChanged" ><el-button type"primary">选择文件</el-button> </el…

jmete 学习--基础之名词解释

一.jmeter 体系结构 1.名词解释 元件 jmemter工具菜单中的一个子菜单&#xff0c;如http请求&#xff0c;事务控制器等&#xff0c;就是一个元件。 组件 一组元件的集合&#xff0c;比如逻辑控制器中有事务控制器&#xff0c;仅一次控制器等&#xff0c;这些都是hi元件&#x…

Virtual script not found, may missing <script lang=“ts“> / “allowJs“: true / jsconfig.json.volar

解决办法&#xff1a; 在 jsconfig.json 配置文件中设置 "allowJs": true 如果没有jsconfig.json文件&#xff0c;直接在项目要目录创建一个&#xff0c;添加如下配置内容即可&#xff1a; /** Title: This is a file for ……* Author: JackieZheng* Date: 2022…

协鑫集成“熄灯工厂”装上ET工业大脑,验证订单命中率可提高3.99%

4月26日的云栖大会南京峰会&#xff0c;协鑫集成宣布&#xff0c;与阿里云ET工业大脑合作后&#xff0c;通过人工智能验证的订单命中率可提高3.99%。 协鑫集成是全球一线组件制造商&#xff0c;积极致力于推进自主创新与智能制造&#xff0c;综合运用信息通讯、物联网、大数据决…

pip install mysql-connector 安装出错

一、MySQL Connector/Python 2.2.3 的变化&#xff1a; 之前 mysql 官方说MySQL Connector/Python 是纯python语言写的&#xff0c;但是呢&#xff01; 这个问题在2.2.3中变天了&#xff1b; 以下是MySQL Connector/Python 2.2.3 是变更记录 Changes in MySQL Connector/Python…

2022世界传感器大会 | 龙芯中科发布龙芯2K0500多功能SoC芯片及解决方案

8月21日&#xff0c;由工业和信息化部、中国科学技术协会、河南省人民政府共同主办的2022世界传感器大会在郑州开幕&#xff0c;众多诺奖、图灵奖获得者、海内外院士和专家学者出席&#xff0c;全球传感器领域最具影响力的相关企业参加。龙芯中科董事长胡伟武在大会开幕式发表主…

Vue3 配置config文件,打包后随意修改配置,无需重新打包和重启

在public目录创建config.json文件&#xff0c;名字随便起。 {"AppVersion": "1.0","AppTitle": "这里是程序名称" } 修改AppTitle&#xff1a; {"AppVersion": "1.0","AppTitle": "这里是修改后的…

在Vue3中使用Element Plus Icon图标的几种方式

安装 Element Plus $ npm install element-plus/icons在main.js 引入 import * as ElIcon from element-plus/icons-vueObject.keys(ElIcon).forEach((key) > {app.component(key, ElIcon[key]) }) 方式一&#xff1a;通过 icon"el-icon-plus" 使用 <!-- …

Qt 打印机操作

2019独角兽企业重金招聘Python工程师标准>>> 配置文件加入打印机支持&#xff1a; QT printsupport 1、打印图片 打印图片所需头文件&#xff1a; #include <QPixmap> #include <QPrinter> #include <QPainter> 打印图片代码&#xff1a; QStrin…

spark集群详细搭建过程及遇到的问题解决(四)

在spark集群详细搭建过程及遇到的问题解决&#xff08;三&#xff09;中&#xff0c;我们将讲述了hadoop的安装过程&#xff0c;在本文中将主要讲述spark的安装配置过程。sparkmaster:~/spark$ cd hadoop sparkmaster:~/spark/hadoop$ cd $SPARK_HOME/conf sparkmaster:~/spark…

k8s 读书笔记 - 深入掌握 Pod

什么是 PodPod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。在同一个 context 下&#xff0c;应用可能还会有独立的 cgroup 隔离机制&#xff0c;一个 Pod 是一个容器环境下的 “逻辑主机”。Pod 是一组容器单元&#xff0c; 这些容器共享存储、网络、以及怎…

Net core 报 Could not load file or assembly ‘System.Security.Permissions 错误

完整错误提示 System.IO.FileNotFoundException:“Could not load file or assembly System.Security.Permissions, Version4.0.3.0, Cultureneutral, PublicKeyTokencc7b13ffcd2ddd51. 系统找不到指定的文件。” 控制台 错误提示&#xff1a; 根据提示可知&#xff1a;这是由…