Your SlideShare is downloading. ×
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Exodus2 大局观
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Exodus2 大局观

1,154

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,154
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Spring2.5 整合了 AspectJ6 ,根据动态生字节码方式支持字段等其他的连接点
  • 杨亮:能不能把 BeanFactoryService 也实现 MultiInstance 接口,让 car 的每个 BeanFactoryService 实例都引用 main 的 BeanFactoryService 的实例 阿甘:一些全局的 Service 比如 RunDataService 会依赖其他 Service ,所以全局会设置很多 Service
  • 宝宝意思是 service 容器并没有实现 service 之间的注入功能,比如: ServiceA 依赖于 ServiceB 的,需要通过 ServiceManager.getService(ServiceB.class) 。但 ModuleLoaderService 利用 ModuleFactory 实现对 Module 的依赖注入功能
  • 缓冲了整个页面。等页面中全部元素都渲染完成,再开始向客户端 response 。 如果遇到一个很大的页面,那么应该是这个 Screen 设计的不合理。假设真有这种需要,那么应该关闭 buffer ,要特殊对待。
  • WebX 中并没有用到 ReferenceResolver
  • 同一一个请求中 Screen 和 layout 和 action 都是引同一个 TemplateContext 对象实例。而每一个 control 都有一个以 control 名字做为 key 的 TemplateContext 。如果 control 需要用 Screen 中 TemplateContext 中对象时。可以在 screen 模板调用 contorl 时用 setParameter 方法注入。 例: $ control.setTemplate("alipayManagerRegister.vm").setParameter("registerError",$registerError).setParameter(“email",$!email) 多个就直接往后加 setParameter(“xxx”,$!xxx)
  • 关于 Push MVC Model The current encouragement that Turbine gives to developers is to do a mapping between one Screen (Java) and one Template (WM or V). The way it works is that you build up a Context object that is essentially a Hashtable that contains all of the data that is required to render a particular template. Within the template, you refer to that data in order to format it for display. I will refer to this as the "Push MVC Model."
  • 杨亮: AO 是 prototype ,每次请求都新建一个实例,因为他有个 command 引用。 Command 就是 web 调用 biz 时新建 CommandSupport 实例。 里面存储着 web 层传过来的参数集。
  • 我还是没理解他说的妥协是怎么回事? 宝宝后来举了一个 DWR(java 层 ) 的用法,假设 car1 和 car2 都需要使用 DWR 这个对象,并且 DWR 又会操作 Biz 层的对象。 那么最简单的方式就是把 DWR 放到 Biz 层的 Spring 容器中,并提供 car1 和 car2 到 DWR 的访问途径。 Web 层到 Biz 层 Spring 容器的引用,决不能被当作 CommandDispatcher 的快捷方式来使用。
  • sessionDispatcher 引用一 个 ejb/CommandDispatcherSLSB 的 ejb 实例。而这个 ejb 实例 ( com.alibaba.biz.command.dispatcher.ejb.slsb.CommandDispatcherBean ) 也只是代理了 commandDispatcherLogic 。 public Result execute(Command command) { Result result = getCommandDispatcherLogic().execute(command); }
  • 宝宝:也可能是后续维护的人员弄错了。应该一个就够了。 阿甘:如果只用一个全局的话,也不排除有没有其他陷阱,比如会否用到 ResourceLoaderService ,每个 car 是不同的。
  • Apache 除了打点用到,有其他作用么? Exodus2 中应该没有静态页面吧?
  • iBatis 的配置,似乎只对少量业务使用了高速缓存。 Type=LRU
  • Delta Index 增量索引,索引的信息并不完整,所以还不能替代每天晚上的 Build Index 目前数据库 offer 数据在 2 亿多,还能承受 Build Index ,未来可能会面临压力。
  • X 项目二期发布后, XML 文件比以前大了很多,目前大概有将近 30m 。
  • Transcript

    • 1. Exodus2 大局观 内容纲要: 1 , Exodus2 的历史 2 , WebX 大局观 3 , Exodus2 的部署 4 ,数据访问层 hongjiang 2009.5.16
    • 2. 1, Exodus2 的历史Exodus2 代号名称的由来:不知道大家注意过没有, exodus 和 ezra(BOPS 的代号 ) 都是出自圣经,容易联想到这两个产品的设计者可能是基督教信仰者或者深谙圣经。校长:Exodus 是《圣经》出埃及记那一章。摩西带领犹太人走出埃及是一段非常艰辛的过程。早些年 ali 曾经比较崇拜国外的技术,雇佣硅谷的一些工程师开发过一些东西,后来证明并不好用,后由宝宝带领开发出一套新的框架。这个过程是有些类似于出埃及的过程的。 exodus2 是 exodus 后来的重构版本。
    • 3. Exodus2 的历史即使一些工作 2 , 3 年以上的同事,谈及Exodus2 的时候,也会说“水很深”。越深入的了解,发现它的确有很多模糊或者困惑的地方可能是历史遗留原因,我们需要弄清楚,避免一些错误。这个框架不仅 ali 在用,淘宝,支付宝也在用,有些因素可能是其他公司有特殊的需求,使得框架有所妥协而违背原先的设计。
    • 4. 2. WebX 大局观2.1 , Spring 框架2.2 , Service 框架2.3 , WebX 的表现层2.4 , WebX 的业务层2.5 ,表现层和业务层的交互 : CommandDispatcher— 忧愁河上的桥
    • 5. 2.1 Spring 框架 核心: DI 和 AOP
    • 6. Spring 框架布局 J2EE应用程序 消除基于 重复代 Spring应用框架POJO 码简单开发 IoC容器 AOP框架 事务 远程 DAO JMS JNDI 支持企业服务
    • 7. Spring 容器:Spring 容器有多种实现,分两类 : 1: BeanFactory 2: ApplicationContext ( 扩展了 BeanFactory, 提供了更多功能, 绝大部分应用都使用ApplicationContext)
    • 8. 依赖注入:依赖注入是 Spring 运用反向控制原则解决配置管理和对象关系管理的手段。 依赖注入的方式:1: setter 方式2: 构造器方式3: 方法注入,抽象方法
    • 9. 对 AOP 的支持,用代理类包裹切面 代理 调用者 目标 Spring 基于代理实现对 AOP 的支持 通过 J2SE dynamic proxies ,可以代理任意 Java 接口。 通过 CGLIB 字节码生成,可以代理 Java 类。 Spring 的代理机制可以支持由 Spring 容器创建的 bean ,无法支持应用中自行 new 出来的 bean 。 Spring 只支持方法连接点。
    • 10. Bean 如何和 Spring 容器交 互3 个 Ware 接口:《骇客帝国》中的红药丸BeanNameAware : 了解 Bean 的名称BeanFactoryAware: 了解容器ApplicationContextAware: 了解容器
    • 11. 2.2 Service FrameWork 和 Spring 有些相似的一套框架, 用来管理 Service 对象,负责其生命周期,根 据配置来装载 Service ,可以确保 Service 之间 的耦合是松散的
    • 12. Service 是什么?没什么特别的,就是一些对象 ( 实现了 Service 接口而已 ) ,不过这些对象在 WebX 中都是一些比较通 用的服务或者工具。
    • 13. Webx 正常运行所必须的 ServiceFormService 读取并验证用户 submit 的 form 表单的 service 。JSPService JSP 模板引擎,用来渲染 jsp 写成的页面模板。需要 TemplateService 的支持。MappingService 将一个名字映射到另一个名字的 service 。ModuleLoaderService 装载 turbine module 的 service ,例如: screen 、 action 、 control 等。PipelineService 用来创建 pipeline 的 service 。PoolService 缓存以减少对象创建的开销。PullService Pull model service ,自动创建一定作用域的对象,而不需要应用程序干预 ( push )。ResourceLoaderService 用来装载资源的 Resource loader service 。RunDataService Webx 核心 service 之一,用来保存每一个 HTTP 请求的状态。需要 PoolService 和 UploadService 的支持。TemplateService 用来管理 template engine ,渲染页面的 service 。ThreadContextService 线程空间的 singleton 服务,方便 service 存取 request scope 的对象。URIBrokerService 自动生成 URI 的 service 。UploadService 用来上传图片和文件的 service 。VelocityService Velocity 模板引擎,用来渲染 velocity 写成的页面模板。需要 TemplateService 的 支持。
    • 14. Service 概念 ( 摘自《 Exodus2 代码分析初步》 )一个服务 (Service) 可以有多个服务实例一个实例 (Instance) 可以包含多个服务,并有一个实例上下文(InstanceContext)同一个实例的所有服务共享该实例上下文在 Webx 中: 每个 WebxComponent 都是一个实例 每个 WebxComponent 都由一个 webx.xml 配置其中的服务 每个 WebxComponent 都继承缺省实例的配置,缺省实例由 webx-default.xml 和 webx-turbine-default.xml 的来合并定义
    • 15. 类图结构
    • 16. Service 容器结构
    • 17. 假设我们有 2 个 car 。我们为全局配置了 A,B 两个服务;为 car1 配置了 C 服务;为 car2 配置了 D 服务。ServiceManager 初始化后 容器中会是怎样?
    • 18. A BCar1 Car2 C D 是这样么 ?
    • 19. ServiceInstanceContext ServiceConfig ServiceInstance Service注意: ServiceInstance 是对 Service 的包装
    • 20. ServiceInstancA ServiceInstanceB ServiceInstanceC ServiceInstanceD ServiceInstancA ServiceInstancA ServiceInstanceB ServiceInstanceB ServiceInstanceC ServiceInstanceC ServiceInstanceD ServiceInstanceD它有一个将未申明 Service 补全的过程。是这样 ?
    • 21. ServiceInstance 是对 Service 的包装。那么从ServiceInstance 中如何获取 Service 对象?不同的ServiceInstance 会共享 Service 么?看一下代码中的注释:// 1. 如果是 main-instance ,并且指定了 classname ,则实例化 main-instance 。 // 2. 如果是 main-instance ,并且未指定 classname ,则返回 null 。 // 3. 如果是 sub-instance ,并且指定了 classname ,那么: // 3.1 如果是 MultiInstance ,如果和 main-instance 的类相同,则同 4.3 。 // 否则报错。(这样做是为了兼容性好,特别是当一个原来不是MultiInstance 的类转换成 MIS 时) // 3.2 如果 main-instance 不存在,则实例化 service instance 。 // 3.3 如果 main-instance 存在,但不是 MultiInstance ,则实例化 serviceinstance 。 // 3.4 如果 main-instance 存在,而且是 MultiInstance ,则报错。 // 4. 如果是 sub-instance ,并且未指定 classname ,那么: // 4.1 如果 main-instance 不存在,则返回 null // 4.2 如果 main-instance 存在,但不是 MultiInstance ,则用 main-instance 的类实例化 service instance 。 // 4.3 如果 main-instance 存在,而且是 MultiInstance ,则调用 main-instance 的 getInstance 方法。
    • 22. 假设我们的 A 服务实现了 MultiInstance 接口, B 服务 没有。 InstanceA InstanceB InstanceC InstanceD A B null null A A B B C null null D
    • 23. 说明:可以参考 DefaultServiceManager 的 initMapping 函数,最后一段逻辑。Exdodus2 中一共配置了 12 个 car , 22 个 Service 。经过initMapping 后, services 这个 Map 中一共有 286 个 entry而实现 MultiInstance 接口的只有:BootstrapResourceLoaderService,DefaultIPSeekerService, DefaultRunDataService,DefaultViewCacheService, 这 4 个 Service ,也就是说大部分Service 每个 car 都会再创建自己的实例。这样在全局定义那么多Service 干嘛?比如全局的 PullService , TemplateService 有什么作用? 另外 : 在 webx-turbine-default.xml 中对 sub-instance 定义了 FreeMarkerService ,会用到么?
    • 24. 配置级联的 Spring 容器我们说过,每个 car 里的 service 都是一份独立的实例。同样,作为一个普通的 Service ,每个 car中都会创建一份自己的 Spring 容器。假如我有10 个 car ,就有 10 个各不相干的 Spring 容器。
    • 25. 但是,有一些 Beans 是不能够这样做的,否则会占用不必要的系统资源。例如,和 cache 有关的 beans 。怎么解决这个问题呢?有办法!我们可以把 Spring 容器级联起来,使父容器被所有的 car 共享。改进方案如图:
    • 26. 要配置这种级联的 Spring 容器非常简单: WAR └─ WEB-INF │webx.xml - 在此配置共享的父容器 │ ├─ car1 │webx.xml - 在此配置派生的子容器 └─ car2 webx.xml - 在此配置派生的子容器配置文件的写法完全同前例。这样,当查找一个 bean 时, Spring 会首先在子容器中查找,如果找不到,再到父容器里查找。你可以自由地决定,哪些 beans 需要被共享 ,哪些 beans 需要被某个 car 独享。
    • 27. 看看 Service 接口定义的 getParentService 方法:对于 sub-instance ,取得其 main-instance ,否则返回 null 。注意:和 ServiceContext.getService 方法不同,即使 parent instance初始化失败, getParentService 也不会抛出异常,而是将 parentinstance 初始化失败的信息记录在 log 中。ServiceContext( 全局 Service 容器 ) 中:getService(svcName)getService(svcName, instanceName)注释中说:如果 service 不存在,或初始化失败抛出ServiceInstantiationException但实际代码并未声明 throws ServiceInstantiationExceptionto fix: 代码中的注释应该也修改一下。
    • 28. Service 框架和 Spring 框架的异同 1: Spring 是个更通用的容器,容器装载的 Bean 可 以是任何类型对象。而 Service 容器中装载 的是 Service 对象。 2: Spring 容器中的对象可以不必知道容器,而 Service 容器中 service 对象是紧密和容器耦合的 。
    • 29. Service 框架究竟有没有实现“依 赖注入” 《 Service 框架指南》中说 Service 框架不支持“注入”,而 Module 中却 用到了注入。 宝宝的答复: Service 框架不支持注入。但是应工程师要求,在 screen/action/control 等部 件中加入了注入功能,是用 cglib 直接实现的,和 service 框 架无关。 另外,我目前在做的工作是,将 webx 移植到纯 spring 框架 中,抛弃 service 框架, 因此注入从此不是问题了。
    • 30. 2.3 WebX 表现层1, RunData :对 Req,Resp,Session 的封装2, Module :页面编程模块3, Pipeline: 逻辑流程4, 分析一个页面请求的流程
    • 31. RunData: 简化对 http 请求操作RunData 实现了 RequestContext 接 口。RequestContext 体系是一个用装饰 模式实现对功能的层层扩展。
    • 32. RequestContext 的构建 : 封装了哪些功能?看看配置文件,对 RunDataService 的装配:构建一个 ChinaRunData, 它通过一个个的工厂类来进行装配(Decorate) ,负责调用这些工厂的是 RequestContextChainService这些工厂的设置顺序: BufferedRequestContextFactory ↓ LazyCommitRequestContextFactory ↓ ParserRequestContextFactory ↓ SessionRequestContextFactory ↓ SetLocaleRequestContextFactory ↓ RewriteRequestContextFactory
    • 33. ChinaRunData: 注意包装的顺序RewriteRequestContext SetLocaleRequestContext SessionRequestContext ParserRequestContext LazyCommitRequestContext BufferedRequestContext RequestContextImpl
    • 34. HttpSession 中的问题:通过 BufferedRequestContextLazyCommitRequestContext防止了 HttpResponse 的“自动输出”,使得我们可以一直控制 http 头,有机会改写cookie 信息,实现 session 的存储。BufferedRequestContext 是缓冲了整个http 的 head 和 content 还是只缓冲了head ?如果遇到一个很大的页面会如何?
    • 35. WebX 中的 Module Webx 中的页面逻辑编程模块。 Screen, Action,Control,Layout 都实现了 Module 接口。所有的 Module 都是通 过 ModuleLoaderService 装载的。
    • 36. ModuleLoaderService 的装载 和依赖注入装载 Module: 将创建各种 module 的任务转交给ModuleFactory 去做。它可以为每一种 module( screen/control/action )指定一个或多个ModuleFactory 来创建。Module 中的依赖注入 : 1: setter 方式。 2 : abstract getter 方式。注入究竟是怎么实现的?
    • 37. 如果不加特别的配置,那么 DefaultModuleFactory 已经可以支持将 Service 注入到 module 中。例如在 module 中定义下面的 abstract getter :   protected abstract URIBrokerService getURIBrokerService();这句话告诉 DefaultModuleFactory :将 URIBrokerService 注入到 module 中 去。 对于抽象类,通过 CGLIB 动态生成子类 。 在获取 Module 实例时,调用 DefaultModuleFactory 的 getModule instantiateModule(String moduleClassName) 判断 Module 是否 abstract class, 如果是则用 CGLIB 来创建 Module 子 类。 ( 非 abstract 则用反射方式 newInstance) 随后 instantiateModule 函数中,如果 module 实例不为 null 则调用 injectDependences 函数,加载所创建的 module 实例依赖的对象。 injectDependences 调用 propertySetter.invoke 来注入依赖对象
    • 38. 如果 注入的不是 Service, 而是一个 Bean, 则需要利用 ReferenceResolver 接口我们实现了 SpringReferenceResolver ,用来从 Spring 容器中取得对 象。 也就是说 Module 中注入 Service 对象, Webx 框架直 接实现,因为框架本身是一个 Service 容器,很容易获 取到 Service 对象。 而 Module 中注入 Bean 对象,则需要借助 Spring 容器 来获取,非 Service 对象都是通过 Spring 容器托管的。 比如 CommandDispather 这样的非 Service 对象还有 Biz 层的 AO,BO 等都是用 Spring 容器来托管的。
    • 39. 模板的渲染: TemplateEngineService TemplateServiceJspService VelocityService FreeMarkerService TemplateServer 通过注册一个 Engine 来实现渲染 。 渲染的顺序是: Screen->Layout->Control 渲染过程需要 TemplateContext , module 是从 rundata 中获取 templateContext 的, rundata 中需要通过 PullService 来获取。
    • 40. Action/Screen 执行顺序
    • 41. WebX 中的 Pipeline Pipeline 是表现层逻辑流程的核心。它是一种责任链模式, (X 它的代码实现上并不 是)把处理从一个 Valve 流向下一个 Valve ,主要响 应 action module 的 Valve 是可以改变现有的 valve ,例如:改变分析 URL 的方法 PerformActionValve 。可以插入新的 valve ,例如: Session 处理、权限验证等 。
    • 42. 根据返回值 ValveForward 进行跳转内部重定向的实现方式: RedirectTargetValve processModule (ChooseValve 根据条件 RedirectTargetValve 选择 PerformValve)
    • 43. TryCacheFinallyValue: try{ tryPipeline: }catch(Exception e){ cachePipeline: }finally{ finallyPipeline: }
    • 44. 大峰的提问 :PerformActionValve 的安全性隐患?
    • 45. 金立的补充:在 pipeline.xml 配置中,第二个 valve:<valveclass=“com.alibaba.exodus2.web.common.webx.valve.AuthContextValve” />AuthContextValve 的验证机制只是对 URL 而没有对后续的 action 验证,比如:请求 a.htm?action=x&event_submit_doXXXAuthContext 只验证了 a.htm ,并没有验证后续的 action而用户有可能篡改后续的 action ,比如:a.htm?action=y&event_submit_doYYY这样就执行到了 Y Action 里的逻辑。
    • 46. 分析一次页面请求经历的逻辑假设我们执行 offer post 并转向成功页面1: 从 URL 的角度看2: 从 Pipeline 的角度看
    • 47. 从 URL 的角度看: 只关注 URL 的进和出 根据规则 MappingServiceRequest Url Rewrite 映射到物理路径 业务执行模块 URIBrokerServiceResponse 构建要跳转的页面
    • 48. 详细的看这个过程 :1: Webx 的初始化。2: RunData 的构造。3: Servlet 把逻辑交给 Pipeline
    • 49. Service 容器是被 WebxControllerListener 所初始化 的,该 Listener 在 Web 容器初始化时执行。创建好 Service 容器后,将其保存在 ServletContext 中。 Servlet 请求之前,先被 RundataFilter 拦截。它负责 调用 RundataService 把 Req/Resp/Session 等封装成 一个 RunData 对象,随后将其 setAttibute 为 req 的 属性,方便以后通过 req 得到 RunData 。 RunData 经过多重包装的 经过多重包装的 RequestServletContext Request Attribute Response
    • 50. 从 pipeline 的流程来看 : CheckCSRF Hessian 可选Logging Auth AnalyzeURL Remote Screen GreenChanel Action Trace Template Screen Action ChooseRedirect TBStore CheckCode ExpiredUrl
    • 51. 关于 PullServie 实现 Pull-MVC 的设计模式 怎么理解 Pull-MVC, 和 push 的不同之处? What this entails is the ability to create an object that is able to “pull” the requiredinformation out at execution time within the template.
    • 52. 2.4 WebX 业务层 (BIZ 层) 1 :业务层的 Service 容器。是如何创建的? 2 : AO,BO,DAO 都在 Spring 容器中。 AO 每次请求时都是一个新的实例? BO 是一些通用逻辑模块,可供多个 AO 调用。
    • 53. 用 Singleton 启动 Service 容器 为了分离 WEB 层和业务层的对象,我们常常 将 WEB 层的 Service 容器和业务层的 Service 容器彻底分开。这样, WEB 层的 Spring 容器 也随之和业务层的 Spring 容器彻底分开了。如 图所示:
    • 54. Web 层和 BIZ 层分离 Web 层 Service 容器 Car1 Car2 Spring 容器 Spring 容器 Dispatcher DispatcherBiz 层 Service 容器 Spring 容器 AO BO
    • 55. 用 Singleton 启动 Service 容 器 上图中的 CommandDispather 在初始化中, 会调用 SingletonServiceManagerLoader 来 启动一个独立于 WEB 层的业务层 Service 容 器,再从中取得业务层的 Spring 容器。所有 业务层的对象,都配置在这个 Spring 容器中。 请记住,这是一个 Singleton ,意味着业务 层的 Spring 容器只会被初始化一遍。
    • 56. 1.5 表现层和业务层的交互 CommandDispather 使用命令模式,封装了从表现层到业务层 的调用,开发人员可以透明的对待它。 它有多种实现方式, Exodus2 用的那种方 式?
    • 57. 简单方式 ?
    • 58. 改进方式 ?
    • 59. 远程方式 ?虽然由此设计,实际上我们所有的 web 和 biz 都是部署在同一个 JVM 中的。
    • 60. 异步方式 ?
    • 61. 在确认之前还要弄清另外一个问题 :《 Service 框架指南》中说在web 层的 spring 容器中包含 biz 层的 spring 容器的引用。 如何做到?
    • 62. 宝宝《 Webx Modules 的装载以及依赖注入》中说:……然而还有一个问题。在我们的常见应用中,web 层和 biz 业务层是分离的, web 层的spring 容器和 biz 层的 spring 容器也是分离的。上面的配置只能拿到 web 层 spring 容器中的内容,不能拿到 biz 层 spring 容器的内容,怎么办呢?方法很简单:在 web 层的spring 容器中包含 biz 层的 spring 容器的引用。
    • 63. 既然是分层的 (web 层和 Biz 层分别存在各自的 Service 容器中 ) 。Web 层 spring 容器 又如何得到 biz 层的 Spring 容器引用呢? 我看你后边的配置, web 层是通过获取 Biz 层的 Service 容器引用 再去获得 Biz 层 Spring 容器的,<beans> <bean id=“bizBeanFactory”class=“com.alibaba.service.spring.support.SingletonBeanFactoryServiceBean”> <property name=“serviceConfig”value=“biz/services.xml”/><!-- 指向 biz 层 service 容器 --> </bean></beans>那样的话,两个 Service 容器不就完全耦合了吗,还要 CommandDispatcher 干嘛。
    • 64. 实际在我们的 webx-default 中对 sub-instance 也存在一个对 biz层 Spring 容器的引用: <service name=“BeanFactoryService”class=“com.alibaba.service.spring.DefaultBeanFactoryService”> <property name=“bean.descriptors”> <value>exodus2/bean/biz-delegate.xml</value> <value>exodus2/bean/web-tool.xml</value> </property> </service>web-tool.xml 里面配置了 WebApplicationContextUtilsBean ,里面 setter 了serviceConfig:alibaba-biz-service.xml 。该 utilBean 初始化时会通过调用SingletonServiceManagerLoader.getInstance( bootstrapResourceLoaderService, serviceConfig, initAll);获取 biz 层的 Service 容器的单实例引用,进而获取 biz 层的 Spring 容器引用。我们就可以通过该 UtilBean 来访问 biz 层的 spring 容器。
    • 65. Exodus2 的中实际场景(不完整) Car1 Car2 Spring 容器 Spring 容器 UtilBean UtilBean CommandDispatcher Biz 层 spring 容器 AO BO
    • 66. 思考:这样岂不是将 web 层的 Service 容器和 Biz 层的 Service容器耦合在了一起?Michael zhou:Command Dispatcher 是可以访问到业务层的代码的,按理说,这应该是唯一的访问业务层 spring 容器的方法。你看到我把 bizBeanFactory 注入到 web 层容器中,说实在这种做法是不太完美的。但这也是对实际需求的一种妥协。因为有一些公用对象(非业务层和数据访问层对象,如 AO 、 DAO 等),需要放在一个大家都能访问到的地方。但当你要访问业务对象( AO 、 DAO 等)时,仍然应该通过 command dispatcher 来走。
    • 67. Exodus2 中 CommandDispatcher 用哪种方式和 biz 层通讯?看一下 biz-delegate.xml :<bean id="sessionDispatcher"class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean"> <property name="jndiName"> <value>ejb/CommandDispatcherSLSB</value> </property> <property name="businessInterface"> <value>com.alibaba.biz.command.dispatcher.CommandDispatcher</value> </property> </bean> <bean id="messageDispatcher"class="com.alibaba.biz.command.dispatcher.ejb.mdb.CommandDispatcherClient"> <property name="connectionFactory"> <bean class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>AlibabaWebxConnectionFactory</value> </property> </bean> </property> <property name="destination"> <bean class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>queue/AlibabaWebxQueue</value> </property> </bean> </property> </bean>
    • 68. commandDispatcherSelector 会根据 Command 的名称来判断使用哪个 dispatcher 。可供选择的 dispatcher :1, sessionDispatcher 使用 ejb 方式。默认选择此方式。2, messageDispatcher 使用消息队列的方式。3, commandDispatcherLogic 直接通过已持有 biz 层 spring 容器的引用来找到 biz 层的 AO 来执行。顺藤摸瓜。
    • 69. Exodus2 中的 CommandDispatcher 默认的方式 是 远程方式。用 Ejb 实现远程调用。
    • 70. Biz 层的 CommandDispatcher:除了 web 层和 biz 之间使用 CommandDispatcher, biz 层内部之间也使用了 CommandDispatcher比如发邮件的情况, web 层 dispatcher 到 biz 层的 SendMailBO ,它又会通过 biz 层的 dispatcher 交给 JMSbiz 层这时用的 dispatcher 是异步消息队列的方式。 Web-CommandDispatcher EJB 容器 Biz-Serverice 容器 Spring 容器 BO Biz-dipatcher AlibabaWebxQueue ???
    • 71. Web-CommandDispatcher (sessionDispatcher)EJB 容器 EJB (…ejb.slsb.CommandDispatherBean) messageDispatcher Biz-Serverice 容器 Spring 容器 AO/BO/DAO Biz-dipatcher AlibabaWebxQueue EJB
    • 72. SLSB 和 MDB 类型的 EJB 分别是什么? com.alibaba.biz.command.dispatcher.ejb.slsb. CommandDispatherHome CommmandDispatherRemote CommandDispatherBean com.alibaba.biz.command.dispatcher.ejb.mdb. CommandDispatherClient CommandDispatherBean为什么 sessionDispather 用到 slsb, messageDispather 用到 mdb (slsb 可用作远程或本地调用,而异步处理只能用 mdb)
    • 73. 为什么这么配置?性能问题► sessionDispatcher 配置的是远程方式。► 就一定会走远程方法调用么?还是也有可能走 local 方式?► 如果走远程方法调用,是通过 socket 来进行么? 它的端口? 既然我们已经可以直接得到 biz 层对象 的引用;为何这样? 怎么看待这里的效率问题?► 如果是,这些是否都是历史遗留原因?还是?
    • 74. 阿甘:1 :虽然配置方式是远程调用, JBoss 内部会对其优化,判断是同一 JVM ,会相当于本地调用来对待。3 :可能是历史原因,早期是支付宝有需要将web 层和 biz 耦合起来, B2B 也保持了这样的结构。但开发人员使用时应该按照CommandDispatcher 的方式调用,保持这种风格便于维护。
    • 75. Main-instance 和 sub-instance 中都配 置了 ComamndDispather 。 Main-instance 中的 Dispatcher 有何 用意? 阿甘的答复: Main-instance 中的 CommandDispather 是为了某些全局 Service 所用的,某些全局 Service 也会通过 Dispather 去访问 Biz 层 宝宝:也可能是后续维护的人员弄错了。应 该一个就够了。
    • 76. 3, Exodus2 的部署JBoss 没有使用集群,当服务器比较多时,相互之间的监控需要耗费很大性能Exodus2 也没有实现集群。
    • 77. 前段负载均衡 F5 Exodus2Exodus2 Exodus2 Apache Apache 。。。 共 64+7 台 JBoss JBoss Memcached 集群 DataBase
    • 78. 数据库的部署:双机热备Oracle9.2 心跳检测 Oracle9.2 DB1 DB2 DB 并没有使用集群 ,放在两台小型机 共享存储设备 上。 DB2 同时还做 回滚备份
    • 79. Exodus2 的数据层1, 数据存储方式,数据源。2, 基于 iBatis 的 DAO
    • 80. 数据访问层 DALMemcache Search Oracle ViewCache Engine LDAP 已经不再使用
    • 81. 数据库与搜索引擎 前端负载均衡 F5Apache Apache 。。。 搜索引擎 搜索引擎 Dispatcher Build Index Delta Index 每天晚上 每 5 分钟 Oracle
    • 82. ViewCache 缓存数据Oracle SCP XML 文件 Sync Engine ViewCacheService ( 已不用 JOS)SearchEngine Exodus2 搜索引擎的数据:提供统计信息,相当于类目的属性

    ×