(五)soul中springcloud数据注册到soul-admin

(五)soul中springcloud数据注册到soul-admin

目标

  • springcloud的接口信息获取调用soul-admin源码分析
  • soul-admin的soul-client/springcloud-register具体处理
  • SpringCloudClientBeanPostProcessor的postProcessAfterInitialization方法怎么被调用的

springcloud数据注册到soul-admin源码分析

 <dependency>
     <groupId>org.dromara</groupId>
     <artifactId>soul-spring-boot-starter-client-springcloud</artifactId>
     <version>2.2.1</version>
 </dependency>

1 :soul-spring-boot-starter-client-springcloud 里面就一个类:soul-spring-boot-starter-client-springcloud 下面依次分析:
SoulSpringCloudConfig 获取yml文件配置的

    @Bean
    @ConfigurationProperties(prefix = "soul.springcloud")
    public SoulSpringCloudConfig soulSpringCloudConfig() {
        return new SoulSpringCloudConfig();
    }

2:ContextRegisterListener ,监听器使用上下文,从类的命名我们大概就猜出这个类具体干什么的,

    @Bean
    public ContextRegisterListener contextRegisterListener(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
        return new ContextRegisterListener(soulSpringCloudConfig, env);
    }
// 初始化之前先要初始化SoulSpringCloudConfig类,下面是ContextRegisterListener的核心代码:

    @Override
    public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
        //防并发同时初始化
        if (!registered.compareAndSet(false, true)) {
            return;
        }
      //soul.springclou.full的配置,如果配置的true,直接把 contextPath/** ,
        if (config.isFull()) {
             //通过OkHttpTools工具请求接口:http://localhost:9095/soul-client/springcloud-register调用soul-admin, 
            RegisterUtils.doRegister(buildJsonParams(), url, RpcTypeEnum.SPRING_CLOUD);
        }
    }

    private String buildJsonParams() {
        String contextPath = config.getContextPath();
        String appName = env.getProperty("spring.application.name");
        String path = contextPath + "/**";
        SpringCloudRegisterDTO registerDTO = SpringCloudRegisterDTO.builder()
                .context(contextPath)
                .appName(appName)
                .path(path)
                .rpcType(RpcTypeEnum.SPRING_CLOUD.getName())
                .enabled(true)
                .ruleName(path)
                .build();
        return OkHttpTools.getInstance().getGson().toJson(registerDTO);
    }
 soul:
     springcloud:
       admin-url: http://localhost:9095
       context-path: /order-service
       full: false
   # adminUrl: 为你启动的soul-admin 项目的ip + 端口,注意要加http://
   # contextPath: 为你的这个mvc项目在soul网关的路由前缀, 比如/order ,/product 等等,网关会根据你的这个前缀来进行路由.
   # full: 设置true 代表代理你的整个服务,false表示代理你其中某几个controller

3: 初始化SpringCloudClientBeanPostProcessor,实现BeanPostProcessor,
spring容器初始化单例对象是【InstantiationAwareBeanPostProcessor】:提前执行;先触发:postProcessBeforeInstantiation();如果有返回值:触发postProcessAfterInitialization(),具体怎么调用,我在文章最后分析

  @Bean
     public SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
         return new SpringCloudClientBeanPostProcessor(soulSpringCloudConfig, env);
     }


//SpringCloudClientBeanPostProcessor的核心方法postProcessAfterInitialization

    @Override
    public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
        if (config.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 prePath = "";
           //获取类上得注解值
            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();
            }
            final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(bean.getClass());
            for (Method method : methods) {
                //获取方法上得注解值
                SoulSpringCloudClient soulSpringCloudClient = AnnotationUtils.findAnnotation(method, SoulSpringCloudClient.class);
                if (Objects.nonNull(soulSpringCloudClient)) {
                   //会把类的值拼接下
                    String finalPrePath = prePath;
                    executorService.execute(() -> RegisterUtils.doRegister(buildJsonParams(soulSpringCloudClient, finalPrePath), url,
                            RpcTypeEnum.SPRING_CLOUD));
                }
            }
        }
        return bean;
    }

soul-admin的soul-client/springcloud-register具体处理

http://localhost:9095/soul-client/springcloud-register调用soul-admin,会走到如下方法


    @Override
    @Transactional
    public synchronized String registerSpringCloud(final SpringCloudRegisterDTO dto) {
        MetaDataDO metaDataDO = metaDataMapper.findByPath(dto.getContext() + "/**");
        if (Objects.isNull(metaDataDO)) {
            saveSpringCloudMetaData(dto);
        }
        String selectorId = handlerSpringCloudSelector(dto);
        handlerSpringCloudRule(selectorId, dto);
        return SoulResultMessage.SUCCESS;
    }

进到方法:saveSpringCloudMetaData
1: 保存数据到meta_data表
2: spring发布事件eventPublisher.publishEvent ,这里明天分析

    // publish AppAuthData's event
    eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, DataEventTypeEnum.CREATE,
            Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDO))));

SpringCloudClientBeanPostProcessor的postProcessAfterInitialization方法怎么被调用的

看下图,我们打个断点在postProcessAfterInitialization方法上,再一次看它的调用栈,我们需要从spring的初始化对象入手,深入底层
在这里插入图片描述

spring核心类AbstractApplicationContext的方法refresh,

refresh里面有13个带this方法

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                 //重点方法,下面分析的
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

this.finishBeanFactoryInitialization(beanFactory); 字面意思:完成初始化所有剩下的单实例bean

finishBeanFactoryInitialization:初始化SpringCloudClientBeanPostProcessor对象,
关键逻辑

  • 1:获取Bean的定义信息
  • 2:【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
  • 3:创建Bean实例 createBeanInstance(beanName, mbd, args)
  • 4: Bean属性赋值 populateBean(beanName, mbd, instanceWrapper);
  • 5: Bean初始化 initializeBean(beanName, exposedObject, mbd);
    • 1: wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    • 2: this.invokeInitMethods(beanName, wrappedBean, mbd);
    • 3: wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  • 6:【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
  • 6:注册Bean的销毁方法
  • 7:将创建的Bean添加到缓存中singletonObjects,ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息

terInitialization(wrappedBean, beanName);

  • 6:【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
  • 6:注册Bean的销毁方法
  • 7:将创建的Bean添加到缓存中singletonObjects,ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值