提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、Dubbo的功能
- 拆分服务、屏蔽底层细节,解耦;减少Jar包大小
- 服务治理(负载均衡、注册与发现、访问量统计、服务监控、灰度发布)
二、Rpc比Http的优势
Rpc | Http | 所以 | |
---|---|---|---|
序列化方式 | 针对二进制协议(如Hessian)做序列化与反序列化 | 基于文本,比如json | 编码后的二进制数据小了,存储空间的硬件成本小了,传输带宽小了,系统的吞吐量变大 |
传输协议 | 基于TCP|IP协议,分别是传输层和网络层 | 额外多了应用层、表示层、会话层 | 少了这三层 |
连接方式 | 长连接 | 大多都是短连接 | 减少了因为连接损耗的时间 |
三、Netty的优势
- jdk nio类库与api繁杂,api使用简单,开发门槛低
- 预置了很多编码功能,支持多种主流协议
- 可以通过Channelhandler对通信框架进行灵活的扩展
- 综合性能最优、已经修复了jdk已知的所有bug
四、Spi
1、Spi的优点
- 1 支持缓存,实例缓存在cacheInstances中,通过map获取
// key:extensionName,value:Instance
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
// 这里查缓存里的instance
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
- 2 Dubbo的SPI上有默认值
private String cachedDefaultName;
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
// 这里赋值,后面用于动态生成适配器里的代码
if (names.length == 1) cachedDefaultName = names[0];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
- 3.支持AOP与IOC
private Set<Class<?>> cachedWrapperClasses;
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
.....
else if (isWrapperClass(clazz)) {
// 1.1 刘峻峰 如果是包装类,会在这里先cache,当getExtension的时候,会把get到的实例再包装一层
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
}
.....
}
private T createExtension(String name) {
...
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
// 1.2 刘峻峰 调用包装类的有参构造方法,把这些类再包装起来
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
...
}