[本文基於odoo9源碼編寫]
odoo包含的服務有
- db
- object
- report
- workflow
- web[wsgi]
Odoo以wsgi 規范提供Web及Web服務db/object/report,而workflow則包含在model里面,以create[delete|redirect|signal|step]_workflow() 提供服務。Odoo9之后為了保持兼容性,還是保持了舊模式,在 openerp/netsvc.py 定義為 LocalService,提供 workflow 和 report 服務
openerp/cli/main() 函數為odoo的入口, 定義在 openerp/cli/command.py,此函數根據cli命令帶的參數 判斷運行哪個命令, 命令可能是
- deploy
- scaffold
- server
- shell
- start
如果不給出 command,則使用 默認,即server.
啟動前准備工作
- 檢查odoo用戶,不可以是 root
- 實例化配置文件
- 檢查pg用戶,不可以是postgres
- 報告配置情況
- 檢查是否設置 preload database,如果有,則創建空數據庫
- 創建 pid 文件
- 啟動 openerp.service.server
openerp.service.server啟動過程
- 定義全局變量 server
- 裝載 全服務器模塊 load_server_wide_modules(),默認是 web 和 web_kanban,可以通過 server_wide_modules 配置項設置更多的 預裝載模塊。 運行 openerp.modules.module.load_openerp_module() 裝載web 和web_kanban 模塊。此時,僅僅將這些模塊當作 pyton 模塊處理,並不執行任何的 ORM過程
- 根據 configuration 調用對應的服務器,odoo支持3種模式
- GeventServer
- PreforkServer,會調用 geventServer 作為longpolling 的服務端
- ThreadedServer
- 如果設置了 workers 參數, 則是 preforkserver,默認是 threadserver。然后根據配置 執行RegistryManager.new() 裝載 preload 指定的數據庫以及指定的模塊; 如果沒有指定preload,則在 第一個用戶訪問該odoo數據庫時,裝載odoo模塊。 odoo實例為每個數據庫維護一個 registry,用來維護模塊注冊。使用RegistryManager 管理 registry,在 new()時, 使用openerp.modules.load_modules()加載odoo模塊; 此時,不僅將odoo模塊作為Python模塊導入, 並執行ORM過程。
- 啟動wsgi 應用程序,調用 wsgi_xmlrpc() 和 openerp.http.root 這2個handler。 如果啟動odoo時沒有指定preload,則在第一次訪問 wsgi root時,通過 ir_http = request.registry['ir.http'] 嘗試進行 odoo模塊裝載。
裝載odoo模塊以及ModelClass構建
openerp.modules.load_modules() 定義在 py文件 openerp\modules\loading.py
步驟
- 初始化系統路徑
- 檢查數據庫是否初始化,否則 初始化數據庫,使用 openerp\addons\base\base.sql
- 初始化注冊表registry
- 加載base 模塊,初始化 模塊依賴圖 graph,將base 添加到 圖,執行 load_module_graph() 裝載 base 模塊,在注冊表設置模型,裝載語言,標記其他需要裝載和升級的模塊。
- load_module_graph() 過程如下, 初始化 注冊表 和遷移管理器,執行pre 遷移腳本 ,以及odoo模塊定義的 pre_init_hook指令,導入odoo模塊,將模塊里面定義的Model 更新 models.MetaModel.module_to_models[ ],使用 registry.load() 加載 odoo 模塊,執行模塊定義的 init 或者 update 指令,執行 post遷移腳本,更新翻譯,更新注冊表,執行odoo模塊定義的 post_init_hook指令,驗證視圖, 裝載演示數據,更新注冊表。
- registry.load() 首先導入 models.py, 然后 遍歷 models.MetaModel.module_to_models[ ] 登記的 python class,然后執行 models.BaseModel._build_model() 基於 python class 動態 建立 oodo model class, odoo model class 將 按照 graph 里面的依賴順序,依次繼承 python class 構建 odoo model class. 例如, <class 'openerp.addons.stock.product.product_template'> 在 ORM 時, 將通過 繼承關系遍歷出 全部的 父類【inherit[s]】,再加上它自己 ,例如 <type 'list'>: [<class 'openerp.addons.stock.product.product_template'>, <class 'openerp.addons.sale.sale.ProductTemplate'>, <class 'openerp.addons.account.models.product.ProductTemplate'>, <class 'openerp.addons.product.product.product_template'>, <class 'openerp.addons.mail.models.mail_thread.MailThread'>], 然后 基於這些 基類, 使用 type() 構建出 odoo model class. 【<class 'openerp.api.product.template'> 】 和 odoo model 【 template: product.template 】
- 數據持久化部分, 待更 【 挖坑 :) 】
- 執行 load_marked_modules() 裝載 其他已安裝、或者要升級/移除的模塊,此時會查詢 ir_module_module, 讀取需要執行 裝載動作的 模塊, 並加入到 depends graph 里面, 然后 再次 執行 load_module_graph()
- 完成安裝並執行清理動作
- 其他步驟