代码功能更新

This commit is contained in:
root
2025-05-18 07:42:27 +00:00
parent 7fc1d422a1
commit 4a90c41da2
2083 changed files with 695218 additions and 3 deletions
+157
View File
@@ -0,0 +1,157 @@
<?php
namespace app\service\admin;
use app\model\admin\Role;
use app\model\admin\role\Menu;
use laytp\traits\Error;
use think\facade\Request;
/**
* 后台权限服务实现者
* Class Auth
* @package app\service\admin
*/
class Auth
{
use Error;
protected $_noNeedLogin = [];//无需登录的方法名数组
protected $_noNeedAuth = [];//无需鉴权的方法名数组
/**
* 设置无需登录的方法名数组
* @param array $noNeedLogin
*/
public function setNoNeedLogin($noNeedLogin = [])
{
$this->_noNeedLogin = $noNeedLogin;
}
/**
* 获取无需登录的方法名数组
* @return array
*/
public function getNoNeedLogin()
{
return $this->_noNeedLogin;
}
/**
* 当前节点是否需要登录
* @param bool $noNeedLogin
* @return bool true:需要登录,false:不需要登录
*/
public function needLogin($noNeedLogin = false)
{
$noNeedLogin === false && $noNeedLogin = $this->getNoNeedLogin();
$noNeedLogin = is_array($noNeedLogin) ? $noNeedLogin : explode(',', $noNeedLogin);
//为空表示所有方法都需要登录,返回true
if (!$noNeedLogin) {
return true;
}
$noNeedLogin = array_map('strtolower', $noNeedLogin);
$request = Request::instance();
//判断当前请求的操作名是否存在于不需要登录的方法名数组中,如果存在,表明不需要登录,返回false
if (in_array(strtolower($request->action()), $noNeedLogin) || in_array('*', $noNeedLogin)) {
return false;
}
//默认为需要登录
return true;
}
/**
* 设置无需鉴权的方法名数组
* @param array $noNeedAuth
*/
public function setNoNeedAuth($noNeedAuth = [])
{
$this->_noNeedAuth = $noNeedAuth;
}
/**
* 获取无需鉴权的方法名数组
* @return array
*/
public function getNoNeedAuth()
{
return $this->_noNeedAuth;
}
/**
* 当前节点是否需要鉴权
* @param bool $noNeedAuth
* @return bool true:需要登录,false:不需要登录
*/
public function needAuth($noNeedAuth = false)
{
$noNeedAuth === false && $noNeedAuth = $this->getNoNeedAuth();
$noNeedAuth = is_array($noNeedAuth) ? $noNeedAuth : explode(',', $noNeedAuth);
//为空表示所有方法都需要鉴权,返回true
if (!$noNeedAuth) {
return true;
}
$noNeedAuth = array_map('strtolower', $noNeedAuth);
//判断当前请求的操作名是否存在于不需要鉴权的方法名数组中,如果存在,表明不需要鉴权,返回false
if (in_array(strtolower(Request::action()), $noNeedAuth) || in_array('*', $noNeedAuth)) {
return false;
}
//默认为需要鉴权
return true;
}
/**
* 获取某用户拥有的权限列表
* @param $userId int 用户ID,当为空时,为获取当前登录用户权限列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getAuthList($userId = 0)
{
$where[] = ['is_show', '=', 1];
$user = $userId ? \app\model\admin\User::findOrEmpty($userId) : UserServiceFacade::getUser();
//当前后台管理员如果是超级管理员,则拥有所有的权限列表
if ($user->is_super_manager === 1) {
$result = \app\model\admin\Menu::where($where)->select()->toArray();
} else {
//如果不是超级管理员,先查询拥有哪些角色,通过角色查询出权限节点列表
$adminUserId = $user->id;
$roleIds = \app\model\admin\role\User::where('admin_user_id', '=', $adminUserId)->column('admin_role_id');
$menuIds = \app\model\admin\menu\Role::where('admin_role_id', 'in', $roleIds)->column('admin_menu_id');
$where[] = ['id', 'in', $menuIds];
$result = \app\model\admin\Menu::where($where)->select()->toArray();
}
return $result;
}
/**
* 获取某用户是否有某节点的权限
* @param integer $userId 登录用户ID
* @param string $node 节点字符串
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function hasAuth($userId, $node)
{
if (!$userId || !$node) return false;
$authList = $this->getAuthList($userId);
$authArr = [];
foreach ($authList as $k => $v) {
$authArr[] = trim($v['rule'], '/');
}
$authArr = array_filter(array_unique($authArr));
sort($authArr);
if (in_array($node, $authArr)) {
return true;
} else {
return false;
}
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace app\service\admin;
use think\Facade;
/**
* 后台权限服务门面
* @package app\service\admin
* @method static mixed setNoNeedLogin($noNeedLogin) 设置不需要登录的方法名数组
* @method static mixed setNoNeedAuth($noNeedAuth) 设置不需要鉴权的方法名数组
* @method static mixed needLogin() 当前节点是否需要登录
* @method static mixed needAuth() 当前节点是否需要鉴权
* @method static mixed getAuthList($userId) 获取某后台管理员拥有的权限列表
* @method static mixed hasAuth($userId, $node) 某用户是否拥有某个节点的权限
*/
class AuthServiceFacade extends Facade
{
protected static function getFacadeClass()
{
return Auth::class;
}
}
+403
View File
@@ -0,0 +1,403 @@
<?php
namespace app\service\admin;
use app\model\admin\Menu;
use laytp\library\DirFile;
use laytp\library\Http;
use laytp\traits\Error;
use app\model\Migrations;
use think\facade\Config;
use think\facade\Filesystem;
/**
* 插件市场服务实现者
* Class Auth
* @package app\service\admin
*/
class Plugins
{
use Error;
protected $ids=[];
// 离线安装
public function offLineInstall()
{
if (!class_exists('ZipArchive')) {
$this->setError('PHP扩展ZipArchive没有正确安装');
return false;
}
$file = request()->file('laytpUploadFile'); // 获取上传的文件
if (!$file) {
$this->setError('上传失败,请选择需要上传的文件');
return false;
}
$fileExt = strtolower($file->getOriginalExtension());
if($fileExt != 'zip'){
$this->setError('仅允许上传zip文件');
return false;
}
$fileName = $file->getOriginalName();
$pathinfo = pathinfo($fileName);
$plugin = $pathinfo['filename'];
try{
// 将文件上传到指定目录
Filesystem::disk('local')->putFileAs('plugins', $file, $fileName );
$this->insideInstall($plugin);
}catch (\Exception $e){
$this->setError($e->getMessage());
return false;
}
return true;
}
// 安装
public function install($plugin, $laytpGwToken)
{
if (!class_exists('ZipArchive')) {
$this->setError('PHP扩展ZipArchive没有正确安装');
return false;
}
$download = $this->download($plugin, $laytpGwToken);
if(!$download){
return false;
}
$install = $this->insideInstall($plugin);
if(!$install){
return false;
}
return true;
}
// 卸载
public function unInstall($plugin)
{
$pluginDir = $this->getPluginPath($plugin) . DS;
// 删除数据库文件
$migrationsFile = DirFile::recurDir($pluginDir . 'database' . DS . 'migrations');
if($migrationsFile){
foreach($migrationsFile as $file){
$baseNameArr = explode('_', $file['baseName']);
$baseNameArr = explode('.', $baseNameArr[1]);
$migration = Migrations::where('migration_name', '=', ucfirst($baseNameArr[0]))->find();
if($migration) $migration->delete();
@unlink(root_path() . 'database' . DS . 'migrations' . DS . $file['baseName']);
}
}
// 删除菜单
$info = $this->getPluginInfo($plugin);
$menuIds = $info['menu_ids'];
if($menuIds){
Menu::destroy(function($query) use ($menuIds){
$query->where('id', 'in', explode(',', $menuIds));
});
}
// 删除public目录下的文件
$this->removePublicFile($plugin);
// 删除插件目录
DirFile::rmDirs($pluginDir);
// 修改系统插件配置文件config/plugin.php
$this->unInstallPluginConf($plugin, $info);
return true;
}
// 获取上传zip文件所在目录
public function getPluginRuntimeDir()
{
$dir = runtime_path() . 'storage' . DS . 'plugins';
DirFile::createDir($dir);
return $dir;
}
// 下载zip文件到本地
public function download($plugin, $laytpGwToken)
{
$ltVersion = request()->param('ltVersion');
$pluginVersion = request()->param('pluginVersion');
$res = Http::post(Config::get('plugin.apiUrl') . "/plugins/install", [
'plugin'=>$plugin,
'ltVersion'=>$ltVersion,
'pluginVersion'=>$pluginVersion,
], array(
CURLOPT_HTTPHEADER => array(
"token: ".$laytpGwToken
),
));
$resArr = json_decode($res, true);
if($resArr['code'] > 0 ){
$this->setError(['msg'=>$resArr['msg'],'code'=>$resArr['code']]);
return false;
}
$url = $resArr['data']['url'];
$zipSteam = Http::get($url, [], [
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_HTTPHEADER => [
'X-REQUESTED-WITH: XMLHttpRequest'
]
]);
$file = $this->getPluginRuntimeDir() . DS . $plugin . '.zip';
if(file_exists($file)){
@unlink($file);
}
if ($write = fopen($file, 'w')) {
fwrite($write, $zipSteam);
fclose($write);
}
return true;
}
// 内部安装过程
public function insideInstall($plugin)
{
try{
// 解压zip文件
$this->unzip($plugin);
// 复制database文件并执行php think migrate:run命令
$this->migrate($plugin);
// 复制静态文件
if(!function_exists('exec')){
$this->setError('php函数exec不允许执行');
return false;
}
$this->copyPublicFile($plugin);
// 生成菜单,同时将新增的菜单id写入info.ini配置文件中,便于卸载时同时删除菜单
$this->createMenu($plugin);
// 修改系统插件配置文件config/plugin.php
$this->installPluginConf($plugin);
return true;
}catch (\Exception $e){
$this->setError(['msg'=>$e->getMessage(). $e->getLine() . $e->getFile(),'code'=>3]);
return false;
}
}
/**
* 解压插件zip文件
* @param $plugin
* @return bool
* @throws \Exception
*/
public function unzip($plugin)
{
$file = $this->getPluginRuntimeDir() . DS . $plugin . '.zip';
$zip = new \ZipArchive;
if ($zip->open($file) !== TRUE) {
@unlink($file);
throw new \Exception('不能打开zip文件');
}
if(strtolower(trim($zip->getNameIndex(0),'/')) == strtolower($plugin)){
$dir = root_path() . 'plugin' . DS;
}else{
$dir = root_path() . 'plugin' . DS . $plugin . DS;
}
if (!$zip->extractTo($dir)) {
$zip->close();
@unlink($file);
throw new \Exception('不能提取zip文件');
}
$zip->close();
@unlink($file);
return true;
}
// 插件代码文件解压后,执行php run:migrate命令,安装数据库文件
public function migrate($plugin)
{
$pluginDir = $this->getPluginPath($plugin) . DS;
if(is_dir($pluginDir . 'database' . DS . 'migrations')){
DirFile::copyDirs($pluginDir . 'database' . DS . 'migrations', root_path() . 'database' . DS . 'migrations');
// 删除数据库migrations表,已经安装过的版本
$list = scandir($pluginDir . 'database' . DS . 'migrations');
$migrationNameArr = [];
foreach ($list as $value) {
$pathinfo = pathinfo($value);
if ($pathinfo['extension'] == 'php') {
$tempArr = explode('_', $pathinfo['filename']);
$migrationNameArr[] = ucfirst($tempArr[1]);
}
}
Migrations::where('migration_name', 'in', $migrationNameArr)->delete();
sleep(1);
exec('php ' . app()->getRootPath() . '\think migrate:run');
}
return true;
}
// 获取插件路径
public function getPluginPath($plugin)
{
return app()->getRootPath() . DS . 'plugin' . DS . $plugin;
}
// 获取插件信息
public function getPluginInfo($plugin)
{
$pluginPath = $this->getPluginPath($plugin);
$infoFile = $pluginPath . DS . 'info.ini';
$info = [];
if (is_file($infoFile)) {
$info = parse_ini_file($infoFile, true, INI_SCANNER_TYPED) ?: [];
}
return $info;
}
/**
* 设置插件配置信息
* @param $plugin
* @param $array
* @return bool
*/
public function setPluginInfo($plugin, $array)
{
$pluginPath = $this->getPluginPath($plugin);
$file = $pluginPath . DS . 'info.ini';
if (!isset($array['name'])) {
$this->setError("插件配置写入失败");
return false;
}
$res = array();
foreach ($array as $key => $val) {
if (is_array($val)) {
$res[] = "[$key]";
foreach ($val as $sKey => $sVal)
$res[] = "$sKey = " . (is_numeric($sVal) ? $sVal : $sVal);
} else
$res[] = "$key = " . (is_numeric($val) ? $val : $val);
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, implode("\n", $res) . "\n");
fclose($handle);
} else {
$this->setError("文件没有写入权限");
return false;
}
return true;
}
// 生成插件菜单
public function createMenu($plugin)
{
$menuFile = root_path() . 'plugin' . DS . $plugin . DS . 'menu.php';
if(!is_file($menuFile)){
return true;
}
$menus = include_once $menuFile;
$info = $this->getPluginInfo($plugin);
if(isset($info['parent_menu']) && $info['parent_menu'] === 'first'){
$firstMenuId = Menu::where(['pid' => 0, 'is_show' => 1])->order(['sort'=>'desc', 'id'=>'asc'])->value('id');
$ids = $this->createMenuIds($menus, $firstMenuId);
}else{
$ids = $this->createMenuIds($menus, 0);
}
$info['menu_ids'] = implode(',', $ids);
if(!$this->setPluginInfo($plugin, $info)) return false;
return true;
}
public function createMenuIds($menus, $pid=0)
{
foreach($menus as $menu){
$id = Menu::insertGetId([
'name' => $menu['name'],
'des' => isset($menu['des']) ? $menu['des'] : '',
'href' => isset($menu['href']) ? $menu['href'] : '',
'rule' => isset($menu['rule']) ? $menu['rule'] : '',
'is_menu' => $menu['is_menu'],
'pid' => $pid,
'icon' => isset($menu['icon']) ? $menu['icon'] : ''
]);
$this->ids[] = $id;
if(isset($menu['children'])){
self::createMenuIds($menu['children'],$id);
}
}
return $this->ids;
}
// 复制静态文件,包括html css js
public function copyPublicFile($plugin)
{
$pluginDir = $this->getPluginPath($plugin) . DS;
if(is_dir($pluginDir . 'public')){
DirFile::copyDirs($pluginDir . 'public', root_path() . 'public');
}
return true;
}
// 删除静态文件,包括html css js
public function removePublicFile($plugin)
{
$pluginDir = $this->getPluginPath($plugin) . DS;
$pluginHtmlDir = $pluginDir . 'public' . DS . 'admin' . DS . 'plugin' . DS . $plugin;
$publicHtmlDir = root_path() . 'public' . DS . 'admin' . DS . 'plugin' . DS . $plugin;
if(is_dir($pluginHtmlDir) && $publicHtmlDir){
DirFile::rmDirs($publicHtmlDir);
}
$pluginStaticDir = $pluginDir . 'public' . DS . 'static' . DS . 'plugin' . DS . $plugin;
$publicStaticDir = root_path() . 'public' . DS . 'static' . DS . 'plugin' . DS . $plugin;
if(is_dir($pluginStaticDir) && $publicStaticDir){
DirFile::rmDirs($publicStaticDir);
}
return true;
}
// 重新生成config/plugin.php文件
public function installPluginConf($plugin)
{
$pluginConf = Config::get('plugin');
$pluginConf['installed'][] = $plugin;
$pluginConf['installed'] = array_unique($pluginConf['installed']);
sort($pluginConf['installed']);
$info = $this->getPluginInfo($plugin);
if(isset($info['is_editor']) && $info['is_editor']){
$pluginConf['installedEditor'][] = $plugin;
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
sort($pluginConf['installedEditor']);
}
$fileName = root_path() . DS . 'config' . DS . 'plugin.php';
file_put_contents($fileName,"<?php\nreturn " . var_export($pluginConf,true) . ';');
return true;
}
// 重新生成config/plugin.php文件
public function unInstallPluginConf($plugin, $info)
{
$pluginConf = Config::get('plugin');
foreach($pluginConf['installed'] as $k=>$installed){
if($installed === $plugin) unset($pluginConf['installed'][$k]);
}
$pluginConf['installed'] = array_unique($pluginConf['installed']);
sort($pluginConf['installed']);
if(isset($info['is_editor']) && $info['is_editor']){
foreach($pluginConf['installedEditor'] as $k=>$installedEditor){
if($installedEditor === $plugin) unset($pluginConf['installedEditor'][$k]);
}
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
sort($pluginConf['installedEditor']);
}
$fileName = root_path() . DS . 'config' . DS . 'plugin.php';
file_put_contents($fileName,"<?php\nreturn " . var_export($pluginConf,true) . ';');
return true;
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace app\service\admin;
use think\Facade;
/**
* 插件市场服务门面
* @package app\service\admin
* @method static mixed getError() 获取错误信息
* @method static mixed offLineInstall() 离线安装
* @method static mixed unInstall($plugin) 卸载
* @method static mixed getPluginPath($plugin) 获取插件目录
* @method static mixed getPluginInfo($plugin) 获取插件信息
* @method static mixed install($plugin, $laytpGwToken) 安装插件
*/
class PluginsServiceFacade extends Facade
{
protected static function getFacadeClass()
{
return Plugins::class;
}
}
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace app\service\admin;
use laytp\library\Token;
use laytp\traits\Error;
/**
* 后台用户服务实现者
* @package app\service\admin
*/
class User
{
use Error;
protected $_user = null;//实例化的用户对象
protected $_token = null;//用户登录凭证,token
protected $_isLogin = null;//当前用户是否登录
protected $userModel = null;//用户数据模型
protected $allowFields = ['id', 'username', 'nickname', 'avatar', 'is_super_manager', 'status', 'create_time'];
protected $tokenKeepTime = 365 * 24 * 60 * 60;//Token默认有效时长,单位秒,365天
/**
* 初始化
* @param $token
* @return bool
*/
public function init($token)
{
if (!$token) {
$this->setError('token不能为空,请重新登录');
return false;
}
$data = Token::get($token);
if (!$data) {
$this->setError('token无效,请重新登录');
return false;
}
$userId = intval($data['user_id']);
if ($userId > 0) {
$user = \app\model\admin\User::with(['avatar_file'])->findOrEmpty($userId);
if (!$user) {
$this->setError('账号不存在,请重新登录');
return false;
}
//用户状态 1正常 2禁用
if ($user['status'] != 1) {
$this->setError('账号被禁用,请联系管理员');
return false;
}
$this->_user = $user;
$this->_isLogin = true;
$this->_token = $token;
return true;
} else {
$this->setError('账号不存在,请重新登录');
return false;
}
}
/**
* 退出登录
* @return bool
*/
public function logout()
{
if (!$this->_isLogin) {
$this->setError('你没有登录');
return false;
}
//设置登录标识
$this->_isLogin = false;
//删除Token
Token::delete($this->_token);
return true;
}
/**
* 获取登录用户信息
*/
public function getUserInfo()
{
$data = $this->_user->toArray();
$allowFields = $this->getAllowFields();
$userInfo = array_intersect_key($data, array_flip($allowFields));
$userInfo['avatar_file'] = $data['avatar_file'];
$userInfo = array_merge($userInfo, ['token' => $this->_token]);
return $userInfo;
}
/**
* 获取允许输出的字段
* @return array
*/
public function getAllowFields()
{
return $this->allowFields;
}
/**
* 获取User模型
* @return User
*/
public function getUser()
{
return $this->_user;
}
/**
* 判断是否登录
* @return boolean
*/
public function isLogin()
{
if ($this->_isLogin) {
return true;
}
return false;
}
/**
* 获取当前Token
* @return string
*/
public function getToken()
{
return $this->_token;
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace app\service\admin;
use think\Facade;
/**
* 后台用户服务门面
* @package app\service\admin
* @method static mixed init($token) 初始化
* @method static mixed getError() 获取错误信息
* @method static mixed logout() 退出登录
* @method static mixed getUserInfo() 获取登录用户信息
* @method static mixed getAllowFields() 获取允许展示的字段
* @method static mixed getUser() 获取User模型
* @method static mixed isLogin() 获取登录状态
* @method static mixed getToken() 获取token
*/
class UserServiceFacade extends Facade
{
protected static function getFacadeClass()
{
return User::class;
}
}
+44
View File
@@ -0,0 +1,44 @@
- 容器
- 通俗一点理解容器,我们用PHP中唯一的数据结构数组来做比方。
- 你可以直接把容器理解为一个数组
- 数组中的key是一个字符串,作为容器中类实例的标识,方便使用这个标识来调用类的实例
- 数组中的value就是一个一个类的实例
- 容器就是存储具有key-value数据结构的,用于存储标识和类实例的一个大集合
- tp6中,默认在容器中添加了很多的类实例,手册中的[系统内置绑定到容器中的类库包括]的表格中说明了标识和系统类库对应的关系
- 依赖注入
- 在容器中存入了很多key-value形式的类实例,就可以实现依赖注入。
- 比如在控制器的某个方法中,使用依赖注入的方式,参数设置一个类,其实这个类在框架进行初始化时,就已经放在容器中了
- 如果容器中不存在,容器也可以使用composer的类自动加载机制,实时的将类注入进入容器
- 服务
- 平时在编写程序的时候,我们会写很多服务,比如权限验证,用户信息,支付,手机短信,邮件等等
- 在tp6之前,我们一般就是写一个一个的类,需要用到的时候就new一下,得到服务类的实例,然后调用服务类的方法
- 现在tp6使用容器来管理所有的类,当服务类需要使用依赖注入的方式调用时,就需要把服务类注册到容器中
- tp6就提供了一个配置文件,service.php,写上哪些类需要注册到容器中
- 注册到容器中的类还可以设置一个标识,那就使用服务类的register方法,或者bind方法
- 服务不推荐使用,因为php本身语言的问题,容器的初始化是每次请求都会执行的,意味着,每次请求都会实例化所有服务类并注册进容器。服务越多,初始化消耗越大
- 门面
- 门面为容器中的动态类提供了一个静态调用接口,相比于传统的静态方法调用,带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。
laytp里面的服务,其实就是用了tp6的门面,一般由两个文件组成
- 服务具体实现者 这个类无需继承任何基类,只需要实现服务的具体方法
- 服务门面
- 编写服务门面的原因要谈到如何调用服务
- 第一种:使用new关键字,创建一个服务具体实现者的类实例,就可以调用服务的方法,这种方法比较通用,但是需要多一行new的代码,而且服务本身还要考虑是否需要实现单例
- 第二种,使用依赖注入。在控制器层可以使用此方法,调用起来也很方便,但是中间件中,不能使用依赖注入
- 第三种,编写服务门面类,可以直接使用静态方法调用服务实现者的具体实现方法。此方式代码编写方便,中间件中也可以使用,而且服务门面基类实现了单例
- 唯一要注意的是,服务门面类需要写好注释,PHPStorm编辑器的代码跟踪才能跟踪到门面类里面来,然后就可以在门面的getFacadeClass方法中继续跟踪服务的具体实现者类
- 服务的目录 /app/service
- 命名规范,以ServiceFacade结尾的就是服务门面
- 服务提供者,文件名和类名一般以Service结尾
- 举例:
- tp6的验证码就是使用的服务提供者来提供全局调用的
- vendor/topthink/think-captcha/src/CaptchaService.php
- 提供者仅需实现服务注册方法,如果服务需要做一些其他操作,可以使用服务启动方法进行操作。
- 在提供者中,服务启动方法,可以进行路由注册、验证器扩展标识,
- 服务提供者的用处
- 提供者实现了服务注册方法,就能进行依赖注入的方式调用服务
- 提供者的启动方法,服务在调用之前,就会执行的一些程序