Soul网关源码学习04

Soul网关源码学习04

soul-client 数据同步

soul-client 将元数据进行同步到soul-admin,支持dubbo、springMVC、springCloud、sofa等协议。

客户端注解

@SoulDubboClient、@SoulSofaClient、@SoulSpringCloudClient、@SoulSpringMvcClient 客户端自定义注解,bean实例化后获取appName、地址、接口元数据等信息同步到soul-admin,注解作用域ElementType.TYPE, ElementType.METHOD,描述类、接口、方法。

 	//请求路径
    String path();
	//规则名称
    String ruleName() default "";
 	//描述信息
    String desc() default "";
	//使用协议
    String rpcType() default "http";
	//注册开关
    boolean enabled() default true;
	//注册元数据
    boolean registerMetaData() default false;

@SoulSpringCloudClient 微服务客户端自定义注解,功能和参数基本同上。

客户端类

各协议同步服务处理类:SpringMvcClientBeanPostProcessor、SpringCloudClientBeanPostProcessor、AlibabaDubboServiceBeanPostProcessor、ApacheDubboServiceBeanPostProcessor等。

SoulSpringMvcClientConfiguration 配置 SpringMvc 的客户端。

@Configuration
public class SoulSpringMvcClientConfiguration {
    
	//bean对象初始化后,将使用自定义注解的客户端信息,同步到soul-admin
    @Bean
    public SpringMvcClientBeanPostProcessor springHttpClientBeanPostProcessor(SoulSpringMvcConfig config) {
        return new SpringMvcClientBeanPostProcessor(config);
    }
    
	//事件的监听器
    @Bean
    public ContextRegisterListener contextRegisterListener(final SoulSpringMvcConfig soulSpringMvcConfig) {
        return new ContextRegisterListener(soulSpringMvcConfig);
    }
    
  	//配置文件
    @Bean
    @ConfigurationProperties(prefix = "soul.http")
    public SoulSpringMvcConfig soulHttpConfig() {
        return new SoulSpringMvcConfig();
    }
}

SpringMvcClientBeanPostProcessor 实现 BeanPostProcessor 重写了 postProcessAfterInitialization 方法在bean初始化后被调用。

public Object postProcessBeforeInitialization( Object bean, String beanName) throws BeansException {
    if (soulSpringMvcConfig.isFull()) {
        return bean;
    }
    //查找类中,是否存在对应的注解,如果有,就返回此注解,没有就返回空
    Controller controller = AnnotationUtils.findAnnotation(bean.getClass(), Controller.class);
    RestController restController = AnnotationUtils.findAnnotation(bean.getClass(), RestController.class);
    RequestMapping requestMapping = AnnotationUtils.findAnnotation(bean.getClass(), RequestMapping.class);
    if (controller != null || restController != null || requestMapping != null) {
        String contextPath = soulSpringMvcConfig.getContextPath();
        SoulSpringMvcClient clazzAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), SoulSpringMvcClient.class);
        String prePath = "";
        if (Objects.nonNull(clazzAnnotation)) {
            //在类上使用通配符*
            if (clazzAnnotation.path().indexOf("*") > 1) {
                String finalPrePath = prePath;
                 //线程池执行同步
                executorService.execute(() -> post(buildJsonParams(clazzAnnotation, contextPath, finalPrePath)));
                return bean;
            }
            //获取对应path
            prePath = clazzAnnotation.path();
        }
        final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(bean.getClass());
        for (Method method : methods) {
            //方法上是否存在对应的注解
            SoulSpringMvcClient soulSpringMvcClient = AnnotationUtils.findAnnotation(method, SoulSpringMvcClient.class);
            if (Objects.nonNull(soulSpringMvcClient)) {
                String finalPrePath = prePath;
                //线程池执行同步
                executorService.execute(() -> post(buildJsonParams(soulSpringMvcClient, contextPath, finalPrePath)));
            }
        }
    }
    return bean;
}

//组装接口参数
private String buildJsonParams(SoulSpringMvcClient soulClient, String contextPath, String prePath) {
    String appName = soulClient.getAppName();
    Integer port = soulSpringMvcConfig.getPort();
    String path = contextPath + prePath + soulClient.path();
    String desc = soulSpringMvcClient.desc();
    String configHost = soulClient.getHost();
    String host = ("".equals(configHost) || null == configHost) ? IpUtils.getHost() : configHost;
    String configRuleName = soulSpringMvcClient.ruleName();
    String ruleName = ("".equals(configRuleName)) ? path : configRuleName;
    SpringMvcRegisterDTO registerDTO = SpringMvcRegisterDTO.builder()
        .context(contextPath)
        .host(host)
        .port(port)
        .appName(appName)
        .path(path)
        .pathDesc(desc)
        .rpcType(soulClient.rpcType())
        .enabled(soulClient.enabled())
        .ruleName(ruleName)
        .registerMetaData(soulSpringMvcClient.registerMetaData())
        .build();
    return OkHttpTools.getInstance().getGosn().toJson(registerDTO);
}

SpringMvc 和 SpringCloud 处理流程逻辑基本一致,SpringCloud不需要传递端口从注册中心获取。

AlibabaDubboServiceBeanPostProcessor 监听ContextRefreshedEvent事件,初始化加载完成后触发。

    @Override
    public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
        if (Objects.nonNull(contextRefreshedEvent.getApplicationContext().getParent())) {
            return;
        }
		//获取dubbo所有服务提供者
        Map<String, ServiceBean> serviceBean = contextRefreshedEvent.getApplicationContext().getBeansOfType(ServiceBean.class);
        for (Map.Entry<String, ServiceBean> entry : serviceBean.entrySet()) {
            //线程池执行接口与 soul-admin 的同步
            executorService.execute(() -> handler(entry.getValue()));
        }
    }
	
	//通过组装服务信息:appName、Interface、methodName、参数类型
    private String buildJsonParams( ServiceBean serviceBean,  SoulDubboClient soulDubboClient,  Method method) {
        String appName = dubboConfig.getAppName();
        if (StringUtils.isEmpty(appName)) {
            appName = serviceBean.getApplication().getName();
        }
        String path = dubboConfig.getContextPath() + soulDubboClient.path();
        String desc = soulDubboClient.desc();
        String serviceName = serviceBean.getInterface();
        String configRuleName = soulDubboClient.ruleName();
        String ruleName = ("".equals(configRuleName)) ? path : configRuleName;
        String methodName = method.getName();
        Class<?>[] parameterTypesClazz = method.getParameterTypes();
        String parameterTypes = Arrays.stream(parameterTypesClazz).map(Class::getName).collect(Collectors.joining(","));
        MetaDataDTO metaDataDTO = MetaDataDTO.builder()
                .appName(appName)
                .serviceName(serviceName)
                .methodName(methodName)
                .contextPath(dubboConfig.getContextPath())
                .path(path)
                .ruleName(ruleName)
                .pathDesc(desc)
                .parameterTypes(parameterTypes)
                .rpcExt(buildRpcExt(serviceBean))
                .rpcType(RpcTypeEnum.DUBBO.getName())
                .enabled(soulDubboClient.enabled())
                .build();
        return OkHttpTools.getInstance().getGson().toJson(metaDataDTO);
    }

	//组装group、版本号、负载均衡算法、超时时间、重试次数
    private String buildRpcExt(final ServiceBean<?> serviceBean) {
        MetaDataDTO.RpcExt build = MetaDataDTO.RpcExt.builder()
                .group(StringUtils.isNotEmpty(serviceBean.getGroup()) ? serviceBean.getGroup() : "")
                .version(StringUtils.isNotEmpty(serviceBean.getVersion()) ? serviceBean.getVersion() : "")
                .loadbalance(StringUtils.isNotEmpty(serviceBean.getLoadbalance()) ? serviceBean.getLoadbalance() : Constants.DEFAULT_LOADBALANCE)
                .retries(Objects.isNull(serviceBean.getRetries()) ? Constants.DEFAULT_RETRIES : serviceBean.getRetries())
                .timeout(Objects.isNull(serviceBean.getTimeout()) ? Constants.DEFAULT_CONNECT_TIMEOUT : serviceBean.getTimeout())
                .url("")
                .build();
        return OkHttpTools.getInstance().getGson().toJson(build);

    }

1、初始化加载完成后获取所有dubbo的服务提供者,使用自定义注解标记方法同步数据到soul-admin 。
2、组装dubbo的提供服务的接口之后 soul-web使用dubbo泛化的方式进行调用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值