轻量级Rpc框架设计--motan源码解析三:服务暴露前的初始化检查工作

本文阐述Motan框架如何通过实现InitializingBean接口,确保服务暴露前的基础配置、协议及注册中心配置正确。若缺失,框架将自动生成默认值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一, 服务暴露前的初始化工作

1.1 实现InitializingBean接口

motan通过实现InitializingBean接口, 实现afterPropertiesSet()方法, 完成服务暴露前的三项初始化工作:

①checkAndConfigBasicConfig(); // 检查并配置basicConfig

②checkAndConfigExport(); //检查是否已经装配export,如果没有则到basicConfig查找

③checkAndConfigRegistry(); //检查并配置registry

@Override
    public void afterPropertiesSet() throws Exception {

        // 注意:basicConfig需要首先配置,因为其他可能会依赖于basicConfig的配置, 即从spring容器取数据, 给BasicServiceInterfaceConfig类的属性赋值
        checkAndConfigBasicConfig();
        // 检查和配置export和protocol
        checkAndConfigExport();
        // 检查并配置registry, 即从spring容器取数据, 给AbstractInterfaceConfig类的属性赋值
        checkAndConfigRegistry();

        // 等spring初始化完毕后,再export服务
        // export();
    }

1.2 checkAndConfigBasicConfig();检查并配置basicConfig

private void checkAndConfigBasicConfig() {
        if (getBasicServiceConfig() == null) {
        	
        	// 从静态变量中取出已经解析过的basicConfig配置, 可能basicConfig配置了多个
        	// 注意这里的name, 就是指的是 <motan:basicService>标签配置的id, 为serviceBasicConfig
            for (String name : MotanNamespaceHandler.basicServiceConfigDefineNames) {
            	
            	// 根据bean id和bean 类型, 从spring的beanfactory获取bean.
                BasicServiceInterfaceConfig biConfig = beanFactory.getBean(name, BasicServiceInterfaceConfig.class);
                if (biConfig == null) {
                    continue;
                }
                if (MotanNamespaceHandler.basicServiceConfigDefineNames.size() == 1) {
                    setBasicServiceConfig(biConfig);
                } else if (biConfig.isDefault() != null && biConfig.isDefault().booleanValue()) {
                    setBasicServiceConfig(biConfig);
                }
            }
        }
    }

在一开始motan框架解析server端的xml配置文件时, 就将xml配置文件中的每个标签所对应的配置属性, 与其包装类进行了一一对应. 如:

  ①server端xml中对于注册中心的配置, 则其包装类就是RegistryConfig进行封装的

<motan:registry regProtocol="zookeeper" name="registry" address="127.0.0.1:2181"/>
public class RegistryConfig extends AbstractConfig {
    private static final long serialVersionUID = 3236055928361714933L;
    // 注册配置名称
    private String name;
    // 注册协议
    private String regProtocol;
    // 注册中心地址,支持多个ip+port,格式:ip1:port1,ip2:port2,ip3,如果没有port,则使用默认的port
    private String address;
    // 注册中心缺省端口
    private Integer port;
    // 注册中心请求超时时间(毫秒)
    private Integer requestTimeout;
    // 注册中心会话超时时间(毫秒)
    private Integer registrySessionTimeout;
    // 失败后重试的时间间隔
    private Integer registryRetryPeriod;
    // 启动时检查注册中心是否存在
    private String check;
    // 在该注册中心上服务是否暴露
    private Boolean register;
    // 在该注册中心上服务是否引用
    private Boolean subscribe;
    private Boolean isDefault;
    // vintage的配置移除策略,@see #RegistryConfig#Excise
    private String excise;

            ....
            .... 省略get/set方法
            ....

②server端xml中对Protocol协议的配置, 则是使用ProtocolConfig包装类

<motan:protocol id="demoMotan" default="true" name="motan"
                    requestTimeout="220" maxServerConnection="80000" maxContentLength="1048576"
                    maxWorkerThread="800" minWorkerThread="20"/>
public class ProtocolConfig extends AbstractConfig {

    private static final long serialVersionUID = 7605496816982926360L;
    // 服务协议
    private String name;
    // 序列化方式
    private String serialization;
    // 协议编码
    private String codec;
    // IO线程池大小
    private Integer iothreads;
    // 请求超时
    protected Integer requestTimeout;
    // client最小连接数
    protected Integer minClientConnection;
    // client最大连接数
    protected Integer maxClientConnection;
    // 最小工作pool线程数
    protected Integer minWorkerThread;
    // 最大工作pool线程数
    protected Integer maxWorkerThread;
    // 请求响应包的最大长度限制
    protected Integer maxContentLength;
    // server支持的最大连接数
    protected Integer maxServerConnection;
    // 连接池管理方式,是否lifo
    protected Boolean poolLifo;
    // 是否延迟init
    protected Boolean lazyInit;
    // endpoint factory
    protected String endpointFactory;
    // 采用哪种cluster 的实现
    protected String cluster;
    // loadbalance 方式
    protected String loadbalance;
    // high available strategy
    protected String haStrategy;
    // server worker queue size
    protected Integer workerQueueSize;
    // server accept connections count
    protected Integer acceptConnections;
    // proxy type, like jdk or javassist
    protected String proxy;
    // filter, 多个filter用","分割,blank string 表示采用默认的filter配置
    protected String filter;
    // retry count if call failure
    protected Integer retries;
    // if the request is called async, a taskFuture result will be sent back.
    protected Boolean async;
    // 是否缺省配置
    private Boolean isDefault;
    // 扩展参数
    private Map<String, String> parameters;
        ....
        .... 省略get/set方法
        ....

③server端对motan:basicService标签解析, 与其包装类BasicServiceInterfaceConfig

<motan:basicService requestTimeout="220" export="demoMotan:8002"
                        group="motan-demo-rpc" accessLog="false" shareChannel="true" module="motan-demo-rpc"
                        application="myMotanDemo" registry="registry" id="serviceBasicConfig"/>
public class AbstractInterfaceConfig extends AbstractConfig {
    private static final long serialVersionUID = 4776516803466933310L;
    // 暴露、使用的协议,暴露可以使用多种协议,但client只能用一种协议进行访问,原因是便于client的管理
    protected List<ProtocolConfig> protocols;
    // 注册中心的配置列表
    protected List<RegistryConfig> registries;
    // 扩展配置点
    protected ExtConfig extConfig;
    // 应用名称
    protected String application;
    // 模块名称
    protected String module;
    // 分组
    protected String group;
    // 服务版本
    protected String version;
    // 代理类型
    protected String proxy;
    // 过滤器
    protected String filter;
    // 最大并发调用
    protected Integer actives;
    // 是否异步
    protected Boolean async;
    // 服务接口的失败mock实现类名
    protected String mock;
    // 是否共享 channel
    protected Boolean shareChannel;
    // if throw exception when call failure,the default value is ture
    protected Boolean throwException;
    // 请求超时时间
    protected Integer requestTimeout;
    // 是否注册
    protected Boolean register;
    // 是否记录访问日志,true记录,false不记录
    protected String accessLog;
    // 是否进行check,如果为true,则在监测失败后抛异常
    protected String check;
    // 重试次数
    protected Integer retries;
    // 是否开启gzip压缩
    protected Boolean usegz;
    // 进行gzip压缩的最小阈值,usegz开启,且大于此值时才进行gzip压缩。单位Byte
    protected Integer mingzSize;
    protected String codec;
        ....
        .... 省略get/set方法
        ....

所以经过上面的说明, 该checkAndConfigBasicConfig()方法就是针对<motan:basicService>该标签及其属性做合法性校验, 检查其是否存在, 存在的话, 就将该封装类设置进ServiceConfig, 以供后来进行服务暴露时, 引用.

1.3 checkAndConfigExport(); 检查是否已经装配export,如果没有则到basicConfig查找

①首先检查<motan:basicService>标签配置了export, 当然我们这里的demo已经配置了export, 如下:

 <motan:basicService requestTimeout="220" export="demoMotan:8002"
                        group="motan-demo-rpc" accessLog="false" shareChannel="true" module="motan-demo-rpc"
                        application="myMotanDemo" registry="registry" id="serviceBasicConfig"/>

②再判断basicService标签配置是否配置protocol

③如果配置文件中没有配置protocol, 就默认随机生成一个motan:随机port端口

private void checkAndConfigExport() {
    	// 首先判断basicServiceConfig是否配置了export
    	// 判断basicService的export是否为空
        if (StringUtils.isBlank(getExport()) && getBasicServiceConfig() != null
                && !StringUtils.isBlank(getBasicServiceConfig().getExport())) {
        	// basicService标签配置的export不为空, 则使用该属性
            setExport(getBasicServiceConfig().getExport());
            // 判断basicService标签配置是否配置protocol
            if (getBasicServiceConfig().getProtocols() != null) {
                setProtocols(new ArrayList<ProtocolConfig>(getBasicServiceConfig().getProtocols()));
            }
        }
        // 如果配置文件中没有配置protocol, 就默认随机生成一个motan:随机port端口
        if(CollectionUtil.isEmpty(getProtocols()) && StringUtils.isNotEmpty(getExport())){
            int port = MathUtil.parseInt(export, 0);
            if(port > 0){
                export = MotanConstants.PROTOCOL_MOTAN + ":" + export;
                setProtocol(MotanFrameworkUtil.getDefaultProtocolConfig());
            }
        }
        // 如果还是没有export和port, 直接抛出异常
        if (StringUtils.isEmpty(getExport()) || CollectionUtil.isEmpty(getProtocols())) {
            throw new MotanFrameworkException(String.format("%s ServiceConfig must config right export value!", getInterface().getName()),
                    MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
        }
    }

1.4 checkAndConfigRegistry(); 检查并配置registry

①首先都是判断basicServiceConfig中是否配置了registry

②如果basicServiceConfig没有的话, 就将motan框架一开始解析xml文件<motan:registry>标签的包装类RegistryConfig, 根据beanId从spring容器中获取, 并将其设置进AbstractInterfaceConfig抽象类的registries变量保存下来.

private void checkAndConfigRegistry() {
    	// 首先都是判断basicServiceConfig中是否配置了registry
        if (CollectionUtil.isEmpty(getRegistries()) && getBasicServiceConfig() != null
                && !CollectionUtil.isEmpty(getBasicServiceConfig().getRegistries())) {
        	// 如果basicServiceConfig中有的话, 就使用该配置下的registry 
            setRegistries(getBasicServiceConfig().getRegistries());
        }
        // 如果basicServiceConfig中也没有的配置registry的话, getRegistries()也还是空的
        if (CollectionUtil.isEmpty(getRegistries())) {
        	// 从MotanNamespaceHandler类的静态变量中获取registryDefineNames, 该变量是spring
        	// 解析xml配置文件时, 注入的
            for (String name : MotanNamespaceHandler.registryDefineNames) {
            	// 从spring的beanFactory根据id或者name, 获取registryConfig
                RegistryConfig rc = beanFactory.getBean(name, RegistryConfig.class);
                if (rc == null) {
                    continue;
                }
                if (MotanNamespaceHandler.registryDefineNames.size() == 1) {
                    setRegistry(rc);
                } else if (rc.isDefault() != null && rc.isDefault().booleanValue()) {
                    setRegistry(rc);
                }
            }
        }

二, 总结:

motan通过实现InitializingBean接口的方式, 并且实现其afterPropertiesSet()方法, 从而检查服务暴露前一些必要的属性, 如basicService基础配置是否存在, protocol协议以及registry注册中心是否均已经配置, 没有配置的话, motan框架就会自己生成一个默认值, 以供服务暴露时使用.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值