Dubbo第三讲:Dubbo的可扩展机制SPI源码解析

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Dubbo第三讲:Dubbo的可扩展机制SPI源码解析

1、Dubbo SPI机制

1.1、Dubbo具有良好拓展性的原因
  • 1、整个框架中针对不同的场景,恰到好处地使用了各种设计模式
  • 2、基于Dubbo SPI 加载机制,让整个框架的接口和具体实现完全解耦合
  • Dubbo SPI 扩展
  • 与Java SPI类似,需要在META-INF/dubbo/下放置对应的SPI配置文件,文件名称需要命名为接口的全路径名。配置文件的内容为 key=扩展点实现类全路径名,如果有多个实现类则需要使用换行符分割
  • 在Dubbo启用时,会默认扫描这三个目录下的配置文件:META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/
  • 1、dubbo filter详解
  • todo
1.2、Dubbo SPI和Java SPI的区别?

Dubbo的扩展点加载从JDK标准SPI(Service provider Interface)扩展点发现机制加强而来。

改进了JDK标准SPI的以下问题:

1、JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但是没用上也加载,会很浪费资源。(我的代码中初始化配置项也存在这样的问题)

2、如果扩展点加载失败,连扩展点的名称都拿不到了

3、增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点。

1.3、Dubbo SPI可认为是IOC实现吗?

todo

2、SPI机制在商品中心的应用

2.1、TMF校验器

详情见这个项目

项目实战第十六讲:使用开闭原则实现商品价格规则引擎

2.2、在AfterImage应用中的使用
2.2.1、整体流程图如下所述

2.2.2、业务逻辑

残影系统,使用切面实现的

  • 注解:Afterimage
  • 包含的字段有
  • captorConfig 本次使用的captor(捕获)配置
  • 该类包含两字段 Captor,dubbo接口或其他 config dubbo接口详情,具体结构见下文
  • expireMills 超时时间,单位是毫秒,小于1:不过期;大于1:过期;不配置:使用captor侧配置的过期时间
  • 使用场景:缓存dubbo调用结果,用于优化在执行上下文重复同一dubbo调用
  • 当同个线程执行链路,多次使用此注解时,只有最外层的注解生效
  • 加上此注解的方法,耗时调用将被暂存起来,直到退出方法
  • 注意事项:
  • 必须使用在能被spring AOP代理的方法上
  • 如何使用:
  • 引入依赖
<dependency>
    <groupId>cn.gov.zcy</groupId>
    <artifactId>afterimage-integration-zcy</artifactId>
    <version>2.0.0-SNAPSHOT</version>
</dependency>
  • 如果是spring,请使用注解@EnableAfterimage开启, 然后在需要的方法(可被spring aop切面)加上注解@Afterimage开启。
  • eg: 1、启动时开启Afterimage,如果是spring boot 环境,会自动配置开启,
  • 如果spring-boot,不想启动时自动开启可配置afterimage.spring.bootstrap.enabled=false
@EnableAfterimage
public class Application{
}
  • 开启后,使用在需要优化的方法(可被spring aop切面),使被注解的方法开启afterimage
  • 如果想在运行时关闭,请配置:afterimage.spring.enabled=false
public class ItemServiceImpl{
    @Afterimage
    public Item find(){        
    }
}
  • 执行流程
  • 1、afterimage-config 以扩展配置读取、监听的扩展
  • 第一块:apollo配置获取,监听事件变更
  • 第二块:spring配置 ,将残影实例自动配置到Spring中
  • config 扩展
  • 作用:统计每个dubbo方法的缓存时间
  • 定义的方法:default get(key,defaultValue)、get(key)、default ddListener(key,configListenr) 如果对应key发生变化,调用listener、default removeListener(configListenr) 移除监听器、default removeListener(key, configListenr) 移除监听器
  • 实现类1
  • ApolloConfig(apollo配置)
  • 继承apollo的ConfigChangeListener接口实现了ApolloListener,实现其onChange事件
  • onChange方法里面,遍历所有改变的key,如果等于当前key,监听其改变
  • 补充了addListener方法和removeListener方法
  • 使用了写时复制ArraySet,因为配置读取的场景读多写少
  • 组合apolloConfig,并实现了Config的get方法,底层调用apolloConfig的getProperty方法
  • 实现了addListener(key,configListenr)方法,先创建监听,然后添加监听,如果apolloListener监听的数量等于1,底层调用apolloConfig的addChangeListener方法
  • 实现类removeListener(configListenr)方法,apolloListener移除监听,检查ApolloListener,为空则移除
  • 实现类removeListener(key, configListenr)方法,获取apolloListener监听器,如果为空,返回,否则,移除监听器,检查ApolloListener,为空则移除
  • 实现类2
  • SpringConfig(Spring配置)
  • 先实例化自身,然后获取系统参数
  • 实现了get(key)方法,如果系统参数为空,抛错,否则,有key获取系统参数
  • 实现类3
  • CompositeConfig(组合配置)
  • 实现了get(String key)方法,遍历每一个configList,查询config,如果能找到值,返回,否则,返回null
  • 实现了addListener(key, ConfigListener),给configList添加监听器
  • 实现了removeListener(ConfigListener)方法, 给configList移除监听器
  • 实现了removeListener(key, ConfigListener)方法, 给configList移除监听器
  • 实现类4
  • SystemConfig (系统配置)
  • 实现了get(key)方法,获取系统的值
  • 读取配置的顺序
  • apollo配置
  • 在resources资源文件夹下的META-INF/afterimage/ConfigProvider.def中配置, 格式如:order,name,providerClass,选择时,order小的优先,可以以#开头在上一行添加注释

100,ApolloConfig,cn.gov.zcy.afterimage.config.apollo.ApolloConfigProvider

  • Apollo环境可引入afterimage-config-apollo来支持apollo的配置读取、以及动态配置监听
<dependency>
    <groupId>cn.gov.zcy</groupId>
    <artifactId>afterimage-config-apollo</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

  • Spring配置
  • 在resources资源文件夹下的META-INF/afterimage/ConfigProvider.def中配置

0,SpringConfig,cn.gov.zcy.afterimage.config.spring.SpringConfigProvider

  • 系统配置
  • 在resources资源文件夹下的META-INF/afterimage/ConfigProvider.def中配置

1000,SystemConfig,cn.gov.zcy.afterimage.core.config.SystemConfigProvider

  • 默认配置为spring优先、apollo次之、System.getProperty最低
  • 配置的读取将按照spi的order配置,顺序从小到大读取,取到第一个不为null则返回
  • 也可以再启动时,设置-Dafterimage.config.order=SpringConfig,ApolloConfig 指定顺序,未指定的配置扩展将按默认顺序对应追加在后面
  • ObjectProvider 接口
  • 提供的方法:get()
  • 实现类
  • 实现类1、ApolloConfigProvider
  • NameSpace:afterimage.apollo.namespace
  • 实现了get()方法 --》从系统参数中获取名称空间,如果名称空间非空,获取apollo中当前名称空间的配置,否则:获取apollo “application”名称空间的配置项
  • 实现类2:SpringConfigProvider
  • 实现了get()方法 --》从SpringConfig获取实例
  • 实现类3:SystemConfigProvider
  • 实现了get()方法 --》获取SystemConfig实例
  • 实现类4:NopAlbumProvider
  • 实现了get()方法 --》获取NopAlbum实例
  • 实现类5:SoftReferenceAlbumProvider
  • 实现了get()方法 --》获取软引用类型ReferenceAlbum实例
  • 实现类6:StrongReferenceAlbumProvider
  • 实现了get()方法 --》获取强引用类型ReferenceAlbum实例
  • 实现类7:WeakReferenceAlbumProvider
  • 实现了get()方法 --》获取虚引用类型ReferenceAlbum实例
  • 2、afterimage-album 扩展调用结果的存储
  • 作用:存储dubbo接口调用结果
  • 定义的方法
  • init() 初始化,
  • destory() 销毁,
  • write(contextId,key,value,超期时间)存入数据,获取残影系统上下文数据,如果值为空,返回;如果上下文为空,抛错,获取上下文中的超期时间,如果这个时间为空,取入参中传递过来的超期时间,写入;
  • dowrite(contextId,key,value,超期时间)方法, 为null或小于1,将不过期
  • read(ContextId contextId, String key) 读取
  • clear(ContextId contextId, String key) 清理
  • clear(ContextId contextId) 清空整个context
  • 实现类
  • 实现类1:抽象类 AbstractAlbum
  • 实现了dowrite(contextId,key,value,超期时间)方法,获取-当不存在时,创建新的上下文,组装ValueWrapper(value,超期时间,系统时间)
  • 实现了read(ContextId contextId, String key),获取上下文,如果为空,return,否则 --》获取valueWrapper ,如果没有超期(时间为空或者小于1ms)–》返回valueWrapper中值 --》如果有配置超期时间,获取当前时间,减去valueWrapper中的系统时间,比较valueWrapper中的超期时间,如果大于 --》移除上下文,否则返回valueWrapper中的值
  • 实现了clear(ContextId contextId, String key), 获取上下文,移除对应的key
  • 提供了两抽象类
  • 1、getOrCreate(contextId) 获取或创建上下文
  • 2、get(ContextId contextId) 获取上下文
  • 实现类:ReferenceAlbum
  • Map类型 字段album,使用了ValueReference(有三个实现类,后面讲解)
  • 字段strength,枚举类型(STRONG强引用 SOFT软引用 -在内存不足时回收,每MB空余可保留1s,WEAK弱引用-GC就被回收 )
  • 提供了一个抽象方法referenceValue
  • 实现了三个静态内部类
  • StrongValueReference实现ValueReference接口,实现了get方法
  • SoftValueReference继承了SoftReference 实现了ValueReference
  • WeakValueReference继承了WeakReference 实现了ValueReference
  • 实现了方法init()
  • 实现了方法destory() 调用 album的清理
  • 实现了方法clear() 调用 album的remove
  • 实现了父类的抽象方法getOrCreate(contextId) 由context获取album Map的value,如果为空,说明需要初始化,给album初始化一个空的map,否则,返回map
  • 实现了父类的抽象方法get(contextId) 由context获取album Map的value,如果为空,返回空,否则,返回map
  • 实现类2:NopAlbum
  • 实现了这几个方法,都是空实现
  • init()方法初始化
  • destory() 销毁
  • doWrite(ContextId contextId, String key, Object value, Integer expireTimeMills) 存入
  • read(ContextId contextId, String key) 返回null
  • clear(ContextId contextId, String key) 清除第一个
  • clear(ContextId contextId) 清空
  • 实现类3:ReferenceAlbum 使用了引用实现,方便帮助GC 见上文
  • Album配置
  • 在resources资源文件夹下的META-INF/afterimage/AlbumProvider.def中配置,格式如:order,name,providerClass,选择时,order小的优先,可以以#开头在上一行添加注释
0,SoftReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.SoftReferenceAlbumProvider
100,WeakReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.WeakReferenceAlbumProvider
1000,StrongReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.StrongReferenceAlbumProvider
10000,NopAlbum,cn.gov.zcy.afterimage.core.album.NopAlbumProvider
  • 默认实现:
  • 0,SoftReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.SoftReferenceAlbumProvider
  • 软引用map实现,help gc
  • 100,WeakReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.WeakReferenceAlbumProvider
  • 弱引用map实现,help gc
  • 1000,DefaultAlbum,cn.gov.zcy.afterimage.core.album.reference.StrongReferenceAlbumProvider
  • map实现
  • 10000,NopAlbum,cn.gov.zcy.afterimage.core.album.NopAlbumProvider
  • 空实现
  • 只能使用一个具体实现,默认取order最小的那一个
  • 3、afterimage-captor 用来按需捕获调用结果进行存储
  • 背景知识:dubbo SPI 见上文dubbo filter的使用
  • 配置项为:afterimage.captor.dubbo.config
  • 配置格式:接口名1#方法名1=过期时间毫秒&方法名2=过期时间毫秒,接口名2#方法名1=过期时间&方法名2=过期时间
  • 可用*匹配所有方法名;过期时间单位为毫秒,当未配置或者小于1时,代表不过期,特别注意:当被优化方法执行完毕时,执行期间存储的调用将自动失效。
  • 配置eg: com.A#a=1&b&c=2,com.B#*=1
  • 目前不支持重载方法不同配置
  • AfterimageCaptorFilter实现了dubbo filter,使用代理设计模式,在调用dubbo接口前,先查询album是否有返回结果,在dubbo接口调用之后,将调用id和rpc结果放入到album中
  • 执行时机:消费方
  • **执行过程简述:**先获取dubbo配置,查询db(album)中是否存在该dubbo接口执行结果,有结果,直接返回该数据,否则,执行远程rpc调用,然后将方法入参和调用结果缓存到db(album)中
  • 类似于查询redis,查不到就查询db,并将结果放到redis中
  • 添加Activate注解,标识其为被代理对象,其注解含义如下
  • group :所属组:消费者,只能在消费端使用
  • order: 多个filter的执行顺序(越小越早)
  • 文件名:com.alibaba.dubbo.rpc.Filter 对于Filter的接口
  • 执行过程详述:在resources目录下新建META-INF文件夹,然后建立子文件夹dubbo,最后新建文件com.alibaba.dubbo.rpc.Filter --》key为过滤器的实例名,value为过滤器的全类名 --》在dubbo接口执行之前,会进入拦截器里面 --》
  • 在拦截器里面 --》先获取CompositeConfig配置,如果配置项不存在或者开关未开启,提前return --》否则,获取配置项,优先上下文配置,获取dubbo接口全路径,不存在的话,获取Config中的数据 --》读取配置项,入参为原始配置 + dubbo执行信息,在工具类里面获取dubboConfig --》获取超期时间 --》如果获取的配置为空,执行invoke方法调用远程rpc,否则获取上下文,然后生成调用id --》获取应用程序信息,group信息,版本信息,接口名和方法名,入参类型信息(用逗号链接),入参信息(用逗号链接) --》使用 + 将上述全部信息连接后返回 --》获取db数据(album),由上下文+dubbo信息查询album中是否存在数据,如果为空,返回null,否则 --》判断是否有设置超期时间,如果没有设置,返回album对应的值,–》如果已经超期了,从album中删除数据,否则,返回album对应的值 --》有值,说明近期有调用,AsyncRpcResult返回该值,否则,没有结果
  • 执行rpc调用,拿到返回结果,如果返回结果没有异常,将结果写入到album中,入参为上下文id,dubbo组装参数后的id,rpc调用的结果,超期时间 --》album如果没有key,初始化,然后以dubbo组装参数后的id为key,rpc结果,超期时间,当前时间这三个字段组装的对象为value,存入map中
  • 如果这个过程中发生了异常,分类讨论,如果执行了远程rpc,并且结果非空,返回执行结果,结果为空,抛出异常 --》没有执行远程rpc,此时调用远程rpc接口,并返回
  • Action:这个兜底逻辑中,执行远程rpc后,没有把执行结构放入到album中
  • 4、afterimage-boot 启动afterimage
  • 实现了切面逻辑 ,源码分析如下
  • 注入切面的逻辑
  • 5、afterimage-core 核心类,
  • 定义了spi拓展接口:
  • cn.gov.zcy.afterimage.core.config.Config:可用于配置读取、监听的扩展
  • cn.gov.zcy.afterimage.core.album.Album:用于存储调用结果
  • 6、afterimage-boot-dubbo模块
  • AfterimageBootFilter实现了dubbo filter,使用代理设计模式,在调用dubbo接口前,先查询album是否有返回结果,在dubbo接口调用之后,将调用id和rpc结果放入到album中
  • 执行时机:生产方
  • 执行过程简述:先获取dubbo配置,查询Config中配置是否开启,没开启,执行远程rpc,否则,查询配置项,有方法入参查询超期时间,配置超期时间,执行rpc调用,最后清理db(album) 数据
  • 可以类似于redis中:缓存时间到期了,清理redis缓存
  • Action:这个操作不优雅,它是在每次调用dubbo接口时,判断当前执行的方法有没有过期,可以模仿redis删除key的实现思路
  • 添加Activate注解,标识其为被代理对象,其注解含义如下
  • group :所属组:提供者,只能在服务提供端使用
  • 前提:需要引入对应captor才会优化相应的调用
  • 配置项为:afterimage.boot.dubbo.config
  • 配置格式:接口名1#方法名1=过期时间毫秒&方法名2=过期时间毫秒,接口名2#方法名1&方法名2=过期时间
  • 可用 * 匹配所有方法名;过期时间单位为毫秒,当未配置或者小于1时,代表不过期,特别注意:当被优化方法执行完毕时,执行期间存储的调用将自动失效。
  • 配置eg: com.A#a=1&b&c=2,com.B#*=1
  • 目前不支持重载方法不同配置
  • 在resources目录下新建META-INF文件夹,然后建立子文件夹dubbo,最后新建文件com.alibaba.dubbo.rpc.Filter --》key为过滤器的实例名,value为过滤器的全类名
  • 在服务提供端接口返回之前,会进入拦截器里面 --》首先获取CompositeConfig配置,如果配置项不存在或者开关未开启,执行dubbo接口invoke业务逻辑 --》否则,获取配置项详情,原始配置 格式如:接口名#方法名=过期时间&方法名=过期时间,接口名#方法名=过期时间&方法名=过期时间 --》获取配置详情,如果为空,跳过,否则 --》去除全部空格,接口的配置用’,'隔开,接口名和方法使用“#”分割,如果不合规范,跳过 --》如果当前的接口名与入参接口名相符,继续匹配方法的参数,使用“&”分割,然后使用 “=” 分割入参的key和value,如果key value不是一个pair,跳过,否则,获取入参的key --》如果key为通配符“*” 或者符合入参方法名,执行DubboConfig方法 --》设置超期时间,目前只有expireMills一个配置项,返回DubboConfig —》如果获取到的DubboConfig对象为null,执行dubbo业务逻辑并返回,否则 --》调用startAfterimageManage,底层为AfterimageManage的start1方法,入参为超期时间 --》然后执行dubbo invoke执行业务方法 --》最后,调用AfterimageManage的end方法清理数据
  • Action:这个过滤器如果执行报错,不需要补偿吗?
  • 残影系统使用的设计模式:
  • 1、代理模式 在dubbo invoke之前和之后执行某些操作
  • 2、filter模式:拦截器设计模式
  • 源码分析:
  • 入口:切面AfterimageAspectj
  • 在构造器里面初始化,如果已经初始化,提前return,否则,调用AfterimageManage初始化数据 --》对ConfigLoader进行初始化 --》对AlbumLoader进行初始化 --》环切操作,先判断ConfigLoader中“afterimage.spring.enabled”配置项是否打开,如果没有打开,直接执行业务逻辑,否则 --》调用start0开始执行切面逻辑,然后执行业务逻辑,最后执行残影的清理操作(end方法)
  • AfterimageManage --》初始化init,如果已经初始化,return,否则 --》初始化项目,
  • ConfigLoader
  • order_key:afterimage.config.order
  • PATH = “META-INF/afterimage/ConfigProvider.def” 使用系统配置
  • order:1000
  • name:SystemConfig
  • providerClassName:cn.gov.zcy.afterimage.core.config.SystemConfigProvider
  • CompositeConfig CONFIG
  • 初始化,如果CONFIG非空,说明已经被初始化了,提前return --》 由固定的PATH查询Spi order_key拓展信息 --》加载资源,由path获取类加载器中的urls,–》如果加载出的资源为空,return,否则 --》解析路径,如果路径长度不等于3,抛出异常,否则 --》定义SpiModel,并组装顺序、名称、类名 --》按顺序排序 --》定义组合配置CompositeConfig,将SpiModel转换为CompositeConfig --》按key为name,value为spiModel构建为map --》指定顺序排序(afterimage–config–order) --》循环遍历SpiModel,通过类名获取类实例,然后添加到配置中
  • AlbumLoader
  • ALBUM_KEY = “afterimage.album”
  • PATH = “META-INF/afterimage/AlbumProvider.def”
  • ALBUM
  • List < SpiModel> SPI_MODELS
  • order :0
  • name:SoftReferenceAlbum
  • providerClassName:cn.gov.zcy.afterimage.core.album.reference.SoftReferenceAlbumProvider
  • 初始化 --》如果CONFIG非空,说明已经被初始化了,提前return --》 由固定的PATH查询Spi拓展信息 --》加载资源,由path获取类加载器中的urls,–》如果加载出的资源为空,return,否则 --》解析路径,如果路径长度不等于3,抛出异常,否则 --》定义SpiModel,并组装顺序、名称、类名 --》按顺序排序 --》按key为name,value为spiModel构建为map --》指定顺序排序(afterimage–config–order) --》循环遍历SpiModel,通过类名获取类实例,然后添加到配置中
  • 加载:–》获取SPI_MODELS的第一条数据, --》如果指定了CompositeConfig,使用指定的,否则 --》调用ConfigLoader初始化接口,返回CONFIG --》从配置项中读取“afterimage.album”,使用指定的spiModel --》获取单签拓展点实例信息 --》添加钩子函数,在程序结束时自动销毁album
  • 强制清除方法 forceClear --》获取残影上下文,如果为空,提前return,否则 --》由AlbumLoader获取ALBUM,做清理工作 --》然后由残影上下文中移除ThreadLocal数据
  • start0
  • 执行时机
  • 当进入切面后
  • 业务逻辑:
  • 当某线程连续调用start时,只有第一次的配置生效 --》入参为残影注解,如果没有配置过期时间,返回null --》入参中的captor非空,循环遍历captorConfig --》组装captor(目前仅为dubbo接口),config(dubbo接口的全路径)–》组装到配置项AfterimageConfig中 --》然后调用start(afterimageConfig)方法执行后续逻辑 --》
  • 当嵌套多次start时,计数器会加1,调用end是减1,当为0时,代表上下文安全结束 --》判断是否是新的上下文,如果通过Local能获取上下文,返回该数据,否则 --》 创建一个空的上下文到Local中,返回Local --》计数器自增,如果计数器值不为1,返回false,否则,将入参中的配置放入上下文中,然后返回true
  • start1
  • 执行时机
  • 对于每一个执行的dubbo,都会进入拦截器里面去,然后判断有没有匹配上,有配置上,重新计算超期时间
  • 业务逻辑
  • 当某线程连续调用start时,只有第一次的配置生效 --》过期时间毫秒-为null或小于1,将不过期 --》获取Local里面的上下文,如果数据非空,返回上下文,否则 --》初始化Local后返回 --》计数器自增,如果计数器不为1,返回false,否则,组装配置后,返回true
  • Action:计数器起的作用是啥? 返回的true,false是啥意思?
  • 计数器是为空防止一次请求中,进入切面里面多次
  • Action:提供的两filter方法会拦截全部的dubbo接口,这样做不会影响性能吗?
  • start(expireMills, captorConfigList) 当某线程连续调用start时,只有第一次的配置生效
  • end 在结束后必须调用end --》获取Local中的上下文,如果上下文为空,抛错异常,否则 --》计数器自减 --》如果数量不为0,返回false,标识在其它上下文之中,不用清理数据,否则 --》返回true,获取Album,做清理操作,清理上下文信息,return
  • SystemConfigProvider 系统配置提供方
  • SoftReferenceAlbumProvider

3、SPI总结

1、利用Dubbo SPI机制提供的良好拓展性

  • 1、整个框架中针对不同的场景,恰到好处地使用了各种设计模式
  • 2、基于Dubbo SPI 加载机制,让整个框架的接口和具体实现完全解耦合

2、缓存思想的运用

  • 先获取dubbo配置,查询db(album)中是否存在该dubbo接口执行结果,有结果,直接返回该数据,否则,执行远程rpc调用,然后将方法入参和调用结果缓存到db(album)中
  • 先获取dubbo配置,查询Config中配置是否开启,没开启,执行远程rpc,否则,查询配置项,有方法入参查询超期时间,配置超期时间,执行rpc调用,最后清理db(album) 数据
相关文章
|
29天前
|
缓存 Dubbo Java
Dubbo线程模型设计解析
该文章主要介绍了Dubbo线程模型的设计解析,包括Dubbo作为一个支持大量并发请求的网络框架的特点,以及其线程模型的工作原理。
|
11天前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
37 3
|
10天前
crash扩展 —— trace解析
crash扩展 —— trace解析
|
11天前
|
存储 关系型数据库 MySQL
深入解析 MySQL 中的扩展
【8月更文挑战第31天】
11 0
|
2月前
|
域名解析 安全 物联网
阿里云EMAS HTTPDNS 扩展全球服务节点:提升解析安全性与网络覆盖
阿里云EMAS HTTPDNS新增国内西南、华南及国际欧洲、美东服务节点,提升了全球覆盖能力与性能。作为高效域名解析服务,EMAS HTTPDNS针对互联网、汽车、物流、IOT等行业提供支持,解决了传统解析易遭劫持等问题。新增节点优化了就近调度功能,显著缩短响应时间并增强了服务稳定性和连续性,尤其为中国企业的海外业务提供了强有力的支持。此次扩展展现了阿里云对服务质量的持续追求和全球市场布局的战略思考。
|
1月前
|
域名解析 编解码 负载均衡
【域名解析DNS专栏】域名解析中的EDNS扩展:提升DNS协议灵活性
在互联网中,DNS作为连接用户与网络资源的关键桥梁,其传统协议在面对复杂网络环境时显现出局限性。EDNS(扩展机制)应运而生,通过在DNS请求和响应中添加额外选项和字段,提升了DNS的功能和灵活性。EDNS不仅提高了查询效率和支持更大范围的数据类型,还能增强安全性并通过负载均衡提升系统稳定性。例如,允许指定更大的UDP数据包大小以减少分片和重传,支持DNSSEC加强安全性验证,以及通过Python示例代码展示了如何在DNS查询中使用EDNS选项。随着技术发展,EDNS将在域名解析领域扮演更重要角色。
61 0
|
2月前
|
传感器 芯片
嵌入式通信协议全解析:SPI、I²C、UART详解(附带面试题)
通信是指人与人或人与自然之间通过某种行为或媒介进行的信息交流与传递。从广义上来说,通信是指需要信息的双方或多方在不违背各自意愿的情况下采用任意方法、任意媒质,将信息从某方准确安全地传送到另方。在出现电波传递通信后,通信被单一解释为信息的传递,是指由一地向另一地进行信息的传输与交换,其目的是传输消息。通信方式包括利用“电”来传递消息的电信,这种通信具有迅速、准确、可靠等特点,且几乎不受时间、地点、空间、距离的限制,因而得到了飞速发展和广泛应用。
373 0
|
2月前
|
传感器 编解码 API
【STM32开发入门】温湿度监测系统实战:SPI LCD显示、HAL库应用、GPIO配置、UART中断接收、ADC采集与串口通信全解析
SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。
|
2月前
|
负载均衡 Java 微服务
Java中的可扩展微服务架构设计案例解析
Java中的可扩展微服务架构设计案例解析
|
13天前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件

热门文章

最新文章

推荐镜像

更多