问题:
如果打开cppcms的reference文档,在吹泡泡cms::sessions namespace下存在如下几个类:
class encryptor; // 泛型session cookies 加密接口.
class encryptor_factory; // 顾名思义,建立新加密器的接口
class session_cookies; // 使用加密的或者签名的cookies的session_api实现。
class session_dual; // session_api的客户端和服务器端存储实现
class session_sid; // 用session_storage和唯一session id存储session数据的session_api实现。
class session_server_storage //是一个允许用户实现自定义session storage(如数据库)的抽象类。
class session_storage_factory //建立session storage对象的工厂类。
但是session_cookies, session_dual, 和session_sid三个实现的接口类session_api却不在cppcms::sessions namespace下,另外,在cppcms::application调用的session()返回的session_interface类引用也同样不在namespace下。在service中定义的session_pool也不在此命名空间内。为什么呢?这几个类虽然都跟session有关系,互相之间又是如何关联的呢?
小结:
打开service.cpp浏览代码,先看构造函数service::service(int argc,char *argv[]) :
impl_(new impl::service()) { impl_->args_.assign(argv,argv+argc); //pimp idiom, args的类型vector<std::string> json::value val = load_settings(argc,argv); //读取并解析config.js中的json配置参数 impl_->settings_.reset(new json::value()); //重置 impl_->settings_->swap(val); //按照config.js的配置修改Impl的设定。 setup(); //安装service. }
再看setup成员函数
void service::setup() { impl_->cached_settings_.reset(new impl::cached_settings(settings())); impl::setup_logging(settings()); impl_->id_=0; int reactor=reactor_type(settings().get("service.reactor","default")); impl_->io_service_.reset(new io::io_service(reactor)); impl_->sig_.reset(new io::stream_socket(*impl_->io_service_)); impl_->breaker_.reset(new io::stream_socket(*impl_->io_service_)); int apps=settings().get("service.applications_pool_size",threads_no()*2); impl_->applications_pool_.reset(new cppcms::applications_pool(*this,apps)); impl_->views_pool_.reset(new cppcms::views::manager(settings())); impl_->cache_pool_.reset(new cppcms::cache_pool(settings())); impl_->session_pool_.reset(new cppcms::session_pool(*this)); if(settings().get("file_server.enable",false)) { applications_pool().mount(applications_factory<cppcms::impl::file_server>(),mount_point("")); } }
这个成员函数执行过程中,在倒数第二步重置了session_pool. 当扮演controller角色的application main函数调用app.run()函数后,cppcms后面又做了什么跟session相关的动作呢?我们且再看下run成员函数。
void service::run() { run_prepare(); //->依次调用函数generator(), forwarder(), session_pool().init(), start_acceptor(). impl::daemonizer godaemon(settings()); if(prefork()) { // prefork() 用以设置系统signal及handler return; } thread_pool(); // make sure we start it if(impl_->prefork_acceptor_.get()) impl_->prefork_acceptor_->start(); after_fork_exec(); run_acceptor(); setup_exit_handling(); run_event_loop(); }
根据上述代码,我们再继续查看session_pool.cpp代码中的init成员函数
void session_pool::init() { service &srv=*service_; if(backend_.get()) return; std::string location=srv.settings().get("session.location","none"); if((location == "client" || location=="both") && !encryptor_.get()) { ... ... } if((location == "server" || location == "both") && !storage_.get()) { ... ... } if(location == "server") { std::auto_ptr<session_api_factory> f(new sid_factory(this)); backend(f); } else if(location == "client") { std::auto_ptr<session_api_factory> f(new cookies_factory(this)); backend(f); } else if(location == "both") { unsigned limit=srv.s.ettings().get("session.client_size_limit",2048); std::auto_ptr<session_api_factory> f(new dual_factory(limit,this)); backend(f); } else if(location == "none") ; else throw cppcms_error("Unknown location"); service_->after_fork(boost::bind(&session_pool::after_fork,this)); }
不过上述代码比较冗长一些,但是还好,逻辑看起来还是比较清晰的。顺序上,大致是如下逻辑;
1. 判断是否已经有session了?如果有,返回。
2. 如果1.没有,则根据config.js中session section的配置,进行各种scenario的判断和处理;
I. session存放在client端或者both(既存放在client端也存放在server端),同时没有配置encryptor
II. session存放在server端或者both,但没有配置session storage
III. session只存放在server端,那么通过sid_factory创建session_sid
IV. session只存放在client端,那么通过cookies_factory创建session_cookies
V. session存在在both端,那么通过dual_factory创建session_dual
VI. session的location如果是none, 啥也不做。
VII. 其他情况,抛出unknown location异常。
针对scenario I, II, 还有进一步的处理,此处忽略。
从上述的各种scenario处理情况来看,逻辑上大致分三种情况,即
1. 如果存放在client端的话,必须对session存放的数据按照配置的加密算法进行加密。
2. 如果存在server端的话,server负责产生一个session id.
3. 如果存在both端的话,session_sid, session_cookies都需要被创建。
这样我们可以看出cppcms中有关session的一些端倪了。实际上,session_pool是cppcms框架中用来管理session的核心组件,session_pool中包含了三个auto_ptr,分别指向session_api_factory, encryptor_factory和session_storage_factory。session_api_factory用以创建实际操作session的类。根据不同的操作,cppcms中一共有三种session操作类,它们是session_cookies, session_sid, session_dual。session_storage_factory用以创建针对不同s媒介的storage,包含memory, cookie, database, network等。encryptor_factory主要创建加密器用以针对存储在客户端的session数据应该实施必要的加密措施。
那么上述的那三个session操作类,操作对象是什么呢?当然是session了!对,不过在cppcms里,session是被封装在session_interface中的。
之所以没有把session_api, session_interface, session_pool这三个类放在cppcms::sessions namespace下,个人认为可能是作者有意想把跟http session在框架中独立出来,放在了cppcms域中。而组成session_pool的核心组件类才被放入到cppcms::sessions域中。