【中间件常用写法】中间件如何加载和控制类

一. 导读

每一个框架都有客户端和服务端,一般客户端只需要引入一个包,然后通过注解自动开启客户端,这是如何做到的?
有的框架,比如 Seata 没有引入 spring ,就无法使用 spring 的注解来定义bean,那么它是如何管控实例的?
框架代码肯定不全是写死的,那运行时加载是如何做到的?

二. Spring boot 如何加载管理实例

Spring boot 主要是通过 ApplicationContext 来作bean的容器,通过注解来识别需要被管理的bean。
Spring Cloud 中大量的用 starter包代替传统的包,主要就是因为使用 starter 可以不用在启动类上加注解,通过约定的默认路径 resources/META-INF 来加载自定义配置类。下面是 sb 启动时的加载:

SpringApplication构造函数 --> setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class)  
  -->SpringFactoriesLoader.loadFactoryNames --> loadSpringFactories(ClassLoader) --> classLoader.getResources(resource/META-INF)

使用类加载器来加载默认路径下的文件,加载格式:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=自定义配置类

在自定义类中,可以通过注解,进行类的扫描和一些自定义bean的引入,非常方便。

sb 引入传统的包,需要在启动类上加注解,通过注解来扫描包中需要被spring管理的bean。类似:

@EnableInterceptor
@EnableDatabase
@Import(SupportAutoConfiguration.class)
public @interface EnableSupport {
}

这个注解加载启类上,启动类识别 @import ,引入 SupportAutoConfiguration ,进行类的加载。

不管传统的方式还是starter,都需要一个入口,来引入需要被管理的bean。

三. Seata如何加载和管理实例

首先看一下 Seata common包中 EnhancedServiceLoader 加载器的用法:

EnhancedServiceLoader.load(class,ClassLoader) 
  --> loadFile(Class,String,Classloader,Class[],Object[])
  --> findAllExtensionClass(service, activateName, loader)
  --> initInstance(service, extension, argTypes, args)
  --> Class.newInstance()

主要就是根据 class的全名称 ,查找指定目录下 (META-INF/seata) 是否有这个类全名称命名的文件,按行读取文件中配置的 class ,通过 Class.forName() 加载class,缓存到 providers 中,最后通过 newInstance 实例化返回。
使用 CurrentHashMap 缓存class (不是实例) :

private static Map<Class, List<Class>> providers = new ConcurrentHashMap<Class, List<Class>>();

一个 class 对应的是一个列表,因为一个抽象类可以有多个实现,通过注解 @LoadLevel 来决定如何加载,注解中有name和order参数,name 优先。

最后通过获取到的实例,就可以调用对应的方法。

这里主要用的就是SPI机制来加载文件,通过double-check-lock来防止并发问题。通过SPI,可以不用在启动时就加载文件,而是在扩展方法被调用时,通过运行时参数加载文件。这也是为什么 map 中缓存的是类而不是实例。

四. 总结

想要在运行时根据参数加载类,就一定要有一个入口,可以是约定好的,然后通过运行时加载进行框架的扩展,避免纯写死在代码中。实例的缓存一般就是使用 ConcurrentHashMap 进行缓存,要注意读写并发问题和可能多次实例化问题。

.

.
推荐几个不错的博客:
dubbo SPI自适应扩展
自定义starter

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值