版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 Webx框架初始化解析前言:对整个webx框架的初始化进行了全面的分析,webx是怎么一步一步的初始化的,组件与组件时间如何相互通信,web层怎么能够方便的拿到service的东西,service的资源存在什么地方;外部程序怎样拿到webxcontroller的实例;又怎样保证car与car之间的独立,car与car之间又是怎么共享资源的,configration在整个环境是怎么起到核心作用的;希望这样的文章会对大家有所帮助;主要是分析wex框架的内部初始化情况,和结构分析;(1):com.alibaba.webx.WebxControllerServlet为整个系统的门面,初始化工作也在这
2、里进行; web.xml里面:michael已经说的很清楚webx主控制器;<!- Webx主控制器。 -><servlet-name>WebxController</servlet-name><servlet-class>com.alibaba.webx.WebxControllerServlet</servlet-class>WebxControllerServlet继承com.alibaba.webx.controller.AbstractWebxControllerServlet;AbstractWebxControllerS
3、ervlet继承自HttpServlet;容器启动的时候,因为WebxController的启动状态是<load-on-startup>1</load-on-startup>,所以直接执行WebxControllerServlet按照servlet的规范首先执行init();WebxControllerServlet直接执行父类AbstractWebxControllerServlet的init();public void init() throws ServletException try configure();("WebxControll
4、er: init() Ready to Rumble!"); catch (Exception e) log.error("WebxController: init() failed", e);/ 这个异常将被servlet engine记录到servlet log中。UnavailableException ue = new UnavailableException("WebxController: init() failed: " + e.getMessage();ue.initCause(e);throw ue; 以上又是一个比较经典的模
5、板应用,init()方法里面执行 configure()方法,但是AbstractWebxControllerServlet定义的configure十一个抽象方法:protected abstract void configure() throws WebxInitializationException;并且由子类实现,所以直接执行子类的configure();具体业务逻辑子类化;1 / 16WebxControllerServlet的configure()方法中主要进行两个操作,一初始化WebxController,二将相关的servletConfig对象放到ServletContext中;
6、WebxControllerServlet中属性 private WebxController controller;光看名字就知道十一个比较重要的对象;所以时刻要注意它;分析configure():protected void configure() throws WebxInitializationException controller = WebxUtil.getWebxController(getServletContext();if (controller = null) WebxLoader loader = new WebxLoader(log, getServletConte
7、xt(), getServletConfig();loader.configure();controller = loader;/ 将servletConfig放在servletContext中,供rundata filter使用。getServletContext().setAttribute(WEBX_CONTROLLER_SERVLET_CONFIG_KEY, getServletConfig();这里首先用WebxUtil工具类根据ServletContex对象来初始化controller;调用WebxUtil的public static WebxController getWebxC
8、ontroller(ServletContext context);请看具体方法: public static WebxController getWebxController(ServletContext context) WebxController controller = null;try Reference holder = (Reference) context.getAttribute(WEBX_CONTROLLER_KEY);/context里面并没有这个属性,这里拿出来应该是空的;controller = (WebxController) holder.get(); catc
9、h (ClassCastException e) catch (NullPointerException e) return controller;这里返回的controller应该是空的,因为context里面没有注入“webx.controller”属性;接下来应该执行: WebxLoader loader = new WebxLoader(log, getServletContext(), getServletConfig();WebxLoader 实现了 com.alibaba.webx.controller.WebxController和com.alibaba.webx.WebxCo
10、nstantcom.alibaba.webx.controller.WebxController是webx框架的核心调度者,是mvc框架的入口,它里面包含了获取大量资源的方法,需要用的上下文对象都在接口里面提供了的;例如可以通过接口拿到:ServletContext,ServiceManager(service管理器),Scheme(scheme方案初始化配置的方案),RunDataService(RunData服务),ThreadContextService(线程范围的singleton服务),WebxComponent等信息; com.alibaba.webx.WebxConstant包含
11、一些配置信息,关于webxfreamwork的常量定义;现在我们应该看一下实现类是怎么的结构,以及它是怎样工作的;com.alibaba.webx.WebxLoader首先通过构造函数进行初始化,传入日志对象,servlet上下文对象,servletConfig对象;WebxLoader loader = new WebxLoader(log, getServletContext(), getServletConfig();loader 初始化成功之后,执行 loader.configure();这一步是初始化了webx的所有配置;接下来可能要花大量的篇幅讲解很多初始化工作虽然有点枯燥;(2)
12、真正的controller是怎样产生的:在这里要注意看注释的编号对应下面的具体解释;WebxLoader的configure() public void configure() throws WebxInitializationException /*(一)创建日志输出路径,看后面的注解*/File loggingRoot = configureLoggingRoot(); /*(二)初始化 WebappBootstrapResourceLoaderService *WebappBootstrapResourceLoaderService resourceLoader = new Webapp
13、BootstrapResourceLoaderService(servletContext);/ 在配置文件中可以使用如下变量:/ $loggingRoot/ $server.host/ $server.addr/ 以及所有System.getProperties()中的变量Properties props = new Properties(System.getProperties(); /*(三)为配置log4j,取出相关属性*/props.setProperty(LOGGING_ROOT_KEY, loggingRoot.getAbsolutePath();props.setPropert
14、y(LOCAL_HOST_KEY, SystemUtil.getHostInfo().getName();props.setProperty(LOCAL_ADDRESS_KEY, SystemUtil.getHostInfo().getAddress();/*(四) 配置log4j日志系统。*/configureLog4j(resourceLoader, props);/ 现在,logging系统应该已经可以工作了。("=");("Logging root is " + loggingRoot);/*(五)取得scheme
15、的实例*/scheme = configureScheme(resourceLoader);/*(六)取得规格化的servletPaths*/servletPaths = configureServletPaths();/*(七)取得webx配置文件*/Configuration configuration = configureWebx(resourceLoader, props, scheme);/*(八)设置默认的services和配置项*/scheme.applyDefaultConfiguration(resourceLoader, configuration, props);if
16、(log.isDebugEnabled() log.debug("WebxController initialized with configuration: n"+ (ConfigurationUtil.list(configuration);/*(九)初始化service manager*/serviceManager = configureServiceManager(resourceLoader, configuration, scheme);/*(十)其它有关WebxController配置*/configureWebxController();/*(十一)如果指
17、定了initAllServices,则强制初始化所有services*/configureAllServices(); 注解:(一)创建日志输出路径的目录,这里有三种策率,第一种是默认策率,首先会取你的user.home,我的user.home是:C:Documents and Settingsliangkuan,然后用user.home+/.webx+ServletName+/logs,最终中生成的路径是C:Documents and Settingsliangkuan.webxWebxControllerlogs+log4j.xml中配置的路径变量。以我本机为例;但是构建目录的时候首先会去
18、寻找servletConfig里面关于日志的配置参数,来决定路径,如果在servletConfig中没有找到的话,会去servletContext里面找配置参数,如果两者都没有找到就会直接用第一种默认策率来作为日志输出路径,相当灵活;以我的环境为例,因为我的servlet里面配置了 <init-param><param-name>loggingRoot</param-name><param-value>$fortuna_loggingRoot</param-value><!-这个参数是会在perty文件里面注入的
19、-></init-param>所以直接就会在servletConfig里面找;实现用到的相关类和:WebxLoader.configureLoggingRoot(),.findInitParameter(),mon.lang.SystemUtil的getHomeDir();(二)初始化WebappBootstrapResourceLoaderService 简单讲下WebappBootstrapResourceLoaderService 的结构WebappBootstrapResourceLoaderService 继承com.alibaba.service.resource
20、.BootstrapResourceLoaderServiceBootstrapResourceLoaderService实现com.alibaba.service.resourceResourceLoaderService,com.alibaba.service.MultiInstance;(实现它可以有多个实例)这个初始化操作只做了3个事情: 1:执行父类的非缺省构造函数,进本上什么都没有做;2:setLoggerReady(false),设置日志并没有准备好;3:传入servletContext属性;this.servletContext = servletContext;这是一个功能强
21、大的资源装载器;可以读取各种资源,例如url,file等;这里的资源装载器主要是针对web应用的资源装载器实例;(三)将和log4j相关的属性装入资源文件;LOGGING_ROOT_KEY对应的是日志输出的地址,LOCAL_HOST_KEY对应的是主机名,LOCAL_ADDRESS_KEY对应的是ip地址;都是通过InetAddress取出地址相关属性的,对这个些类不熟悉可以去看一下网络编程;在SystemUtil里面使用了几个静态内部类,并且构造函数都是私有的,主要是防止外面直接创建;(四)配置log4j应用configureLog4j(resourceLoader, props);这里传入
22、了资源装载器,和相关的资源文件;首先要取出log4j配置文件的路径,这里还是三种策率:(1)如果servletConfig里面有配置文件的引用路径优先考虑;(2)如果servletConfig里面没有直接在servletContext里面寻找;(3)如果servletContext里面也不能找到直接用缺省配置/WEB-INF/log4j.xml;接下来把路径生成相关的url对象;然后把文件取出来;这里对log4j的配置文件有两种解析方式,如果配置文件名为*.xml,则使用DOMConfigurator,否则使用PropertyConfigurator。现在log4j可以工作了所以进行下面操作
23、resourceLoader.setLoggerReady(true);现在打日志就没有问题了;(五)取得Scheme的实例 首先取得schemeName 先在servletConfig里面找如果没有去servletContext 里面找如果都没有找到暂时为turbine;构造一个名为webx.scheme.turbine的serviceId,这里的serviceId是一个文件的名字;这个文件里面存有一条信息com.alibaba.turbine.scheme.TurbineScheme,从这里应该看出来这是一个类的全名,并且可能是Scheme的实现类;接下来ClassLoaderUtil来装
24、载这个类,ClassLoaderUtil.loadServiceClass(serviceId)这个方法指定了当前线程的类装载器来装载这个类;在这里构造了一个完整的路径名:META-INF/services/webx/scheme/turbine,并且用当前的类装载器的getResource()方法把文件路径转换成url,然后直接把输入流打开;得到一个完整类名,并且用当前类装载器把com.alibaba.turbine.scheme.TurbineScheme装载;个人觉得这样的实现有点麻烦;类装载之后实例化com.alibaba.turbine.scheme.TurbineScheme;关于
25、TurbineScheme Michael在注释中写到经典的webx方案,可见它的重要性,在后面使用到它的地方将为大家介绍;(六)取得 取得web.xml中定义的servlet paths,并规格化之,让我们拿出的请求路径更加有规律;这里会在servletConfig,servletContext 去找webx.servlet.paths如果找不到缺省为空字符串;根据我这里的上下文路径这里没有这个参数;(七)Configuration配置对象的接口,Configuration configuration = configureWebx(resourceLoader, props, scheme
26、);这里要去找一个webxConfiguration的配置路径,首先在servletConfig,servletContext去找初始化参数webx.configuration,如果都没有找到的话使用缺省值 webxConfiguration=/WEB-INF/webx.xml而在当前系统中用的是缺省配置;用web资源装载器得到/WEB-INF/webx.xml对应的url;从这个配置文件的名称应该可以看出这里拉出了webx初始化的开端;接下来读取webx配置文件,将配置文件映射为Configuration对象,接下来会在servletConfig,servletContext中去找参数web
27、x.configuration.loader.class如果找不到的话就以默认值com.alibaba.webx.configuration.WebxConfigurationLoader为使用类;WebxConfigurationLoader调用了JellyDigester的parse();这里声明了一个内部类 private class DefaultJellyContext extends JellyContext configuration 最终是通过Jelly引擎解析出来的;Jelly是一种基于java的脚本引擎,提供了解析xml的功能,它还具有比较强的动态特性;接下来在web.xm
28、l中取出ponents,这里是在servletContext中取到的,取出了六个组件auction, member, mytaobao, common, shop, message并且为每一个组件也就是car包分配一个资源装载器的实例;实现代码如下:ResourceLoaderService componentResourceLoader = (ResourceLoaderService) resourceLoader.getInstance(componentName);根据配置将每一个组件的配置文件转换成Configuration,并且和主要的Configuration对象进行合并,具体实
29、现代码如下:car包下的Configuration合并到总的Configuration时,key全部变为car包的componentname+key值;public static void loadComponent(Configuration configuration, String componentName,String className, URL url, Map properties) throws DigesterException Configuration componentConfiguration = load(className, url, properties);/
30、 将componentName加入到services.instances中,确保不重复。if(!configuration.getList(ServiceManager.SERVICE_INSTANCES_KEY).contains(componentName) configuration.addProperty(ServiceManager.SERVICE_INSTANCES_KEY, componentName);/ 将component配置加入到主配置中。ConfigurationUtil.merge(configuration, componentConfiguration, comp
31、onentName);(八):调用com.alibaba.turbine.scheme.TurbineScheme的applyDefaultConfiguration()方法;这一步主要是初始化webx的默认配置;将相关配置文件里面配置的信息加入到Configuration中;1:首先将webx-default.xml中的配置合并到总的configuration对象中,具体步骤如下:用web资源装载器寻找/WEB-INF/webx-default.xml如果这个文件存在,生成对应于/WEB-INF/webx-default.xml的Configuration;生成Configuration都是
32、用的Jelly来解析xml生成的Configuration对象;第一步将configuration对象里面标记为services的配置信息读取出来,根据configuration的规则,只搜索根目录下面一级的services标记例如:<configuration><services><service name="RunDataService" class="com.alibaba.webx.service.rundata.DefaultRunDataService"><property name="re
33、quest.buffered.class"value="com.alibaba.webx.request.context.buffered.BufferedRequestContextFactory"/> </service><service name="PullService" class="com.alibaba.service.pull.DefaultPullService"><property name="tool.global"><property
34、 name="util" value="com.alibaba.service.pull.LangToolSet"/></property></service></services><instance name="component"><services><service name="liuzh" class="com.alibaba.webx.service.rundata.DefaultRunDataService"&g
35、t;<property name="request.buffered.class"value="com.alibaba.webx.request.context.buffered.BufferedRequestContextFactory"/> </service><service name="liangkuan" class="com.alibaba.webx.service.rundata.DefaultRunDataService"/></services>&l
36、t;/instance></configuration>根据上面例子取出来的是RunDataService,PullService,把这些值放到set里面;然后迭代这个set对象,以services为前缀,set里面取出的值;拼成的值类似于services.RunDataService最终以拼装的值为key在defaultConfiguration将相关属性取出,全部合并到总的Configuration中;在这里如果总的Configuration里面的配置和缺省Configuration的配置的key一样的话,忽略缺省Configuration的配置,不进行合并;在webx框
37、架有一个优先级,默认是以webx-defaut.xml的配置为准,如果webx.xml的配置和webx-defaut.xml的配置相同以webx.xml为准;各car包下面的配置不会和以上两个文件的配置产生冲突;2:将缺省对象中key为component.services对应的配置信息读取出来;以上面的配置文件信息为例,根据解析,最终得到一个set,这个set里面包含的数据是(liuzh,liangkuan);循环set 以liuzh为例拼装成component.services.liuzh,并且将defaultConfiguration对应的值取出来,组合到总的Configuration中;
38、这里添加的key的规则是instanceName + "." + serviceKey + "." + defaultKey;参见具体代码:Configuration defaultConfiguration, String serviceName, boolean isSubInstance) StringserviceKey = ServiceManager.SERVICE_PREFIX + "." + serviceName;boolean standalone = true;if (isSubInstance) / 如果isS
39、ubInstance,表示对每个instance设置默认值。/ 将instance.services.ServiceName.*设置到每个instanceName.services.ServiceName中for (Iterator i = configuration.getList(ServiceManager.SERVICE_INSTANCES_KEY).iterator(); i.hasNext();) standalone = false;StringinstanceName= (String) i.next();Configuration serviceConfiguration =
40、 defaultConfiguration.subset(WEBX_CONFIGURATION_DEFAULT_INSTANCE+ "." + serviceKey);for (Iterator keys = serviceConfiguration.getKeys(); keys.hasNext();) String defaultKey = (String) keys.next();String key = instanceName + "." + serviceKey + "." + defaultKey;if (!config
41、uration.containsKey(key) configuration.addProperty(key, serviceConfiguration.getProperty(defaultKey); if (log.isDebugEnabled() log.debug("Added default configuration for service " + serviceName + "."+ instanceName);defaultConfiguration = defaultConfiguration.subset(WEBX_CONFIGURA
42、TION_DEFAULT_INSTANCE);3:加入其它非service的默认主配置:main-instance,加入其它非service的默认配置:sub-instances。4:将/classpath/com/alibaba/turbine/scheme/webx-turbine-default.xml的配置信息合并到总的Configuration;这个配置文件的优先级是最低的,如果前面没有配置和webx-turbine-default.xml相同的配置,将使用webx-turbine-default.xml里面配置的服务;5:加载/classpath/com/alibaba/webx/
43、scheme/webx-default.xml配置的信息到总的Configuration里面了;接下来组合一个keyservices.ThreadContextService.factory.default 做了下面操作;if (!configuration.getList(key).contains(RunDataObjectFactory.class.getName() configuration.addProperty(key, RunDataObjectFactory.class.getName();(九):初始化ServiceManager第一步找到ServiceManager的默认
44、实现类首先会在servletconfig里面寻找参数名为service.manager.class对应的值,如果没有找到去servletcontext里面去找,如果都没有找到以com.alibaba.webx.service.DefaultWebxServiceManager作为ServiceManager的实现类DefaultServiceManager是DefaultWebxServiceManager的父类;得到ServiceManager的实例以后把资源装载,和总的configration注入到manager中,让ServiceManager可以方便调用这些属性;接下来调用manage
45、r的init(),实际上是调用的DefaultServiceManager的init方法;首先调用initMapping();通过 configuration.getStringArray(services.instances)取出一个admin, member, auction, auxiliary, crm, support, product数组;这个数组里面存储的是所有的car的名字,根据数组长度循环,configuration.subset(instanceName)取出每个car下面的configuration然后以实例名为key,具体car包下的configration为value
46、放入map中,这样就把每个car包下的配置独立开来了;接下来找出每一个service的名字并且根据为每一个service配置一个初始化一个ServiceInstance,并且把每一个service对应的configration 注入到ServiceInstance中,这样每个service可以方便的找到属于自己的configration;然后将每一个ServiceInstance 以instancekey为key ServiceInstance为value放入一个map中,让ServiceManager以后可以通过相关key轻松拿到对应service的所有信息;instancekey的构造规则
47、,如果是主配置的话直接是service的名字,如果是car下面的配置的话为car的名字加上service的名字下一步为初始化resource loader services;这里可以分析下怎么取到service的,一般是调用manager的getService(String serviceName, String instanceName)首先根据serviceName和instanceName取得相关service的ServiceInstance 对象;如果这里不是car包里面的service第二个参数传null;这里manager把serviceName,instanceName组合成in
48、stancekey给据这个key在map里面取出ServiceInstance;拿到ServiceInstance的实例之后,调用manager.initService(ServiceInstance,false)ServiceInstance是DefaultServiceManager的一个内部类;这里实际上是调用的ServiceInstance的getInstance()方法,因为ServiceInstance正好对应一个service;getInstance()方法是一个同步方法,防止不同的线程都在初始化ServiceInstance,这样保证了ServiceInstance,首先判断
49、ServiceInstance里面的service属性是否为空的,如果service已经初始化了直接返回service的实例,所有我们自定义的service是继承于Service接口的;这里避免了反复初始化service,让我们拿到的service都是同一个实例;接下来在service对应的configration中把当前service对应的calssname取出来;这里在得实例话service的时候有多种策率,如果是主配置,直接拿到class然后执行newInstance();在这里实现了service的单例和多例;得到service的实例以后执行service的init(),将Servic
50、eInstance参数传给init(),这样每个service可以方便的拿到自己的实例;最后执行了initServices();这一步是将需要在启动容器初始化的service进行初始化;首先取出所有的service的名字,和所有car上下文的名字分别放在两个数组里面循环这个装有所有的service名称的serviceNames数组,分别取出每一个servicename对应的instance, 取出对应主配置的ServiceInstance用getServiceInstance(serviceName, null);取出对应car下面的service的ServiceInstance取出car下面
51、的ServiceInstance第二个参数不能为空应该为对应car实例的名字;取出了ServiceInstance之后需要判断当前ServiceInstance实例对应的configration的EarlyInit属性是否为true如果为true说明需要初始化,执行 initService(ServiceInstance, true); 进入方法以后先拿到具体的service的实例, 获取service实例还是运用的ServiceInstance的方法getInstance();如果service已经初始化了 ,将不进行初始化;执行初始化只需要调用service的init(instance)方法;一般的service里面没有这个方法,这样可以直接调用GenericService的init(instance)然后回调子类的init();这种调用模式可以利用GenericService的在每一个ServiceInstance里面有一个Service instance,如果service已经实例化了之后直接可以取出来不用再次实例化service;所有需要初始化的service初始化完
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- HY/T 0419-2024海岸带综合保护与利用规划编制技术指南
- 烟台理工学院《交际韩语》2022-2023学年第一学期期末试卷
- 烟台大学《算法与数据结构》2021-2022学年第一学期期末试卷
- 创客教育在秋季的实施方案计划
- 许昌学院《环境色彩设计》2022-2023学年第一学期期末试卷
- 二年级数学计算题专项练习1000题汇编
- 互动式阅读与书籍推广活动计划
- 提升公司财务管理效率的方法计划
- 电商物流分拣协议三篇
- 校内外实习与见习安排计划
- 框架结构-多层框架结构布置
- 尿毒症预防科普
- 直播翡翠行业现状分析
- 预防小火亡人主题班会
- 小学语文教学中的跨学科融合
- 唐山市大学生女子篮球活动开展现状的调查研究开题报告
- 中药材种植可行性研究报告三篇
- 肛瘘LIFT术式介绍
- 通过《古文观止》选读了解古代文学的社会功能与价值
- GB/T 43575-2023区块链和分布式记账技术系统测试规范
- 幼儿园儿歌教学PPT优质课件
评论
0/150
提交评论