public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
implements Ordered {
/**
* The bean name of {@link DubboBootstrapApplicationListener}
*
* @since 2.7.6
*/
public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
private final DubboBootstrap dubboBootstrap;
public DubboBootstrapApplicationListener() {
this.dubboBootstrap = DubboBootstrap.getInstance();
}
/**
* 在Spring容器初始化完成后执行某个方法 防止onApplicationEvent方法被执行两次
*/
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
/**
* ContextRefreshedEvent 事件会在Spring容器初始化完成会触发该事件
*/
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
/**
* close是spring容器真正销毁了才会触发
*/
private void onContextClosedEvent(ContextClosedEvent event) {
dubboBootstrap.stop();
}
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
}
}
/**
* Start the bootstrap
*/
public DubboBootstrap start() {
// 只初始化一次
if (started.compareAndSet(false, true)) {
ready.set(false);
initialize();
if (logger.isInfoEnabled()) {
logger.info(NAME + " is starting...");
}
// 导入dubbo服务
exportServices();
// Not only provider register
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// 2. export MetadataService
exportMetadataService();
//3. Register the local ServiceInstance if required
registerServiceInstance();
}
referServices();
if (asyncExportingFutures.size() > 0) {
new Thread(() -> {
try {
this.awaitFinish();
} catch (Exception e) {
logger.warn(NAME + " exportAsync occurred an exception.");
}
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
}).start();
} else {
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
}
if (logger.isInfoEnabled()) {
logger.info(NAME + " has started.");
}
}
return this;
}
在start方法中,也会调用initialize方法,之前提到过,服务端启动的时候,dubbo在start方法中调用initialize方法做初始化,而客户端启动的时候会跳过initialize方法。
exportServices方法
initialize方法之后调用exportServices方法,该方法用于暴露服务,服务端使用
private void exportServices() {
//创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
configManager.getServices().forEach(sc -> {
// TODO, compatible with ServiceConfig.export()
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
if (exportAsync) {
异步暴露,使用线程池暴露服务
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future> future = executor.submit(() -> {
//暴露服务
sc.export();
//;//记录所有暴露的服务
exportedServices.add(sc);
});
asyncExportingFutures.add(future);
} else {
sc.export();
exportedServices.add(sc);
}
});
}
public synchronized void export() {
if (this.shouldExport()) {
if (this.bootstrap == null) {
this.bootstrap = DubboBootstrap.getInstance();
this.bootstrap.initialize();
}
this.checkAndUpdateSubConfigs();
this.serviceMetadata.setVersion(this.getVersion());
this.serviceMetadata.setGroup(this.getGroup());
this.serviceMetadata.setDefaultGroup(this.getGroup());
this.serviceMetadata.setServiceType(this.getInterfaceClass());
this.serviceMetadata.setServiceInterfaceName(this.getInterface());
this.serviceMetadata.setTarget(this.getRef());
if (this.shouldDelay()) {
DELAY_EXPORT_EXECUTOR.schedule(this::doExport, (long)this.getDelay(), TimeUnit.MILLISECONDS);
} else {
this.doExport();
}
this.exported();
}
}
hasExportedServices()检查是否配置元数据中心的url,如果配置了,返回true。
exportMetadataService方法用于暴露本地元数据服务
private void exportMetadataService() {
metadataServiceExporters
.stream()
.filter(this::supports)
.forEach(MetadataServiceExporter::export);
}
registerServiceInstance用于将dubbo实例注册到专用于服务发现的注册中心。
referServices方法用于处理ReferenceConfig对象,但是这里有个问题。
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {
String name = protocolConfig.getName();
if (StringUtils.isEmpty(name)) {
name = "dubbo";
}
Map map = new HashMap();
map.put("side", "provider");
appendRuntimeParameters(map);
AbstractConfig.appendParameters(map, this.getMetrics());
AbstractConfig.appendParameters(map, this.getApplication());
AbstractConfig.appendParameters(map, this.getModule());
AbstractConfig.appendParameters(map, this.provider);
AbstractConfig.appendParameters(map, protocolConfig);
AbstractConfig.appendParameters(map, this);
MetadataReportConfig metadataReportConfig = this.getMetadataReportConfig();
if (metadataReportConfig != null && metadataReportConfig.isValid()) {
map.putIfAbsent("metadata-type", "remote");
}
String scope;
Iterator var10;
if (CollectionUtils.isNotEmpty(this.getMethods())) {
Iterator var6 = this.getMethods().iterator();
label172:
while(true) {
MethodConfig method;
List arguments;
do {
if (!var6.hasNext()) {
break label172;
}
method = (MethodConfig)var6.next();
AbstractConfig.appendParameters(map, method, method.getName());
String retryKey = method.getName() + ".retry";
if (map.containsKey(retryKey)) {
scope = (String)map.remove(retryKey);
if ("false".equals(scope)) {
map.put(method.getName() + ".retries", "0");
}
}
arguments = method.getArguments();
} while(!CollectionUtils.isNotEmpty(arguments));
var10 = arguments.iterator();
while(true) {
ArgumentConfig argument;
Method[] methods;
do {
while(true) {
if (!var10.hasNext()) {
continue label172;
}
argument = (ArgumentConfig)var10.next();
if (argument.getType() != null && argument.getType().length() > 0) {
methods = this.interfaceClass.getMethods();
break;
}
if (argument.getIndex() == -1) {
throw new IllegalArgumentException("Argument config must set index or type attribute.eg: or ");
}
AbstractConfig.appendParameters(map, argument, method.getName() + "." + argument.getIndex());
}
} while(methods.length <= 0);
for(int i = 0; i < methods.length; ++i) {
String methodName = methods[i].getName();
if (methodName.equals(method.getName())) {
Class>[] argtypes = methods[i].getParameterTypes();
if (argument.getIndex() != -1) {
if (!argtypes[argument.getIndex()].getName().equals(argument.getType())) {
throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
AbstractConfig.appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
for(int j = 0; j < argtypes.length; ++j) {
Class> argclazz = argtypes[j];
if (argclazz.getName().equals(argument.getType())) {
AbstractConfig.appendParameters(map, argument, method.getName() + "." + j);
if (argument.getIndex() != -1 && argument.getIndex() != j) {
throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
}
}
}
}
}
}
}
}
String host;
if (ProtocolUtils.isGeneric(this.generic)) {
map.put("generic", this.generic);
map.put("methods", "*");
} else {
host = Version.getVersion(this.interfaceClass, this.version);
if (host != null && host.length() > 0) {
map.put("revision", host);
}
String[] methods = Wrapper.getWrapper(this.interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("No method found in service interface " + this.interfaceClass.getName());
map.put("methods", "*");
} else {
map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
}
}
if (ConfigUtils.isEmpty(this.token) && this.provider != null) {
this.token = this.provider.getToken();
}
if (!ConfigUtils.isEmpty(this.token)) {
if (ConfigUtils.isDefault(this.token)) {
map.put("token", UUID.randomUUID().toString());
} else {
map.put("token", this.token);
}
}
this.serviceMetadata.getAttachments().putAll(map);
host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
URL url = new URL(name, host, port, (String)this.getContextPath(protocolConfig).map((p) -> {
return p + "/" + this.path;
}).orElse(this.path), map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {
url = ((ConfiguratorFactory)ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol())).getConfigurator(url).configure(url);
}
scope = url.getParameter("scope");
if (!"none".equalsIgnoreCase(scope)) {
if (!"remote".equalsIgnoreCase(scope)) {
this.exportLocal(url);
}
if (!"local".equalsIgnoreCase(scope)) {
if (CollectionUtils.isNotEmpty(registryURLs)) {
var10 = registryURLs.iterator();
while(var10.hasNext()) {
URL registryURL = (URL)var10.next();
if (!"injvm".equalsIgnoreCase(url.getProtocol())) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
if (url.getParameter("register", true)) {
logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL);
} else {
logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
}
}
String proxy = url.getParameter("proxy");
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter("proxy", proxy);
}
Invoker> invoker = PROXY_FACTORY.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter> exporter = PROTOCOL.export(wrapperInvoker);
this.exporters.add(exporter);
}
}
} else {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
}
Invoker> invoker = PROXY_FACTORY.getInvoker(this.ref, this.interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter> exporter = PROTOCOL.export(wrapperInvoker);
this.exporters.add(exporter);
}
WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter("metadata-type", "local"));
if (metadataService != null) {
metadataService.publishServiceDefinition(url);
}
}
}
this.urls.add(url);
}
dubbo://10.0.73.222:20880/com.jd.dubbo.EchoService?anyhost=true&application=echo-provider&bind.ip=10.0.73.222&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.jd.dubbo.EchoService&metadata-type=remote&methods=echo,hello&pid=74193&release=2.7.8&side=provider&timeout=1000×tamp=1628125664210