最近新项目里面用了cola框架,里面有一个扩展点,特定去撸了一下它的源码,把它整明白了
Cola中提供了一种扩展点的机制,允许我们通过bizId(组织ID)、useCase(使用案例)、scenario(业务场景)三者动态的去选择实现类。有点类似与我们的策略模式,在程序运行的过程中,动态的选择实现类去处理我们的请求。
我就不多做解释了,下面的例子看了,就能明白这个扩展点怎么用了。
1、定义扩展点接口,实现ExtensionPointI
public interface OrganizationExtPt extends ExtensionPointI {
/**
* 根据corpId查询企业下所有部门
*
* @return 部门
*/
String getDepartmentsByCorpId();
}
2、钉钉场景扩展点实现
@Extension(bizId = "organize",useCase = "getByCorpId",scenario = "dingTalk")
public class DingTalkOrganizationExt implements OrganizationExtPt {
@Override
public String getDepartmentsByCorpId() {
System.out.println("在组织结构业务,通过企业编号获取部门列表的用例,在钉钉的场景下业务的实现处理方式");
System.out.println("通过钉钉的配置信息和API获取得到组织信息,并组装成云枢识别的部门信息");
return "钉钉";
}
}
3、微信扩展点接口实现
@Extension(bizId = "organize",useCase = "getByCorpId",scenario = "wechat")
@Slf4j
public class WechatOrganizationExt implements OrganizationExtPt{
public String getDepartmentsByCorpId() {
log.info("业务:组织机构,用例:通过企业编号获取部门 , 场景:企业微信");
log.info("通过企业微信的API获取组织的部门信息,然后包装为需要的部门列表");
return "微信";
}
}
4、扩展点使用
在命令执行器中使用。
@Component
public class OrgazationQueryExe {
@Resource
private ExtensionExecutor extensionExecutor;
public String execute(OrgnizationQry cmd) {
return extensionExecutor.execute(OrganizationExtPt.class, cmd.getBizScenario(),
ex -> ex.getDepartmentsByCorpId());
}
}
5、测试扩展点的使用
@RestController
public class OrganizationController {
@Resource
private OrgazationQueryExe orgazationQueryExe;
@GetMapping(value = "/organization/getDepartmentsByCorpId/{corpId}/{scenario}")
public String listCustomerByName(@PathVariable("corpId") String corpId, @PathVariable("scenario") String scenario){
OrgnizationQry qry = new OrgnizationQry();
qry.setCorpId(corpId);
qry.setIncludeDelete(true);
qry.setBizScenario(BizScenario.valueOf("organize","getByCorpId",scenario));
return orgazationQueryExe.execute(qry);
}
}
第一次使用Cola扩展点后,我就在想,它是怎么找到具体的实现的?而在我们上面的代码实例中,唯一的入口就是下面这段代码:
extensionExecutor.execute(OrganizationExtPt.class, cmd.getBizScenario(),
ex -> ex.getDepartmentsByCorpId());
因此,跟进去看看源代码是怎么实现的。
public <R, T> R execute(Class<T> targetClz, BizScenario bizScenario, Function<T, R> exeFunction) {
// 1.找到负责执行的具体实现类
T component = locateComponent(targetClz, bizScenario);
// 2.执行
return exeFunction.apply(component);
}
继续往下跟的话,发现实现类是从extensionRepository 中获取的。所以,升起了第二个疑问:实现类是什么时候被放到extensionRepository中去的?
这时候,利用IDEA定位到cola有关扩展点源码的位置:
根据SpringBoot自动配置的机制,我们知道ExtensionAutoConfiguration 会被Spring初始化,因此这是我们进一步探究源码的入口。
@Configuration
public class ExtensionAutoConfiguration {
@Bean(initMethod = "init")
@ConditionalOnMissingBean(ExtensionBootstrap.class)
public ExtensionBootstrap bootstrap() {
return new ExtensionBootstrap();
}
@Bean
@ConditionalOnMissingBean(ExtensionRepository.class)
public ExtensionRepository repository() {
return new ExtensionRepository();
}
@Bean
@ConditionalOnMissingBean(ExtensionExecutor.class)
public ExtensionExecutor executor() {
return new ExtensionExecutor();
}
@Bean
@ConditionalOnMissingBean(ExtensionRegister.class)
public ExtensionRegister register() {
return new ExtensionRegister();
}
}
我看名字猜了一下,ExtensionBootstrap很明显与初始化相关,因此就去看一下它到底做了什么。然后大概画了一个流程图。具体的代码我就不带大家一起看了(因为我觉得自己去看代码会更清楚,这代码挺容易看懂的)
简单来说就是:
参考文章:
https://www.cnblogs.com/snidget/p/12961700.html