一, 服务暴露前的初始化工作
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框架就会自己生成一个默认值, 以供服务暴露时使用.