一、目标
分析SpringCloud插件源码,理清插件的设计思路和运作原理。
二、内容
上一节内容,我们一起体验了Soul网关SpringCloud插件的使用。这一节内容,就让我们一起来看一下SpringCloud插件。
2.1 springCloud 服务注册到网关
先看 SoulSpringCloudClientConfiguration,这是Soul网关SpringCloud插件的配置类
@Configuration
public class SoulSpringCloudClientConfiguration {
//SpringCloud客户端bean后处理器
@Bean
public SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
return new SpringCloudClientBeanPostProcessor(soulSpringCloudConfig, env);
}
//Context寄存器监听
@Bean
public ContextRegisterListener contextRegisterListener(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
return new ContextRegisterListener(soulSpringCloudConfig, env);
}
//soul网关配置类,负责加载服务配置文件关于soul-admin注册url等相关信息
@Bean
@ConfigurationProperties(prefix = "soul.springcloud")
public SoulSpringCloudConfig soulSpringCloudConfig() {
return new SoulSpringCloudConfig();
}
}
2.1.1 springCloudClientBeanPostProcessor方法解析
在soulSpringCloudConfig加载完成之后,会注入到上面的springCloudClientBeanPostProcessor方法中:
@Bean
public SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
return new SpringCloudClientBeanPostProcessor(soulSpringCloudConfig, env);
}
接下来看一下SpringCloudClientBeanPostProcessor这个类,这个类实现了Spring里面的BeanPostProcessor接口,重写了postProcessAfterInitialization方法。
-
postProcessAfterInitialization方法:在任何bean初始化回调之后,将此BeanPostProcessor应用于给定的新bean实例。bean将已经被属性值填充。返回的bean实例可能是原始bean的包装器。
对于FactoryBean,将为FactoryBean实例和FactoryBean创建的对象调用此回调(从Spring2.0开始)。后处理器可以通过相应的FactoryBean检查bean实例来决定是应用于FactoryBean还是应用于创建的对象,或者两者都应用。
实例化aw触发短路后,也将调用此回调areBeanPostProcessor.postProcessBeforeInstantiation方法;
- 里面的核心处理方法如下,会去调用RegisterUtils.doRegister()方法 。postProcessBeforeInstantiation方法会扫描带有SoulSpringCloudClient注解的方法,之后发起真正的注册。
... SoulSpringCloudClient clazzAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), SoulSpringCloudClient.class); if (Objects.nonNull(clazzAnnotation)) { if (clazzAnnotation.path().indexOf("*") > 1) { String finalPrePath = prePath; executorService.execute(() -> RegisterUtils.doRegister(buildJsonParams(clazzAnnotation, finalPrePath), url, RpcTypeEnum.SPRING_CLOUD)); return bean; } prePath = clazzAnnotation.path(); } ...
- RegisterUtils.doRegister()方法如下,将之前组装的相关配置信息传递给soul-admin,该类方法是所有插件客户端的通用注册方法
public static void doRegister(final String json, final String url, final RpcTypeEnum rpcTypeEnum) { try { String result = OkHttpTools.getInstance().post(url, json); if (AdminConstants.SUCCESS.equals(result)) { log.info("{} client register success: {} ", rpcTypeEnum.getName(), json); } else { log.error("{} client register error: {} ", rpcTypeEnum.getName(), json); } } catch (IOException e) { log.error("cannot register soul admin param, url: {}, request body: {}", url, json, e); } }
- buildJsonParams()方法如下,组成json格式的参数:
private String buildJsonParams(final SoulSpringCloudClient soulSpringCloudClient, final String prePath) { String contextPath = config.getContextPath(); String appName = env.getProperty("spring.application.name"); String path = contextPath + prePath + soulSpringCloudClient.path(); String desc = soulSpringCloudClient.desc(); String configRuleName = soulSpringCloudClient.ruleName(); String ruleName = ("".equals(configRuleName)) ? path : configRuleName; SpringCloudRegisterDTO registerDTO = SpringCloudRegisterDTO.builder() .context(contextPath) .appName(appName) .path(path) .pathDesc(desc) .rpcType(soulSpringCloudClient.rpcType()) .enabled(soulSpringCloudClient.enabled()) .ruleName(ruleName) .build(); return OkHttpTools.getInstance().getGson().toJson(registerDTO); }
2.1.2 contextRegisterListener
- ContextRegisterListener 类实现了Spring里面的ApplicationListener接口,重写了onApplicationEvent方法:
public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) { if (!registered.compareAndSet(false, true)) { return; } if (config.isFull()) { RegisterUtils.doRegister(buildJsonParams(), url, RpcTypeEnum.SPRING_CLOUD); } }
ContextRegisterListener 主要作用是在spring启动时,接收上下文刷新事件后,获取SoulSpringCloudConfig中full属性,如果为true的话,会自动注册contextPath下所有的url。
-
AbstractSoulPlugin.execute处打断点,这是插件处理的入口处。可以进入springCloud插件处理的逻辑。
AbstractSoulPlugin实现了SoulPlugin接口,SoulPlugin接口在之前divide插件的文章中已经分析过了,可以参考:
https://blog.csdn.net/qq_38314459/article/details/112760726
三、总结
今天一起看了SpringCloud插件的注册原理,插件之间很很多共同的地方。在理解共同的地方之后再去看不同的地方,最后再整合起来一起看,这样会理解的更加清楚。