框架设计原则

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

《框架设计原则》梁飞/虚极(2012-11)1课程说明•内容:–主要讲在Dubbo设计过程中积累的一些经验,–以及一些设计理论在Dubbo中的应用,–并且只讲实践原则,不谈设计模式。•目的:–希望给其它产品的设计起一些借鉴作用。2大纲模块分包原则框架扩展原则模型划分原则接口分离原则组件协作原则功能演进原则34RPCRemotingBusinessreferreceivedrequestconnectbindconnectbindsendreplyinvokeinvokeencodemergewritereadgetProxygetInvokerexportreferdecodeserializeselectlistregistergetExecutornotifygetRegistrynotifylistinvokeinvokeProviderConsumerExporterInterfaceProxyFilterInvokerInvokerFilterImplementClientServerTransporterLoadBalanceProtocolNotifyListenerRegistryProtocolRegistryExchangeServiceSerializationInheritInitDubboFrameworkDependDubboInvokerDubboProtocolDubboExporterInterfaceClassProxyFactoryInvokerProxyReferenceConfigServiceConfigConfigCallClusterCodecObjectOutputObjectInputExchangerTransportSerializeDirectoryClusterThreadPoolRegistryProtocolUserAPIContributorSPIRegistryFactoryRegistryDirectorydeserializeexportinvokeinvokeinvokeexportChannelHandlerExchangeHandlerRouterRouterFactoryMonitorMonitorMonitorFactoryrouteMonitorFilterExchangeSereverExchangeClientcountreferreceivedgetMonitorStartgetexportinvokeinvokenewsubscribeDispatchergetRouterdispatchDubboHandlermergegetRoutergetRegistrygetMonitorwrapconnectconnectbindbindDubbo的模块包5模块分包原则•复用度–包中的类应该有同样的重用可能性,–紧密协作的类应该放在一个包。–对于变化因子,包中的类应全改或全不改,–变化应在包内终止,而不传播到其它包。–发布的粒度和复用度相同。•稳定度–被依赖的包应该总是比依赖者更稳定,–不要让一个稳定的包依赖于不稳定包。–单向依赖,无环依赖。•抽象度–越稳定的包应该越抽象,–稳定的包不抽象将导致扩展性极差,–抽象的包不稳定将导致其依赖包跟随变化。6稳定不稳定非常不稳定抽象具体packageimportcom.foo.*不稳定度与抽象度矩阵•I=Ce/(Ca+Ce)I:InstabilityCa:AfferentCoupling(Usedbypackges)Ce:EfferentCoupling(Dependuponpackges)•A=Na/NcA:AbstractnessNa:NumberofabstractclassesNc:Numberofclasses(Includeabstractclasses)•D=abs(1-I-A)*sin(45)D:DistanceI:InstabilityA:Abstractness7JDepend不稳定度与抽象度类图8HTTL分包示例9主页:框架扩展原则•微核+插件体系•平等对待第三方•外置生命周期•最少化概念模型•一致性数据模型11微核+插件体系•OSGi–Equinox–Eclipse,HSF–META-INF/MANIFEST.MF•IoC–Spring,Guice–META-INF/spring/beans.xml•SPI–java.util.ServiceProvider–JDBC,MessageDigest,ScriptEngine–META-INF/services/com.xxx.Xxx12KernelPluginPluginPluginPlugin平等对待第三方•Dogfooding–框架自己的功能也要扩展点实现–甚至微核的加载方式也可以扩展•Autowire–装配逻辑由扩展点之间互助完成–杜绝硬编码的桥接和中间代码•Cascading–层叠扩展粒度,逐级细分–由大的扩展点加载小的扩展点•LawofDemeter–只与触手可及的扩展点交互,间接转发–保持行为单一,输入输出明确13DogfoodingAutowire外置生命周期•API传入参数,SPI扩展点实例•尽量引用外部对象的实例,而不类元–正确:•userInstance.xxx();–错误:•Class.forName(userClass).newInstance().xxx();•尽量使用IoC注入,减少静态工厂方法调用–正确:•setXxx(xxx);–错误:•XxxFactory.getXxx();•applicationContext.getBean(“xxx”);14最少化概念模型•Filter-Chain?–Resultfilter(Chainc,Invocationi);•returnc.doNext(i);–Resultinvoke(Invokerv,Invocationi)•returnv.invoke(i);15ProxyFilterChainFilterInvokerProxyFilterInvokerFilterInvokerProxyInvoker一致性数据模型•Dubbo统一URL模型:–所有配置信息都转换成URL的参数–所有的元信息传输都采用URL–所有接口都可以获取到URL16Provider•dubbo://10.20.153.10:20880/xxxService?timeout=1000Registry•dubbo://10.20.153.10:20880/xxxService?timeout=2000Consumer•dubbo://10.20.153.10:20880/xxxService?timeout=3000Dubbo重构示例17博客:重构步骤第一步•微核心,插件式,平等对待第三方。第二步•每个扩展点只封装一个变化因子,最大化复用。第三步•全管道式设计,框架自身逻辑,均使用截面拦截实现。第四步•最少概念,一致性概念模型。第五步•分层,增量式扩展,而不是扩充式扩展。18微核+插件+正交分解19管道+事件+一致模型20分层+增量+平等对待21大纲模块分包原则框架扩展原则模型划分原则接口分离原则组件协作原则功能演进原则22核心领域模型划分原则•服务域–指产品主要功能入口,同时负责实体域和会话域的生命周期管理。–Velocity的Engine–Spring的BeanFactory•实体域–表示你要操作的对象模型,不管什么产品,总有一个核心概念,大家都绕围它转。–Velocity的Template–Spring的Bean•会话域–表示每次操作瞬时状态,操作前创建,操作后销毁。–Velocity的Context–Spring的Invocation23ServiceSessionEntityinitrun核心领域模型类图24Dubbo的核心领域模型•服务域:Protocol–它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。•实体域:Invoker–它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。•会话域:Invocation–它持有调用过程中的变量,比如方法名,参数等。25核心领域模型划分优势•结构清晰,可直接套用•充血模型,实体域带行为。•可变与不可变状态分离,可变状态集中•所有领域线程安全,不需要加锁26核心领域模型线程安全性•服务域–通常服务域是无状态,或者只有启动时初始化不变状态,所以天生线程安全,只需单一实例运行。•实体域–通常设计为不变类,所有属性只读,或整个类引用替换,所以是线程安全的。•会话域–保持所有可变状态,且会话域只在线程栈内使用,即每次调用都在线程栈内创建实例,调用完即销毁,没有竞争,所以线程安全。27GUITask设计示例28博客:用法•newSwingWorkerListUser,Void(){//没有子任务,第二个泛型声明为Void•//独立的线程池执行doInBackground方法,执行完后,结果放在get方法的Future引用中•protectedListUserdoInBackground()throwsException{•returnremoteService.findUsers();•}•//在EDT线程执行done方法,所有与GUI的相关操作都应放在done方法中处理•protecteddone(){•try{•//通过get获取doInBackground返回的结果•ListUserusers=get();•//显示到UI•tableModel.addAll(users);•}catch(Exception){•//捕获doInBackground抛出的异常,由get方法抛出•}•}•}.execute();//直接执行,内部有封装线程池和FutureTask29SwingWorker问题•如果不看文档,你很难猜到它的用法,这个类集实体域,会话域,服务域于一身,非常复杂,即表示任务本身(实体域),也包含执行过程的状态(会话域),同时也具有主动执行能力(服务域)。行为状态混杂•比如:doInBackground()的返回值是给done()方法用的,而且要通过get()方法获取到返回值。数据传递隐晦•这个类和Thread类一样,只能执行一次,多次执行是无效的,因为其有状态,所以这样做是正确的。全局有状态30重构后的模型划分31重构后的完整设计32对应模型划分说明•Task表示任务本身•TaskListener为事件通知,所有的UI操作均放在Listener里处理•TaskAdapter同时实现Task接口和TaskListener接口实体域•TaskContext为互上下文,保存执行过程中的状态•TaskEvent为事件信息会话域•TaskExecutor提供执行能力,为执行入口•TaskService做为SPI,这样就可以同时适配Swing/AWT和JFace/SWT服务域33大纲模块分包原则框架扩展原则模型划分原则接口分离原则组件协作原则功能演进原则34API&SPI•DubboAPI–ServiceConfig–ReferenceConfig–RpcContext•DubboSPI–Protocol–Transporter–LoadBalance35APISPIFrameworkUserDeveloperAPI与SPI分离36声明式API,过程式SPI•声明式A

1 / 60
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功