предисловие
Краткое введениеspi
некоторые основные понятия, но на самом делеDubbo
В jdk's spi внесены некоторые улучшения. В чем конкретно заключается улучшение? Давайте посмотрим на описание документа.
- Стандартный SPI JDK будет создавать экземпляры всех реализаций точек расширения одновременно.Если есть реализации расширений, инициализация занимает много времени, но если они не используются, они будут загружены, что будет пустой тратой ресурсов.
- Если точка расширения не загружается, даже имя точки расширения будет недоступно. Например: стандартный JDK ScriptEngine, получить имя типа сценария через getName(), но если RubyScriptEngine не может загрузить класс RubyScriptEngine, потому что jruby.jar, от которого он зависит, не существует, причина этой ошибки съедена, и она не соответствует ruby.Когда пользователь выполняет скрипт ruby, он сообщит, что ruby не поддерживается, а не настоящая причина сбоя.
- Добавлена поддержка точек расширения IoC и AOP, точка расширения может напрямую внедрять сеттеры в другие точки расширения.
По пониманию прочитанного китайского языка начальной школы нетрудно обобщить, что на самом деле提高了性能
а также增加了功能
.Многие друзья любят спрашивать, чтение исходного кода не так хорошо, как с чего начать и что подготовить.Если просто прочитать исходный код примерно и усвоить общую идею, по сути, это почти то же самое, что и понимание чтения начальная школа китайского языка и чтение картинок и написание домашних заданий (вы можете увидеть эту статью. Все они полностью соответствуют этому условию, так что не бойтесь. Но чтобы понять идею, хорошо узнайте детали и даже напишите лучший фреймворк , то есть четыре слова ->终身学习
.(Например, теперь обратите внимание на официальный аккаунт Фей Чао, общайтесь и обсуждайте вместе, и обучение на протяжении всей жизни начнется немедленно)
Для чтения исходного кода, конечно, есть еще какие-то хитрости.
Толстяк столкнулся с багом и нужно было ввести многопоточность.В итоге после внедрения многопоточности появилось два бага
Видно, что многопоточность действительно является головной болью для всех, поэтому позже я также продемонстрирую некоторые советы, такие как
-
如何调试多线程代码(手把手实战,不讲理论)
-
如何查看代理对象源码(手把手实战,不讲理论)
Модифицированный даббоspi
Как повысить производительность и какие функции добавляются, об этом и пойдет речь в этой статье.
Вопросы для интервью в прямом эфире
-
Поскольку у вас есть определенное понимание spi, есть ли разница между spi dubbo и spi jdk?Если да, то в чем разница?
-
Вы сказали, что видели исходный код Dubbo, а затем вкратце скажите, какие детали его конструкции заставляют вас думать, что она очень гениальна? (
区分度高
)
Предзнаменование концепции
даббо拓展点机制
Это требует много очков знаний, а также это сложное место в dubbo, отличается от предыдущей отказоустойчивости кластера.Cluster
,Directory
,Router
,LoadBalance
То же ключевое слово, это拓展点机制
Есть также несколько ключевых слов,SPI
,Adaptive
,Activate
, Они будут объяснены один за другим и, наконец, подытожены.
Сразу к делу
Повысить производительность
Какой самый простой способ повысить производительность? На самом деле, это то же самое, что и политический ответ в средней школе, есть универсальная формула, то есть «кэш». , веб-интерфейс, Java и т. д. и т. д.), если это связано с повышением производительности, перейти к кешу**方向
Ответ однозначно правильный (конечно, по схеме "по пунктам" ответ в сторону тайника просто не даст получить 0 баллов, но仅仅
**Ответ Кэш точно не получит полную оценку) Так что если сравнивать с jdk's spi, то могут быть следующие моменты
1. С точки зрения «универсальной формулы» увеличить кеш
Потому что некоторые друзья пишут, что им нравится вставлять код в форму, поэтому объяснение есть в комментариях.
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)//拓展点类型非空判断
throw new IllegalArgumentException("Extension type == null");
if(!type.isInterface()) {//拓展点类型只能是接口
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if(!withExtensionAnnotation(type)) {//需要添加spi注解,否则抛异常
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
//从缓存EXTENSION_LOADERS中获取,如果不存在则新建后加入缓存
//对于每一个拓展,都会有且只有一个ExtensionLoader与其对应
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
private ExtensionLoader(Class<?> type) {
this.type = type;
//这里会存在递归调用,ExtensionFactory的objectFactory为null,其他的均为AdaptiveExtensionFactory
//AdaptiveExtensionFactory的factories中有SpiExtensionFactory,SpringExtensionFactory
//getAdaptiveExtension()这个是获取一个拓展装饰类对象.细节在下篇讲解
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
Ниже приведен объект точки расширения кеша.
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
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;
}
Зачем это выносить отдельно?Многие знакомые склонны к невнимательности,думая что кеш это не более чем оценка есть он или нет,а добавление .dubbo это как раз то же самое.Я не знаю исходников.Но если вы обратите немного внимания, вы обнаружите, что он хорошо справляется с деталями.
Стук по доске
В предыдущей статье [Говоря о механизме родительского делегирования в ядре Dubbo] я подчеркивал, что независимо от того, что вы делаете, вы должны формировать различия.JVM
а также并发包
, Поскольку мы упоминали в предыдущей статьеJVM
Связанный контент (механизм родительского делегирования), то мы поговорим об этой статье并发包
связанный контент. Давайте внимательнее посмотрим на предыдущий абзацdouble-checked locking
код
//double-checked locking
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
instance = createExtension(name);
holder.set(instance);
}
}
}
public class Holder<T> {
private volatile T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
Почему он используется здесьvolatile
А как насчет ключевых слов? Глядя на исходный код, важнее увидеть эти детали. Дьявол скрывается в деталях! Изначально Фей Чао хотел расширить этот вопрос.volatile
Покажите волну операций, но, к сожалению, место ограничено, что я дам вам ключевое слово.doubleCheck Singleton 重排序
, то ищите это в браузере.Потом прочитайте результаты первой страницы поиска,вы будете знать что этот код не так прост как вы думаете,но это так же просто как добавление кеша.Это то что я часто говорю , Одна из причин, по которой трудно получить глубокое представление о параллельных пакетах, не занимаясь разработкой промежуточного программного обеспечения.
2. Анализ с точки зрения аннотаций
Так как это сравнениеspi
разница есть и в даббо@spi
Эта аннотация, затем давайте проследим за аннотацией, чтобы увидеть, какие подсказки можно найти.
Если вы использовали даббо в течение 15 лет, вы заметите@Extension
Эта аннотация, но позже от нее отказались из-за ее широкого значения, была заменена на@SPI
.
@SPI("javassist")
public interface Compiler {
//省略...
}
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER; // copy reference
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {
compiler = loader.getDefaultExtension();
}
return compiler.compile(code, classLoader);
}
//com.alibaba.dubbo.common.compiler.Compiler 文件配置如下
adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler
javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler
Нам не составит труда разобрать два пункта из приведенных выше двух частей кода и конфигурационных файлов (если вы не знакомы с spi, пожалуйста, прочитайте сначала предыдущий spi(1), если фундамент не сильно расшатан, его нельзя проанализировано)
- JDK
spi
Используйте цикл for, а затем, если суждение может получить указанный объект spi, dubbo может получить его с указанным ключом.
//返回指定名字的扩展
public T getExtension(String name){}
- JDK
spi
Значение по умолчанию не поддерживается, dubbo добавляет дизайн значения по умолчанию
//@SPI("javassist")代表默认的spi对象,比如Compiler默认使用的是javassist,可通过
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
compiler = loader.getDefaultExtension();
//方式获取实现类,根据配置,即为
//com.alibaba.dubbo.common.compiler.support.JavassistCompiler
добавить функцию
Добавлен функционал, как сказано в документации,spi
повысилсяIoC
,AOP
AOP
Это старая тема, говоря оAOP
Легче всего думатьSpring
, даже потому чтоAOP
Его часто используют в бизнес-сценариях, и многие даже думают, чтоAOP
Это бизнес, — предложил Со Фэй Чао.初学者
учитьсяAOP
Маршрут примерно такой:
// 这一步步演进的过程,才是最大的收获
装饰者设计模式->静态代理->JDK、cglib、Javassist优缺点对比->AOP源码
напиши в конце
Feichao — это технический публичный аккаунт, в котором основное внимание уделяется принципам, исходному коду и навыкам разработки, оригинальному тематическому анализу исходного кода в аккаунте и реальному сражению принципов исходного кода в реальных сценах (ключевые моменты).Отсканируйте QR-код нижеОбратите внимание на Фей Чао, пусть те, кто должен строить ракеты, перестанут трахаться!