组件这个名词在百度上的定义:组件(Component)是对数据和方法的简单封装
这里不再赘述概念和定义,也不再过多纠结很多技术问题或者讨论。我们就实际组件应用关注的焦点和思考,做一个回顾,并整理Linux的so组件设计框架及逻辑。
从库的角度,大体分为静态链接库和动态链接库两大类。so就是linux下动态链接库的后缀。其特性可参考度娘:
这里以Linux系统为例,但是Windows同样适用(可能代码上稍有差异)。
我们为了解决组件的关注点,应用了动态链接库的特性,从逻辑层面可以解决业务需求。
so动态链接库:
通过组件的构造和析构作为组件初始化和去初始化机制,当然为了更好的应对优雅退出及异常场景处理,在构造函数中需要做非常多的业务/异常场景的分析和钩子函数设计。
这里针对构造、析构和接口问题进行框架介绍和范例举例:
//so_test.c
#include <stdio.h>
int Myfunc_test(void)
{
printf("........Myfunc_test in %s........\n", __FILE__);
return(0);
}
static void __attribute__((constructor)) Myfunc_init(void)
{
printf("Myfunc_init in %s\n", __FILE__);
return;
}
static void __attribute__((destructor)) Myfunc_fini(void)
{
printf("Myfunc_fini in %s\n", __FILE__);
return;
}
//so_test.h
#ifndef __SO_TEST_HEADER__
#define __SO_TEST_HEADER__
int Myfunc_test(void);
#endif /* __SO_TEST_HEADER__ */
编译方法
$ gcc -fPIC -shared -o libtestsubx.so so_test.c
#include <stdio.h>
#include "so_test.h"
int main(int argc, char** argv)
{
printf("so main\n");
Myfunc_test();
sleep(5);
printf("so main exit\n");
}
编译方法
$ gcc -g so_main.c -o so_main -L. -ltestsubx
鉴于隐式调用收到so路径的限制,因此需要更好的管理路径,测试脚本如下
#!/bin/sh
export LD_PRELOAD=${pwd}libtestsubx.so:${LD_PRELOAD}
export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH}
./so_main
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include "so_test.h"
int main(int argc, char** argv)
{
void(*pTest)();
char dir[256];
char *path = getcwd(dir, 256);
if ( path == NULL ) {
printf("Failed get current dir\n");
return -1;
}
strcat(path, "/");
strcat(path, "/libtestsubx.so");
printf("Current so is %s\n", path);
void*pdlHandle = dlopen(path, RTLD_LAZY);
if( pdlHandle == NULL ) {
printf("Failed load library\n");
return -1;
}
char* pszErr = dlerror();
if(pszErr != NULL) {
printf("%s\n", pszErr);
return -1;
}
pTest = dlsym(pdlHandle, "Myfunc_test");
pszErr = dlerror();
if( pszErr != NULL ) {
printf("%s\n", pszErr);
dlclose(pdlHandle);
return -1;
}
(*pTest)();
dlclose(pdlHandle);
return 0;
}
编译方法
$ gcc -g so_dlopen.c -o so_dlopen -L. -ldl
根据实际应用的要求,选择隐式调用和显式调用。通常来说简单设计,隐式调用更加方便和直接。
而从实际要对组件进行“1.2 组件业务关注点”这种复杂考虑,那么建议采用显式调用方法,并针对API进行管理(这里的API是指函数)。更多业务类解耦可以考虑消息API。
在大型项目开发中,需要建立主体程序框架和基于主体程序框架的业务组件设计框架,以便针对业务的组件能够通过各种API进行解耦,独立进行开发、测试。