【javascript 高级程序设计 源码】【表白神器成品+源码】【交流互动平台+源码】大大白源码_大白代码

来源:读书会小程序源码

1.屏幕取词
2.Hibernate已经落伍了吗?
3.详解Linux系统中的白源白代usr目录

大大白源码_大白代码

屏幕取词

       â€œé¼ æ ‡å±å¹•å–词”技术是在电子字典中得到广泛地应用的,如四通利方和金山词霸等软件,这个技术看似简单,其实在WINDOWS系统中实现却是非常复杂的,总的来说有两种实现方式:

        第一种:采用截获对部分GDI的API调用来实现,如TextOut,TextOutA等。

        第二种:对每个设备上下文(DC)做一分Copy,并跟踪所有修改上下文(DC)的操作。

        第二种方法更强大,但兼容性不好,而第一种方法使用的截获WindowsAPI的调用,这项技术的强大可能远远超出了您的想象,毫不夸张的说,利用WindowsAPI拦截技术,你可以改造整个操作系统,事实上很多外挂式Windows中文平台就是这么实现的!而这项技术也正是这篇文章的主题。

        截WindowsAPI的调用,具体的说来也可以分为两种方法:

        第一种方法通过直接改写WinAPI 在内存中的映像,嵌入汇编代码,使之被调用时跳转到指定的地址运行来截获;第二种方法则改写IAT(Import Address Table 输入地址表),重定向WinAPI函数的调用来实现对WinAPI的截获。

        第一种方法的实现较为繁琐,而且在Win、下面更有难度,这是因为虽然微软说WIN的API只是为了兼容性才保留下来,程序员应该尽可能地调用位的API,实际上根本就不是这样!WIN 9X内部的大部分位API经过变换调用了同名的位API,也就是说我们需要在拦截的函数中嵌入位汇编代码!

        我们将要介绍的是第二种拦截方法,这种方法在Win、和NT下面运行都比较稳定,兼容性较好。由于需要用到关于Windows虚拟内存的管理、打破进程边界墙、向应用程序的进程空间中注入代码、PE(Portable Executable)文件格式和IAT(输入地址表)等较底层的知识,所以我们先对涉及到的这些知识大概地做一个介绍,最后会给出拦截部分的关键代码。

        先说Windows虚拟内存的管理。Windows9X给每一个进程分配了4GB的地址空间,对于NT来说,这个数字是2GB,系统保留了2GB到 4GB之间的地址空间禁止进程访问,而在Win9X中,2GB到4GB这部分虚拟地址空间实际上是由所有的WIN进程所共享的,这部分地址空间加载了共享Win DLL、内存映射文件和VXD、内存管理器和文件系统码,Win9X中这部分对于每一个进程都是可见的,这也是Win9X操作系统不够健壮的原因。

        Win9X中为位操作系统保留了0到4MB的地址空间,而在4MB到2GB之间也就是Win进程私有的地址空间,由于 每个进程的地址空间都是相对独立的,也就是说,如果程序想截获其它进程中的API调用,就必须打破进程边界墙,向其它的进程中注入截获API调用的代码,这项工作我们交给钩子函数(SetWindowsHookEx)来完成,关于如何创建一个包含系统钩子的动态链接库,《电脑高手杂志》已经有过专题介绍了,这里就不赘述了。

        所有系统钩子的函数必须要在动态库里,这样的话,当进程隐式或显式调用一个动态库里的函数时,系统会把这个动态库映射到这个进程的虚拟地址空间里,这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈,也就是说动态链接库中的代码被钩子函数注入了其它GUI进程的地址空间(非GUI进程,钩子函数就无能为力了),当包含钩子的DLL注入其它进程后,就可以取得映射到这个进程虚拟内存里的各个模块(EXE和DLL)的基地址,如:

       HMODULE hmodule=GetModuleHandle(“Mypro.exe”);

        在MFC程序中,我们可以用AfxGetInstanceHandle()函数来得到模块的基地址。EXE和DLL被映射到虚拟内存空间的什么地方是由它们的基地址决定的。它们的基地址是在链接时由链接器决定的。当你新建一个Win工程时,VC++链接器使用缺省的基地址0x。可以通过链接器的BASE选项改变模块的基地址。EXE通常被映射到虚拟内存的0x处,DLL也随之有不同的基地址,通常被映射到不同进程的相同的虚拟地址空间处。

        系统将EXE和DLL原封不动映射到虚拟内存空间中,它们在内存中的结构与磁盘上的静态文件结构是一样的。即PE (Portable Executable) 文件格式。我们得到了进程模块的基地址以后,就可以根据PE文件的格式穷举这个模块的IMAGE_IMPORT_DESCRIPTOR数组,看看进程空间中是否引入了我们需要截获的函数所在的动态链接库,比如需要截获“TextOutA”,就必须检查“Gdi.dll”是否被引入了。

        说到这里,我们有必要介绍一下PE文件的格式,如右图,这是PE文件格式的大致框图,最前面是文件头,我们不必理会,从PE File Optional Header后面开始,就是文件中各个段的说明,说明后面才是真正的段数据,而实际上我们关心的只有一个段,那就是“.idata”段,这个段中包含了所有的引入函数信息,还有IAT(Import Address Table)的RVA(Relative Virtual Address)地址。

        说到这里,截获WindowsAPI的整个原理就要真相大白了。实际上所有进程对给定的API函数的调用总是通过PE文件的一个地方来转移的,这就是一个该模块(可以是EXE或DLL)的“.idata”段中的IAT输入地址表(Import Address Table)。在那里有所有本模块调用的其它DLL的函数名及地址。对其它DLL的函数调用实际上只是跳转到输入地址表,由输入地址表再跳转到DLL真正的函数入口。

        具体来说,我们将通过IMAGE_IMPORT_DESCRIPTOR数组来访问“.idata”段中引入的DLL的信息,然后通过IMAGE_THUNK_DATA数组来针对一个被引入的DLL访问该DLL中被引入的每个函数的信息,找到我们需要截获的函数的跳转地址,然后改成我们自己的函数的地址……具体的做法在后面的关键代码中会有详细的讲解。

        讲了这么多原理,现在让我们回到“鼠标屏幕取词”的专题上来。除了API函数的截获,要实现“鼠标屏幕取词”,还需要做一些其它的工作,简单的说来,可以把一个完整的取词过程归纳成以下几个步骤:

        1. 安装鼠标钩子,通过钩子函数获得鼠标消息。

        使用到的API函数:SetWindowsHookEx

        2. 得到鼠标的当前位置,向鼠标下的窗口发重画消息,让它调用系统函数重画窗口。

        使用到的API函数:WindowFromPoint,ScreenToClient,InvalidateRect

        3. 截获对系统函数的调用,取得参数,也就是我们要取的词。

        对于大多数的Windows应用程序来说,如果要取词,我们需要截获的是“Gdi.dll”中的“TextOutA”函数。

        我们先仿照TextOutA函数写一个自己的MyTextOutA函数,如:

       BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)

       {

       // 这里进行输出lpszString的处理

       // 然后调用正版的TextOutA函数

       }

        把这个函数放在安装了钩子的动态连接库中,然后调用我们最后给出的HookImportFunction函数来截获进程对TextOutA函数的调用,跳转到我们的MyTextOutA函数,完成对输出字符串的捕捉。

        HookImportFunction的用法:

       HOOKFUNCDESC hd;

       PROC pOrigFuns;

       hd.szFunc="TextOutA";

       hd.pProc=(PROC)MyTextOutA;

       HookImportFunction (AfxGetInstanceHandle(),"gdi.dll",&hd,pOrigFuns);

        下面给出了HookImportFunction的源代码,相信详尽的注释一定不会让您觉得理解截获到底是怎么实现的很难,Ok,Let’s Go:

       ///////////////////////////////////////////// Begin ///////////////////////////////////////////////////////////////

       #include <crtdbg.h>

       // 这里定义了一个产生指针的宏

       #define MakePtr(cast, ptr, AddValue) (cast)((DWORD)(ptr)+(DWORD)(AddValue))

       // 定义了HOOKFUNCDESC结构,我们用这个结构作为参数传给HookImportFunction函数

       typedef struct tag_HOOKFUNCDESC

       {

       LPCSTR szFunc; // The name of the function to hook.

       PROC pProc; // The procedure to blast in.

       } HOOKFUNCDESC , * LPHOOKFUNCDESC;

       // 这个函数监测当前系统是否是WindowNT

       BOOL IsNT();

       // 这个函数得到hModule -- 即我们需要截获的函数所在的DLL模块的引入描述符(import descriptor)

       PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule);

       // 我们的主函数

       BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule,

       LPHOOKFUNCDESC paHookFunc, PROC* paOrigFuncs)

       {

       /////////////////////// 下面的代码检测参数的有效性 ////////////////////////////

       _ASSERT(szImportModule);

       _ASSERT(!IsBadReadPtr(paHookFunc, sizeof(HOOKFUNCDESC)));

       #ifdef _DEBUG

       if (paOrigFuncs) _ASSERT(!IsBadWritePtr(paOrigFuncs, sizeof(PROC)));

       _ASSERT(paHookFunc.szFunc);

       _ASSERT(*paHookFunc.szFunc != '\0');

       _ASSERT(!IsBadCodePtr(paHookFunc.pProc));

       #endif

       if ((szImportModule == NULL) || (IsBadReadPtr(paHookFunc, sizeof(HOOKFUNCDESC))))

       {

       _ASSERT(FALSE);

       SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);

       return FALSE;

       }

       //////////////////////////////////////////////////////////////////////////////

       // 监测当前模块是否是在2GB虚拟内存空间之上

       // 这部分的地址内存是属于Win进程共享的

       if (!IsNT() && ((DWORD)hModule >= 0x))

       {

       _ASSERT(FALSE);

       SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);

       return FALSE;

       }

       // 清零

       if (paOrigFuncs) memset(paOrigFuncs, NULL, sizeof(PROC));

       // 调用GetNamedImportDescriptor()函数,来得到hModule -- 即我们需要

       // 截获的函数所在的DLL模块的引入描述符(import descriptor)

       PIMAGE_IMPORT_DESCRIPTOR pImportDesc = GetNamedImportDescriptor(hModule, szImportModule);

       if (pImportDesc == NULL)

       return FALSE; // 若为空,则模块未被当前进程所引入

       // 从DLL模块中得到原始的THUNK信息,因为pImportDesc->FirstThunk数组中的原始信息已经

       // 在应用程序引入该DLL时覆盖上了所有的引入信息,所以我们需要通过取得pImportDesc->OriginalFirstThunk

       // 指针来访问引入函数名等信息

       PIMAGE_THUNK_DATA pOrigThunk = MakePtr(PIMAGE_THUNK_DATA, hModule,

       pImportDesc->OriginalFirstThunk);

       // 从pImportDesc->FirstThunk得到IMAGE_THUNK_DATA数组的指针,由于这里在DLL被引入时已经填充了

       // 所有的引入信息,所以真正的截获实际上正是在这里进行的

       PIMAGE_THUNK_DATA pRealThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->FirstThunk);

       // 穷举IMAGE_THUNK_DATA数组,寻找我们需要截获的函数,这是最关键的部分!

       while (pOrigThunk->u1.Function)

       {

       // 只寻找那些按函数名而不是序号引入的函数

       if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG))

       {

       // 得到引入函数的函数名

       PIMAGE_IMPORT_BY_NAME pByName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule,

       pOrigThunk->u1.AddressOfData);

       // 如果函数名以NULL开始,跳过,继续下一个函数

       if ('\0' == pByName->Name[0])

       continue;

       // bDoHook用来检查是否截获成功

       BOOL bDoHook = FALSE;

       // 检查是否当前函数是我们需要截获的函数

       if ((paHookFunc.szFunc[0] == pByName->Name[0]) &&

       (strcmpi(paHookFunc.szFunc, (char*)pByName->Name) == 0))

       {

       // 找到了!

       if (paHookFunc.pProc)

       bDoHook = TRUE;

       }

       if (bDoHook)

       {

       // 我们已经找到了所要截获的函数,那么就开始动手吧

       // 首先要做的是改变这一块虚拟内存的内存保护状态,让我们可以自由存取

       MEMORY_BASIC_INFORMATION mbi_thunk;

       VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));

       _ASSERT(VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,

       PAGE_READWRITE, &mbi_thunk.Protect));

       // 保存我们所要截获的函数的正确跳转地址

       if (paOrigFuncs)

       paOrigFuncs = (PROC)pRealThunk->u1.Function;

       // 将IMAGE_THUNK_DATA数组中的函数跳转地址改写为我们自己的函数地址!

       // 以后所有进程对这个系统函数的所有调用都将成为对我们自己编写的函数的调用

       pRealThunk->u1.Function = (PDWORD)paHookFunc.pProc;

       // 操作完毕!将这一块虚拟内存改回原来的保护状态

       DWORD dwOldProtect;

       _ASSERT(VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,

       mbi_thunk.Protect, &dwOldProtect));

       SetLastError(ERROR_SUCCESS);

       return TRUE;

       }

       }

       // 访问IMAGE_THUNK_DATA数组中的下一个元素

       pOrigThunk++;

       pRealThunk++;

       }

       return TRUE;

       }

       // GetNamedImportDescriptor函数的实现

       PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule)

       {

       // 检测参数

       _ASSERT(szImportModule);

       _ASSERT(hModule);

       if ((szImportModule == NULL) || (hModule == NULL))

       {

       _ASSERT(FALSE);

       SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);

       return NULL;

       }

       // 得到Dos文件头

       PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule;

       // 检测是否MZ文件头

       if (IsBadReadPtr(pDOSHeader, sizeof(IMAGE_DOS_HEADER)) ||

       (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE))

       {

       _ASSERT(FALSE);

       SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);

       return NULL;

       }

       // 取得PE文件头

       PIMAGE_NT_HEADERS pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);

       // 检测是否PE映像文件

       if (IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) ||

       (pNTHeader->Signature != IMAGE_NT_SIGNATURE))

       {

       _ASSERT(FALSE);

       SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);

       return NULL;

       }

       // 检查PE文件的引入段(即 .idata section)

       if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)

       return NULL;

       // 得到引入段(即 .idata section)的指针

       PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader,

       pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

       // 穷举PIMAGE_IMPORT_DESCRIPTOR数组寻找我们需要截获的函数所在的模块

       while (pImportDesc->Name)

       {

       PSTR szCurrMod = MakePtr(PSTR, pDOSHeader, pImportDesc->Name);

       if (stricmp(szCurrMod, szImportModule) == 0)

       break; // 找到!中断循环

       // 下一个元素

       pImportDesc++;

       }

       // 如果没有找到,说明我们寻找的模块没有被当前的进程所引入!

       if (pImportDesc->Name == NULL)

       return NULL;

       // 返回函数所找到的模块描述符(import descriptor)

       return pImportDesc;

       }

       // IsNT()函数的实现

       BOOL IsNT()

       {

       OSVERSIONINFO stOSVI;

       memset(&stOSVI, NULL, sizeof(OSVERSIONINFO));

       stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

       BOOL bRet = GetVersionEx(&stOSVI);

       _ASSERT(TRUE == bRet);

       if (FALSE == bRet) return FALSE;

       return (VER_PLATFORM_WIN_NT == stOSVI.dwPlatformId);

       }

       /////////////////////////////////////////////// End //////////////////////////////////////////////////////////////////////

       ä¸çŸ¥é“在之前,有多少朋友尝试过去实现“鼠标屏幕取词”这项充满了挑战的技术,也只有尝试过的朋友才能体会到其间的不易,尤其在探索API函数的截获时,手头的几篇资料没有一篇是涉及到关键代码的,重要的地方都是一笔代过,MSDN更是显得苍白而无力,也不知道除了IMAGE_IMPORT_DESCRIPTOR和IMAGE_THUNK_DATA,微软还隐藏了多少秘密,好在硬着头皮还是把它给攻克了,希望这篇文章对大家能有所帮助。

Hibernate已经落伍了吗?

          在Java世界 Hibernate是最引人关注的一个话题 从Gavin King加入EJB EG 负责制订EJB 的持久层规范 到Gavin King非正式退出JDO EG 并且充满个人情绪的攻击JDO 规范 到《Hibernate in Action》的发行 再到Hibernate Alpha的发布 最后再到最近JBoss PR的发布(使用Hibernate 实现Entity Bean) 可以说这其中的每一步都引起业界的侧目

          Hibernate在不到 年的时间里 从一个不起眼的开源软件发展到今天令业界瞩目的主流O/R Mapping框架 Gavin King从一个开源软件的作者成为业界举足轻重的人物 这多少有些传奇的色彩 毕竟 单纯从技术成就而言 Hibernate不算是最有成就的Java开源框架软件 到目前为止也不是一个完美无缺的软件 从个人技术水平而言 Gavin King也不算绝顶高手

          在当前的Java持久层框架中 最流行的O/R Mappin *** 品分别是Hibernate JDO和TopLink

          自从去年Gavin King加入JBoss之后 Hibernate已经由一个民间的开源软件走上了兼容EJB EntityBean的道路 然而更加令人侧目的是 Gavin King在EJB EG中充当了一个非常重要的角色 只要对比一下EJB 的EntityBean和Hibernate 真相就会大白 虽然API接口不同 但是 EntityBean的设计理念完全来自于Hibernate

          虽然EJB 的EntityBean在相当程度上来源于Hibernate 但是毕竟是不同的API接口 因此Hibernate和EJB EntityBean究竟是怎样的一种关系 是很多人心中的疑问

       

           年四月份JBoss的Ben Wang访华期间 我曾经向Ben请教Hibernate的未来发展 他回答说 Hibernate未来将仍旧以独立的软件产品存在和发展 既可以 outside EJB container使用 同时Hibernate也将做为JBoss EntityBean Implementation 又可以inside EJB container使用 然而如何既inside 又outside 终究缺乏一个感性的认识

           月 日JBoss发布的 EJB PR揭开了答案 从Sourcefe的CVS服务器上面checkout出来源代码看一下 我们可以发现 Gavin King对Hibernate 进行了简单的封装 将EJB EntityBean API调用转换为内部Hibernate 自己的API 从而实现EJB EntityBean的兼容

          EJB 不承诺脱离容器调用 如果你想享用EJB 则必须运行在某个EJB Vendor提供的容器内 例如你使用JBoss提供的容器 那么你调用的是EntityBean API 这些调用请求会被转换为Hibernate API的调用请求 这意味着Hibernate实际上提供了两套API 一套是Hibernate原生API 另一套是兼容EJB EntityBean API 对于那些需要分布式调用支持 需要EJB容器的开发人员来说 他们选择后一套API 对于不需要EJB容器的开发人员来说 他们选择前一套 API 这就是Hibernate既定的发展策略

          今年夏天投票通过的JDO 标准从某种程度而言 并不逊色于 Hibernate当前的版本 有些功能甚至比Hibernate还要好 例如 JDO支持对类属性的lazy loading 而Hibernate要到 才支持 当前Hibernate仅仅支持类的lazy loading 实际上在去年 就已经有很多用户不断提出对类属性的lazy loading的需求 然而Gavin King当时一直不认为这个需求有添加的必要性 再例如被Gavin King形容为 可憎的 JDOQL 实际上是类SQL查询语言和对象条件查询的混合体 从功能上来说 不如HQL强大 但是比Hibernate自己的条件查询强

          不知道究竟出于什么原因 Gavin King对JDO似乎一直怀有由衷的厌恶 月 他在Hibernate的blog上面对JDO进行了毫不留情的批判 列举了JDO的种种缺点来解释为什么EJB 持久层规范没有把JDO考虑进去 然而事实上他的批判充满了对JDO的误解和偏见 例如Gavin King憎恨JDOQL丝毫没有什么特别的理由 只因为JDOQL不是一个纯粹的查询语言 而是一个混合体 这多少让人对Gavin King的风度感到遗憾 在被Solarmetric的Abe White反驳之后 同样没有风度的说 我可没有时间做这种无谓的争论 事实上每个人都认为他自己的技术是最好的……我是错了 JDO那伙人也错了 每个人都会犯错误…… (所以说人无完人!)

          JDO 规范的出台事实上构成了对Hibernate 乃至基于 Hibernate理念的EJB EntityBean的严重威胁 JDO 规范在功能上的严重缺失导致了JDO无力面对Hibernate和TopLink的竞争 然而功能基本完备的JDO 挟众多JDO Vendor商业支持的合力 同时JDO规范可以避免产品锁定在某个Vendor的优势 已经将竞争的天平拉直

          

          然而JDO 和EJB 两大商业主流标准的分裂 是大部分人 甚至包括厂商所不希望看到的 于是最终EJB 的Lead Linda DeMichiel和JDO 的Lead Craig Russell联名发表公开信 宣布了一个合并EJB 和JDO 持久层规范的计划 新的持久层规范将以JSR (EJB )的持久层规范为基础 融合JDO 的部分特性 新的持久层规范将进入J EE 之中 独立于EJB存在 既可以inside J EE容器来使用 也可以脱离J EE容器 独立的运行

          这个新的持久层框架可以说完全是一个政治的产物 EJB Vendors出于自身利益反对JDO 使得JDO没有办法成为J EE的一部分 然而标准的分裂也是大部分人更加不希望看到的 于是最终JDO成了政治斗争的牺牲品 从表面上来看 JDO和EJB EntityBean都将被新的持久层框架取代 似乎JDO并没有吃亏 但实际上JDO 标准已经成熟 部分JDO领导厂商的产品已经蓄始待发 而 EJB EntityBean还处于Early Draft 等待产品诞生至少也是一年之后的事情了 另外值得耐人寻味的是 新的持久层框架将基于当前EJB EntityBean 再结合JDO 的规范 并且将处于EJB EG的控制之下 再加入一些JDO EG的成员 因此可以看出来新的持久层框架无疑还是以EJB EG为主导进行制定的

          从长远来看 EJB 和JDO 的政治斗争对双方都有好处 长期分裂带来的后果对双方的发展都不利 然而从短期来看 JDO 确实是在这场政治斗争中败下阵来 最直接的体现就是 已经有一些JDO的用户对JDO的前景产生了动摇和迷茫 不少的JDO爱好者更是直言JDO将死

          TopLink是一个老牌的 O/R Mapping软件了 自从被Oracle收购之后 又增加了对Oracle数据库的良好支持 和对Oracle AS EntityBean的支持 Oracle提供了TopLink的图形设计环境 可以使得设计好的TopLink域模型既可以被单独用在TopLink 中 也可以被用在EJB CMP中 因此看来TopLink也走了一条和Hibernate同样策略的路

          TopLink的问题在于相比Hibernate的开源和免费的优势来说 TopLink既不开源 售价又不菲上 本来商业软件TopLink应该在技术支持和商业宣传策略上拥有足够的优势 然而Oracle公司毕竟是一个以数据库为核心产品的公司 其他的一切产品都是为了数据库销售业绩而服务的 在Oracle产品线中处于一个从属地位的TopLink 由于先天不足 只能眼睁睁看着Hibernate的日益壮大而无所作为 因此 TopLink更多的被局限在购买了Oracle数据库 并且绑定Oracle数据库的用户群体中

          J EE 的新持久层规范将毫无悬念的成为未来持久层框架的主流API 无论是Hibernate JDO 还是TopLink终将兼容这个主流商业API 在当前的这三种持久层API当中 Hibernate无疑是最有前途的 这是因为 新的持久层规范将基于EJB EntityBean规范 这意味着仍将以Hibernate的设计理念为基础

           JBoss对EJB 规范跟随的步伐非常紧密 在规范制定过程中就不断的发布参考实现产品 因此可以对对EJB 规范产生比较大的影响力

          综上所述 我们有理由对Hibernate的前途抱有强烈的信心

          最后的一个疑问是 既然J EE 的新持久层框架可以脱离J EE容器运行 那么大家不全部都去用Hibernate的后一套兼容API 而完全放弃Hibernate的原生API了吗?那么是否意味着Hibernate做为一个独立产品的使命彻底终结呢?

          对于这个问题我的看法是 J EE 的持久层规范要综合各个EJB Vendor JDO Vendor的意见 要平衡他们之间的利益得失 那么这样一个瞻前顾后的规范必然无法覆盖所有应用场合的全面需要 这不像Hibernate的原生API 可以随时根据开发人员的要求增加功能那么灵活 因此我预计Hibernate的原生API以其更加强大的功能仍然会吸引一大批人直接使用原生API 而不是兼容J EE规范的API

lishixinzhi/Article/program/Java/ky//

详解Linux系统中的usr目录

       linux 文件结构中,有一个很神奇的码大码目录 —— /usr。之前一直没有怎么关注过它,白源白代反正程序都是码大码安装在里边的,也没有什么值得追根溯源的白源白代东西。直到有一天 fedora 要简化整个文件系统体系,码大码javascript 高级程序设计 源码看到讨论才想到,白源白代usr 到底是码大码什么的缩写呢,它又是白源白代怎么来的呢?讨论中,大部分观点认为:

       1.usr 是码大码 unix system resources 的缩写;

       2.usr 是 user 的缩写;

       3.usr 是 unix software resources 的缩写。

       根据常识判断,白源白代是码大码 user 缩写的可能性不大,因为和 /home 冲突了嘛。白源白代不过是码大码 system resources 还是 software resources 的缩写还真不好说。特此查了好多东西,白源白代却发现竟然连 wikipedia 也模棱两可。/usr 是linux系统核心所在,包含了所有的共享文件。

       它是 unix 系统中最重要的目录之一,涵盖了二进制文件,各种文档,表白神器成品+源码各种头文件,x,还有各种库文件;还有诸多程序,例如 ftp,telnet 等等。

       曾经的 /usr 还是用户的家目录,存放着各种用户文件 —— 现在已经被 /home 取代了(例如 /usr/someone 已经改为 /home/someone)。

       现代的 /usr 只专门存放各种程序和数据,用户目录已经转移。虽然 /usr 名称未改,交流互动平台+源码不过其含义已经从“用户目录”变成了“unix 系统资源”目录。值得注意的是,在一些 unix 系统上,仍然把 /usr/someone 当做用户家目录,如 Minix。

       /usr 文件系统经常很大,因为所有程序安装在这里. /usr 里的所有文件一般来自Linux distribution;本地安装的程序和其他东西在/usr/local 下.这样可能在升级新版系统或新distribution时无须重新安装全部程序.

       由于/usr中的文件不和特定的计算机相关,也不会在通常使用中修改,因此可以通过网络共享这个目录(文件系统),这样,游戏源码怎么用_当管理员安装了新的软件之后,所有共享这一文件系统的计算机均可以使用新的软件。

       至此,真相大白。看来就像前一阵子的 /var/run 移到 /run 一样。

       真的是不看不知道,一看吓一跳呀。原来 linux 几经进化,好多目录的诞生和用途已经产生了根本的变化。

       /usr 目录结构

       /usr/bin : 所有可执行文件,素材vip解析源码如 gcc,firefox 等(指不包含在 /sbin 和 /bin 内的);

       /usr/include : 各种头文件,编译文件等时需要使用;

       /usr/include/”package-name” : 程序特定的头文件;

       /usr/lib : 所以可执行文件所需要的库文件;

       /usr/local : 这里主要存放那些手动安装的软件,即 不是通过“新立得”或apt-get安装的软件 。 它和/usr目录具有相类似的目录结构 。让软件包管理器来管理/usr目录,而把自定义的 脚本 (scripts)放到/usr/local目录下面,我想这应该是个不错的主意。

       /usr/XR6 : x 系统的二进制文件,库文件,文档,字体等。它不等同于 /usr 的作用,只有 x 才能调用这些库文件等,其他程序不读取或者使用。因为 linux 没有原生图形界面,而且 linux 大部分情况下是 for server 的,所以图形界面没有意义;其中 XR6 代表 version release 6;

       /usr/XR6/bin : x 的二进制文件,包含运行 x 的必须文件;

       /usr/XR6/include : x 相关的头文件;

       /usr/XR6/lib : x 库文件;

       /usr/XR6/lib/modules : x 的模块,启动时加载。缺少 video4linux, DRI and GLX 和 输入输出设备 模块,将工作不正常;

       /usr/XR6/lib/X/fonts : x font server 的字体文件;

       /usr/doc : 文档。实际是 /usr/share/doc 的软链接;

       /usr/etc : 一个极少用到的配置文件存放地;

       /usr/games : 曾经包含游戏等文件,现在很少用到;

       /usr/info : 系统相关信息,是 /usr/share/info 的软链接;

       /usr/man : man 手册,已经移至 /usr/share/man;

       /usr/sbin : 类似 /sbin,root 可以执行。但此目录不包含在环境变量 $PATH 中,它包含的程序类似于 chroot, useradd, in.tftpd and pppconfig;

       /usr/share : 它包含了各种程序间的共享文件,如字体,图标,文档等。(/usr/local 对应的目录是 /usr/loca/share);

       /usr/share/doc : 类似应用程序的 man 手册。它包含程序的说明文件,默认配置文件等;

       /usr/share/info : 不常用,已经被 man 代替;

       /usr/share/man : app 的 manual;

       /usr/share/icons : 应用程序的图标等文件,分为 png,svg 等多种格式;

       /usr/share/fonts : 字体文件,系统范围内可使用,~/.fonts 仅当前用户可用;

       /usr/src : linux 内核的源码和说明文档等;

       /usr/src/linux : linux 源代码;

       /usr/src/linux/.config : 内核编译过程产生的文件;通常由命令 “make config” , “make menuconfig” 或 “make xconfig” 执行后产生;

       /usr/src/linux/.depend, /usr/src/linux/.hdepend : “make dep” 检测编译依赖时需要的文件,由 /usr/src/linux/.config 产生;

       /usr/src/linux/COPYING : GNU license;

       /usr/src/linux/Makefile : 编译内核所需的 Makefile;

       /usr/src/linux/Rules.make : 当有多个 Makefile 时,根据它的规则执行 make;

       /usr/tmp : 已经被众多发行版抛弃的临时文件夹。

文章所属分类:时尚频道,点击进入>>