简介
dubbo框架spring Schema扩展机制与Spring集成,在spring初始化时候加载dubbo的配置类。 dubbo服务导出的入口类是ServiceBean的onApplicationEvent方法 ServiceBean的继承关系如下
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
private static final long serialVersionUID = 213195494150089726L;
private static transient ApplicationContext SPRING_CONTEXT;
private final transient Service service;
private transient ApplicationContext applicationContext;
private transient String beanName;
private transient boolean supportedApplicationListener;
public ServiceBean() {
this.service = null;
}
public ServiceBean(Service service) {
super(service);
this.service = service;
}
public static ApplicationContext getSpringContext() {
return SPRING_CONTEXT;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
if (applicationContext != null) {
SPRING_CONTEXT = applicationContext;
try {
Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class);
method.invoke(applicationContext, this);
this.supportedApplicationListener = true;
} catch (Throwable var5) {
if (applicationContext instanceof AbstractApplicationContext) {
try {
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class);
if (!method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(applicationContext, this);
this.supportedApplicationListener = true;
} catch (Throwable var4) {
;
}
}
}
}
}
public void setBeanName(String name) {
this.beanName = name;
}
public Service getService() {
return this.service;
}
public void onApplicationEvent(ContextRefreshedEvent event) {
//如果不延迟导出且exported和unexported都为false 执行导出
if (this.isDelay() && !this.isExported() && !this.isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + this.getInterface());
}
this.export();
}
}
private boolean isDelay() {
//调用父类`AbstractServiceConfig`中方法
Integer delay = this.getDelay();
ProviderConfig provider = this.getProvider();
if (delay == null && provider != null) {
//调用父类`AbstractServiceConfig`中getDelay方法
delay = provider.getDelay();
}
//delay == -1表示不需要延迟导出
return this.supportedApplicationListener && (delay == null || delay == -1);
}
}
public ProviderConfig getProvider() {
return this.provider;
}
supportedApplicationListener 变量含义,该变量用于表示当前的 Spring 容器是否支持 ApplicationListener,这个值初始为 false。在 Spring 容器将自己设置到 ServiceBean 中时,ServiceBean 的 setApplicationContext 方法会检测 Spring 容器是否支持 ApplicationListener。若支持,则将 supportedApplicationListener 置为 true。
this.export()调用ServiceConfig中方法
public synchronized void export() {
//如果provider存在,从provider中取export和delay属性
if (this.provider != null) {
if (this.export == null) {
this.export = this.provider.getExport();
}
if (this.delay == null) {
this.delay = this.provider.getDelay();
}
}
//如果未导出 判断delay决定立即导出 还是延迟导出
if (this.export == null || this.export) {
if (this.delay != null && this.delay > 0) {
delayExportExecutor.schedule(new Runnable() {
public void run() {
ServiceConfig.this.doExport();
}
}, (long)this.delay, TimeUnit.MILLISECONDS);
} else {
this.doExport();
}
}
}
doExport
protected synchronized void doExport() {
if (this.unexported) {
throw new IllegalStateException("Already unexported!");
} else if (!this.exported) {
this.exported = true;
if (this.interfaceName != null && this.interfaceName.length() != 0) {
this.checkDefault();
if (this.provider != null) {
if (this.application == null) {
this.application = this.provider.getApplication();
}
if (this.module == null) {
this.module = this.provider.getModule();
}
if (this.registries == null) {
this.registries = this.provider.getRegistries();
}
if (this.monitor == null) {
this.monitor = this.provider.getMonitor();
}
if (this.protocols == null) {
this.protocols = this.provider.getProtocols();
}
}
if (this.module != null) {
if (this.registries == null) {
this.registries = this.module.getRegistries();
}
if (this.monitor == null) {
this.monitor = this.module.getMonitor();
}
}
if (this.application != null) {
if (this.registries == null) {
this.registries = this.application.getRegistries();
}
if (this.monitor == null) {
this.monitor = this.application.getMonitor();
}
}
// 检测 ref 是否为泛化服务类型
if (this.ref instanceof GenericService) {
this.interfaceClass = GenericService.class;
if (StringUtils.isEmpty(this.generic)) {
// 设置 generic = "true"
this.generic = Boolean.TRUE.toString();
}
} else {
try {
this.interfaceClass = Class.forName(this.interfaceName, true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException var5) {
throw new IllegalStateException(var5.getMessage(), var5);
}
//检查接口中是否有MethodConfig中定义的方法名称,没有抛异常
this.checkInterfaceAndMethods(this.interfaceClass, this.methods);
//检查ref类型是否合法
this.checkRef();
// 设置 generic = "true"
this.generic = Boolean.FALSE.toString();
}
//如果loal = true 或stub = true 加载并检查本地实现是否合法
Class stubClass;
if (this.local != null) {
if ("true".equals(this.local)) {
this.local = this.interfaceName + "Local";
}
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(this.local);
} catch (ClassNotFoundException var4) {
throw new IllegalStateException(var4.getMessage(), var4);
}
if (!this.interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The local implementation class " + stubClass.getName() + " not implement interface " + this.interfaceName);
}
}
if (this.stub != null) {
if ("true".equals(this.stub)) {
this.stub = this.interfaceName + "Stub";
}
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(this.stub);
} catch (ClassNotFoundException var3) {
throw new IllegalStateException(var3.getMessage(), var3);
}
if (!this.interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + this.interfaceName);
}
}
// 检测各种对象是否为空,为空则新建,或者抛出异常
//检查dubbo.application.name 设置系统属性dubbo.service.shutdown.wait和dubbo.service.shutdown.wait.seconds
this.checkApplication();
//检查RegistryConfig并使用set方法反射设置属性(先从系统属性中取)
this.checkRegistry();
//设置ProtocalConfig并使用set方法反射设置属性(先从系统属性中取)
this.checkProtocol();
//设置当前ServiceConfig并使用set方法反射设置属性(先从系统属性中取)
appendProperties(this);
this.checkStubAndMock(this.interfaceClass);
if (this.path == null || this.path.length() == 0) {
this.path = this.interfaceName;
}
this.doExportUrls();
// ProviderModel 表示服务提供者模型,此对象中存储了与服务提供者相关的信息。
// 比如服务的配置信息,服务实例等。每个被导出的服务对应一个 ProviderModel。
// ApplicationModel 持有所有的 ProviderModel。
ProviderModel providerModel = new ProviderModel(this.getUniqueServiceName(), this, this.ref);
ApplicationModel.initProviderModel(this.getUniqueServiceName(), providerModel);
} else {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
}
}
//检查接口类型是否合法
//遍历MethodConfig中方法,检查接口中是否有MethodConfig中定义的方法名称,没有抛异常
protected void checkInterfaceAndMethods(Class<?> interfaceClass, List<MethodConfig> methods) {
if (interfaceClass == null) {
throw new IllegalStateException("interface not allow null!");
} else if (!interfaceClass.isInterface()) {
throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
} else {
if (methods != null && methods.size() > 0) {
Iterator i$ = methods.iterator();
while(i$.hasNext()) {
MethodConfig methodBean = (MethodConfig)i$.next();
String methodName = methodBean.getName();
if (methodName == null || methodName.length() == 0) {
throw new IllegalStateException("<dubbo:method> name attribute is required! Please check: <dubbo:service interface=\"" + interfaceClass.getName() + "\" ... ><dubbo:method name=\"\" ... /></<dubbo:reference>");
}
boolean hasMethod = false;
Method[] arr$ = interfaceClass.getMethods();
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; ++i$) {
Method method = arr$[i$];
if (method.getName().equals(methodName)) {
hasMethod = true;
break;
}
}
if (!hasMethod) {
throw new IllegalStateException("The interface " + interfaceClass.getName() + " not found method " + methodName);
}
}
}
}
}
//检查ref类型是否合法
private void checkRef() {
if (this.ref == null) {
throw new IllegalStateException("ref not allow null!");
} else if (!this.interfaceClass.isInstance(this.ref)) {
throw new IllegalStateException("The class " + this.ref.getClass().getName() + " unimplemented interface " + this.interfaceClass + "!");
}
}
doExportUrls
loadRegistries 加载注册中心链接,然后再遍历 ProtocolConfig 集合导出每个服务。并在导出服务的过程中,将服务注册到注册中心。 loadRegistries 方法主要包含如下的逻辑: 检测是否存在注册中心配置类,不存在则抛出异常 构建参数映射集合,也就是 map 构建注册中心链接列表 遍历链接列表,并根据条件决定是否将其添加到 registryList 中
private void doExportUrls() {
List<URL> registryURLs = this.loadRegistries(true);
Iterator i$ = this.protocols.iterator();
while(i$.hasNext()) {
ProtocolConfig protocolConfig = (ProtocolConfig)i$.next();
this.doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
protected List<URL> loadRegistries(boolean provider) {
//检查注册中心配置
this.checkRegistry();
List<URL> registryList = new ArrayList();
if (this.registries != null && this.registries.size() > 0) {
Iterator i$ = this.registries.iterator();
label75:
while(true) {
RegistryConfig config;
String address;
do {
do {
do {
if (!i$.hasNext()) {
return registryList;
}
config = (RegistryConfig)i$.next();
address = config.getAddress();
// 若 address 为空,则将其设为 0.0.0.0
if (address == null || address.length() == 0) {
address = "0.0.0.0";
}
// 从系统属性中加载注册中心地址
String sysaddress = System.getProperty("dubbo.registry.address");
if (sysaddress != null && sysaddress.length() > 0) {
address = sysaddress;
}
} while(address == null);
} while(address.length() <= 0);
} while("N/A".equalsIgnoreCase(address));
Map<String, String> map = new HashMap();
// 添加 ApplicationConfig 中的字段信息到 map 中
appendParameters(map, this.application);
// 添加 RegistryConfig 字段信息到 map 中
appendParameters(map, config);
// 添加 path、pid,protocol 等信息到 map 中
map.put("path", RegistryService.class.getName());
map.put("dubbo", Version.getVersion());
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put("pid", String.valueOf(ConfigUtils.getPid()));
}
if (!map.containsKey("protocol")) {
if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
map.put("protocol", "remote");
} else {
map.put("protocol", "dubbo");
}
}
// 解析得到 URL 列表,address 可能包含多个注册中心 ip,
// 因此解析得到的是一个 URL 列表
List<URL> urls = UrlUtils.parseURLs(address, map);
Iterator i$ = urls.iterator();
while(true) {
URL url;
do {
if (!i$.hasNext()) {
continue label75;
}
url = (URL)i$.next();
url = url.addParameter("registry", url.getProtocol());
// 将 URL 协议头设置为 registry
url = url.setProtocol("registry");
} while((!provider || !url.getParameter("register", true)) && (provider || !url.getParameter("subscribe", true)));
registryList.add(url);
}
}
} else {
return registryList;
}
}
//解析address 如果address以;或|符号分隔 则拆分后解析 返回List<URL>
public static List<URL> parseURLs(String address, Map<String, String> defaults) {
if (address != null && address.length() != 0) {
String[] addresses = Constants.REGISTRY_SPLIT_PATTERN.split(address);
if (addresses != null && addresses.length != 0) {
List<URL> registries = new ArrayList();
String[] arr$ = addresses;
int len$ = addresses.length;
for(int i$ = 0; i$ < len$; ++i$) {
String addr = arr$[i$];
registries.add(parseURL(addr, defaults));
}
return registries;
} else {
return null;
}
} else {
return null;
}
}
public static URL parseURL(String address, Map<String, String> defaults) {
if (address != null && address.length() != 0) {
String url;
//1 如果包含:// 直接返回url
//2 否则用,拆分成address数组 后拼接url
// 以172.19.103.55:2181,172.19.103.57:2181,172.19.103.54:2181为例
// 返回172.19.103.55:2181?backup=172.19.103.57:2181,172.19.103.54:2181
if (address.indexOf("://") >= 0) {
url = address;
} else {
String[] addresses = Constants.COMMA_SPLIT_PATTERN.split(address);
url = addresses[0];
if (addresses.length > 1) {
StringBuilder backup = new StringBuilder();
for(int i = 1; i < addresses.length; ++i) {
if (i > 1) {
backup.append(",");
}
backup.append(addresses[i]);
}
url = url + "?backup=" + backup.toString();
}
}
String defaultProtocol = defaults == null ? null : (String)defaults.get("protocol");
if (defaultProtocol == null || defaultProtocol.length() == 0) {
defaultProtocol = "dubbo";
}
String defaultUsername = defaults == null ? null : (String)defaults.get("username");
String defaultPassword = defaults == null ? null : (String)defaults.get("password");
int defaultPort = StringUtils.parseInteger(defaults == null ? null : (String)defaults.get("port"));
String defaultPath = defaults == null ? null : (String)defaults.get("path");
Map<String, String> defaultParameters = defaults == null ? null : new HashMap(defaults);
if (defaultParameters != null) {
defaultParameters.remove("protocol");
defaultParameters.remove("username");
defaultParameters.remove("password");
defaultParameters.remove("host");
defaultParameters.remove("port");
defaultParameters.remove("path");
}
//构造URL
URL u = URL.valueOf(url);
boolean changed = false;
String protocol = u.getProtocol();
String username = u.getUsername();
String password = u.getPassword();
String host = u.getHost();
int port = u.getPort();
String path = u.getPath();
Map<String, String> parameters = new HashMap(u.getParameters());
if ((protocol == null || protocol.length() == 0) && defaultProtocol != null && defaultProtocol.length() > 0) {
changed = true;
protocol = defaultProtocol;
}
if ((username == null || username.length() == 0) && defaultUsername != null && defaultUsername.length() > 0) {
changed = true;
username = defaultUsername;
}
if ((password == null || password.length() == 0) && defaultPassword != null && defaultPassword.length() > 0) {
changed = true;
password = defaultPassword;
}
if (port <= 0) {
if (defaultPort > 0) {
changed = true;
port = defaultPort;
} else {
changed = true;
port = 9090;
}
}
if ((path == null || path.length() == 0) && defaultPath != null && defaultPath.length() > 0) {
changed = true;
path = defaultPath;
}
if (defaultParameters != null && defaultParameters.size() > 0) {
Iterator i$ = defaultParameters.entrySet().iterator();
label119:
while(true) {
String key;
String defaultValue;
String value;
do {
do {
do {
if (!i$.hasNext()) {
break label119;
}
Entry<String, String> entry = (Entry)i$.next();
key = (String)entry.getKey();
defaultValue = (String)entry.getValue();
} while(defaultValue == null);
} while(defaultValue.length() <= 0);
value = (String)parameters.get(key);
} while(value != null && value.length() != 0);
changed = true;
parameters.put(key, defaultValue);
}
}
//如果URL中有username等有一个未指定 则从默认配置读取缺失的配置
if (changed) {
u = new URL(protocol, username, password, host, port, path, parameters);
}
return u;
} else {
return null;
}
}
doExportUrlsFor1Protocol
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
String name = protocolConfig.getName();
//设置dubbo为默认协议
if (name == null || name.length() == 0) {
name = "dubbo";
}
// 添加 side、版本、时间戳以及进程号等信息到 map 中
Map<String, String> map = new HashMap();
map.put("side", "provider");
map.put("dubbo", Version.getVersion());
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put("pid", String.valueOf(ConfigUtils.getPid()));
}
// 通过反射将对象的字段信息添加到 map 中
appendParameters(map, this.application);
appendParameters(map, this.module);
appendParameters(map, this.provider, "default");
appendParameters(map, protocolConfig);
appendParameters(map, this);
//这段代码用于检测 <dubbo:method> 标签中的配置信息,并将相关配置添加到 map 中。
if (this.methods != null && this.methods.size() > 0) {
Iterator i$ = this.methods.iterator();
label188:
while(true) {
MethodConfig method;
List arguments;
do {
do {
if (!i$.hasNext()) {
break label188;
}
method = (MethodConfig)i$.next();
appendParameters(map, method, method.getName());
String retryKey = method.getName() + ".retry";
if (map.containsKey(retryKey)) {
String retryValue = (String)map.remove(retryKey);
if ("false".equals(retryValue)) {
map.put(method.getName() + ".retries", "0");
}
}
arguments = method.getArguments();
} while(arguments == null);
} while(arguments.size() <= 0);
Iterator i$ = arguments.iterator();
while(true) {
ArgumentConfig argument;
Method[] methods;
do {
do {
while(true) {
if (!i$.hasNext()) {
continue label188;
}
argument = (ArgumentConfig)i$.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: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
}
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
}
} while(methods == null);
} 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());
}
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())) {
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 contextPath;
if (ProtocolUtils.isGeneric(this.generic)) {
map.put("generic", this.generic);
map.put("methods", "*");
} else {
contextPath = Version.getVersion(this.interfaceClass, this.version);
if (contextPath != null && contextPath.length() > 0) {
map.put("revision", contextPath);
}
// 为接口生成包裹类 Wrapper,Wrapper 中包含了接口的详细信息,比如接口方法名数组,字段信息等
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 中
map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
}
}
// 添加 token 到 map 中
if (!ConfigUtils.isEmpty(this.token)) {
if (ConfigUtils.isDefault(this.token)) {
map.put("token", UUID.randomUUID().toString());
} else {
map.put("token", this.token);
}
}
if ("injvm".equals(protocolConfig.getName())) {
protocolConfig.setRegister(false);
map.put("notify", "false");
}
contextPath = protocolConfig.getContextpath();
if ((contextPath == null || contextPath.length() == 0) && this.provider != null) {
contextPath = this.provider.getContextpath();
}
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
//上面的代码首先是将一些信息,比如版本、时间戳、方法名以及各种配置对象的字段信息放入到 map 中,map 中的内容将作为 URL 的查询字符串。 构建好 map 后,紧接着是获取上下文路径、主机名以及端口号等信息。最后将 map 和主机名等数据传给 URL 构造方法创建 URL 对象。
URL url = new URL(name, host, port, (contextPath != null && contextPath.length() != 0 ? contextPath + "/" : "") + this.path, map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {
url = ((ConfiguratorFactory)ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol())).getConfigurator(url).configure(url);
}
String scope = url.getParameter("scope");
if (!"none".toString().equalsIgnoreCase(scope)) {
if (!"remote".toString().equalsIgnoreCase(scope)) {
this.exportLocal(url);
}
if (!"local".toString().equalsIgnoreCase(scope)) {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && registryURLs.size() > 0) {
Iterator i$ = registryURLs.iterator();
while(i$.hasNext()) {
URL registryURL = (URL)i$.next();
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = this.loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
Invoker<?> invoker = proxyFactory.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 {
Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
this.exporters.add(exporter);
}
}
}
this.urls.add(url);
}
end
顺便在此给大家推荐一个Java方面的交流学习群:957734884,里面会分享一些高级面试题,还有资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系,主要针对Java开发人员提升自己,突破瓶颈,相信你来学习,会有提升和收获。在这个群里会有你需要的内容 朋友们请抓紧时间加入进来吧