在初始化server的注册解析器时,不是封装到xxxConfig中,而是调用servceBean方法
@Override
public void init() {
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
ServiceBean实现了InitializingBean,ApplicationListener两个接口
InitializingBean在容器启动后完成初始化
ApplicationListener在容器创建完调用ContextRefreshedEvent回调函数
主要的两个核心方法
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware,
ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
@Override
@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
//属性设置
...
}
}
先执行afterPropertiesSet(属性设置),将一些信息保存到ServiceBean中
容器刷新完成后
ServiceConfig.class
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
//执行服务暴露
export();
}
}
暴露服务时,先传入路径(数组类型)
ServiceConfig.class
@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
代理工厂先对路径等信息进行包装
再获取协议进行包装
ServiceConfig.class
//获取Invoker
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
protocol,先注册protocol, 再判断使用什么协议,调用相关方法开启协议
RegistryProtocol.class
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//export invoker 判断Protocol类型委托XXXProtocol使用netty(或其他)暴露
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
URL registryUrl = getRegistryUrl(originInvoker);
//registry provider
final Registry registry = getRegistry(originInvoker);
//获取到注册提供者的地址
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
//to judge to delay publish whether or not
boolean register = registedProviderUrl.getParameter("register", true);
//将提供者的信息,注册到表中
ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);
key为端口号, value为执行者的包装
public class ProviderConsumerRegTable {
public static ConcurrentHashMap<String, Set<ProviderInvokerWrapper>> providerInvokers = new ConcurrentHashMap<String, Set<ProviderInvokerWrapper>>();
public static ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>> consumerInvokers = new ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>>();
DubboProtocol 将服务进行暴露
public class DubboProtocol extends AbstractProtocol {
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
...
//打开服务器
openServer(url);
optimizeSerialization(url);
return exporter;
}
private void openServer(URL url) {
// find server.
String key = url.getAddress();
//client can export a service which's only for server to invoke
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
//创建服务器
serverMap.put(key, createServer(url));
} else {
// server supports reset, use together with override
server.reset(url);
}
}
}
private ExchangeServer createServer(URL url) {
...
ExchangeServer server;
try {
//将服务器与当前ip地址进行绑定(传输层的绑定)
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
...
return server;
}
}