结合源码分析QgsProviderRegistry加载Provi
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;
}