Soul源码解析(12)-Soul网关SpringCloud插件源码分析

一、目标

分析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插件的注册原理,插件之间很很多共同的地方。在理解共同的地方之后再去看不同的地方,最后再整合起来一起看,这样会理解的更加清楚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值