美文网首页
结合源码分析QgsProviderRegistry加载Provi

结合源码分析QgsProviderRegistry加载Provi

作者: NullUser | 来源:发表于2022-06-15 15:59 被阅读0次

1.QgsProviderRegistry被调用

1)main函数

main.cpp的main函数中创建QgisApp对象

main.cpp::main()
└─new QgisApp(...)

2)QgisApp构造函数

进入QgisApp的构造函数,在构造函数内调用QgsApplication::initQgis();

main.cpp::main()
└─new QgisApp(...)
    └─QgsApplication::initQgis()

3)QgsApplication::initQgis()

在QgsApplication::initQgis()中通过单例模式创建了provider registry,同时设置provider的插件路径(此路径决定了provider插件的查找路径)

main.cpp::main()
└─new QgisApp(...)
    └─QgsApplication::initQgis()
         └─QgsProviderRegistry::instance( pluginPath() );

PS.
QgsProviderRegistry的单例实现方式:双重校验锁

static QgsProviderRegistry *sInstance = nullptr;

QgsProviderRegistry *QgsProviderRegistry::instance( const QString &pluginPath )
{
  if ( !sInstance )
  {
    static QMutex sMutex;
    const QMutexLocker locker( &sMutex );
    if ( !sInstance )
    {
      sInstance = new QgsProviderRegistry( pluginPath );
    }
  }
  return sInstance;
} // QgsProviderRegistry::instance

4)QgsProviderRegistry::init()

构造单例时进入QgsProviderRegistry的构造函数,并在构造函数内调用init()进行初始化

main.cpp::main()
└─new QgisApp(...)
    └─QgsApplication::initQgis()
         └─QgsProviderRegistry::instance( pluginPath() )
             └─init()

2.QgsProviderRegistry的init函数

1) 加载static provider

init()先加载一些static provider,如QgsMemoryProvider、QgsMeshMemoryDataProvider......,这些provider在app内实现

void QgsProviderRegistry::init()
{
  // add static providers
  Q_NOWARN_DEPRECATED_PUSH
  {
    const QgsScopedRuntimeProfile profile( QObject::tr( "Create memory layer provider" ) );
    mProviders[ QgsMemoryProvider::providerKey() ] = new QgsProviderMetadata( QgsMemoryProvider::providerKey(), QgsMemoryProvider::providerDescription(), &QgsMemoryProvider::createProvider );
  }
  {
    const QgsScopedRuntimeProfile profile( QObject::tr( "Create mesh memory layer provider" ) );
    mProviders[ QgsMeshMemoryDataProvider::providerKey() ] = new QgsProviderMetadata( QgsMeshMemoryDataProvider::providerKey(), QgsMeshMemoryDataProvider::providerDescription(), &QgsMeshMemoryDataProvider::createProvider );
  }
......

此时可发现QgsProviderRegistry内部通过mProviders维护Provider,mProviders是一个Map结构,key为字符串,用以确定provider,value为QgsProviderMetadata对象指针

class CORE_EXPORT QgsProviderRegistry
{
private:
    //! Associative container of provider metadata handles
    Providers mProviders;
}
//! Type for data provider metadata associative container
SIP_SKIP typedef std::map<QString, QgsProviderMetadata *> Providers;   

2) 从动态库以插件形式加载provider

根据provider插件路径,在该目录下搜寻动态库形式的provider插件,遍历并加载。

void QgsProviderRegistry::init()
{
......
  const auto constEntryInfoList = mLibraryDirectory.entryInfoList();
  for ( const QFileInfo &fi : constEntryInfoList )
  {
    ......
    QLibrary myLib( fi.filePath() );
    if ( !myLib.load() )
    {
      QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) );
      continue;
    }
    ......
  }
......
}

3)创建provider插件的QgsProviderMetadata对象

动态库加载成功后,解析符号(providerMetadataFactory)得到创建QgsProviderMetadata对象的函数指针,并调用该函数创建QgsProviderMetadata对象,将该对象加入mProviders。

    QFunctionPointer func = myLib.resolve( QStringLiteral( "providerMetadataFactory" ).toLatin1().data() );
    factory_function *function = reinterpret_cast< factory_function * >( cast_to_fptr( func ) );
    if ( function )
    {
      QgsProviderMetadata *meta = function();
      if ( meta )
      {
        if ( findMetadata_( mProviders, meta->key() ) )
        {
          QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (key %2 already registered)" ).arg( myLib.fileName() ).arg( meta->key() ) );
          delete meta;
          continue;
        }
        // add this provider to the provider map
        mProviders[meta->key()] = meta;
        libraryLoaded = true;
      }
    }
    else
    {......}

4) 初始化每个provider

将providers加载完后,开始遍历mProviders,初始化每个provider。
从QgsProviderMetadata对象中获取file fileters,之后调用QgsProviderMetadata的initProvider()

  // now initialize all providers
  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
  {
    const QString &key = it->first;

    const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize %1" ).arg( key ) );

    QgsProviderMetadata *meta = it->second;

    // now get vector file filters, if any
    const QString fileVectorFilters = meta->filters( QgsProviderMetadata::FilterType::FilterVector );
    if ( !fileVectorFilters.isEmpty() )
    {
      mVectorFileFilters += fileVectorFilters;
      QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file filters)" ).arg( key ).arg( fileVectorFilters.split( ";;" ).count() ), 2 );
    }

    // now get raster file filters, if any
    const QString fileRasterFilters = meta->filters( QgsProviderMetadata::FilterType::FilterRaster );
    if ( !fileRasterFilters.isEmpty() )
    {
      QgsDebugMsgLevel( "raster filters: " + fileRasterFilters, 2 );
      mRasterFileFilters += fileRasterFilters;
      QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file filters)" ).arg( key ).arg( fileRasterFilters.split( ";;" ).count() ), 2 );
    }
......
    // call initProvider() - allows provider to register its services to QGIS
    meta->initProvider();
  }

至此,Data Provider加载完毕

PS.
1)QgsProviderRegistry::createProvider()可以根据key创建provider对象,其通过key在mProviders中得到QgsProviderMetadata对象,再调用QgsProviderMetadata的createProvider得到具体的Provider实例

/* Copied from QgsVectorLayer::setDataProvider
 *  TODO: Make it work in the generic environment
 *
 *  TODO: Is this class really the best place to put a data provider loader?
 *        It seems more sensible to provide the code in one place rather than
 *        in qgsrasterlayer, qgsvectorlayer, serversourceselect, etc.
 */
QgsDataProvider *QgsProviderRegistry::createProvider( QString const &providerKey, QString const &dataSource,
    const QgsDataProvider::ProviderOptions &options,
    QgsDataProvider::ReadFlags flags )
{
  // XXX should I check for and possibly delete any pre-existing providers?
  // XXX How often will that scenario occur?

  QgsProviderMetadata *metadata = findMetadata_( mProviders, providerKey );
  if ( !metadata )
  {
    QgsMessageLog::logMessage( QObject::tr( "Invalid data provider %1" ).arg( providerKey ) );
    return nullptr;
  }

  return metadata->createProvider( dataSource, options, flags );
}

2) QgsProviderRegistry::registerProvider()可以注册新的providerMetadata

bool QgsProviderRegistry::registerProvider( QgsProviderMetadata *providerMetadata )
{
  if ( providerMetadata )
  {
    if ( mProviders.find( providerMetadata->key() ) == mProviders.end() )
    {
      mProviders[ providerMetadata->key() ] = providerMetadata;
      return true;
    }
    else
    {
      QgsDebugMsgLevel( QStringLiteral( "Cannot register provider metadata: a provider with the same key (%1) was already registered!" ).arg( providerMetadata->key() ), 2 );
    }
  }
  else
  {
    QgsDebugMsgLevel( QStringLiteral( "Trying to register a null metadata provider!" ), 2 );
  }
  return false;
}

相关文章

网友评论

      本文标题:结合源码分析QgsProviderRegistry加载Provi

      本文链接:https://www.haomeiwen.com/subject/wydxvrtx.html