Расскажите о механизме родительского делегирования из Dubbo kernel-SPI.

Java
Расскажите о механизме родительского делегирования из Dubbo kernel-SPI.

предисловие

Когда дело доходит до Dubbo, мы не можем избежать идеи SPI, потому что это очень важная часть ядра Dubbo, но SPI — это большая тема.Эта статья и предыдущиеАнализ исходного кода Dubbo — простой принцип, интеграция с SpringТочно так же это статья для разогрева знаний на тему анализа исходного кода Dubbo.实际项目Я использовал SPI от Dubbo. Позже я поделюсь с вами тем, как использовать SPI в нашем реальном проекте и как мы оптимизировали SPI в будущем.

Вопросы для интервью в прямом эфире

  • ты понимаешьspi, подскажите что такое spi и зачем использовать spi?

  • Вы понимаете механизм загрузки классов?Расскажите, что такое режим родительского делегирования, какие у него есть недостатки, есть ли знакомые случаи этого недостатка и каков принцип решения этого недостатка?

Краткое введение в spi

если упоминаетсяapiЯ верю, что все знают,spiЕсли да, то об этом знает меньше людей.

Проще говоря,apiдля пользователей,spiЭто для разработчиков.Хороший фреймворк с открытым исходным кодом должен оставлять некоторые точки расширения.Пусть участники пытаются расширяться в черном ящике вместо того, чтобы модифицировать код в белом ящике, иначе будет сложно управлять ответвлениями, качеством, слияниями и конфликтами. И фреймворк То, что может автор, может сделать и разработчик.

С точки зрения использования, это динамическое добавление классов реализации в интерфейс во время выполнения.IoCидея вынесения управления сборкой за пределы программы

Если говорить на примере из жизни, типа плагина для браузера, например, если вилки в стене не хватает, вместо смены вилки мы подключим удлинитель (это не очень уместно, так вы его временно так неравномерно поймёте на ранней стадии))

Никакое количество слов не является абстрактным, поэтому давайте воспользуемся кодом, чтобы просто реализовать его.spi

Простая реализация spi

Интерфейсы и конкретные классы реализации

public interface ISayName {
    void say();
}
public class SayEnglishName implements ISayName{
    @Override
    public void say() {
        System.out.println("Toby");
    }
}
public class SayChineseName implements ISayName{
    @Override
    public void say() {
        System.out.println("肥朝");
    }
}

конфигурационный файл, который необходимо поместить вMETA-INF/services/接口全限定名

com.toby.spi.impl.SayChineseName
com.toby.spi.impl.SayEnglishName

демонстрационная структура каталогов

Результаты теста следующие

Изменяя файл конфигурации, мы можем динамически изменять класс реализации интерфейса.

Внимательные друзья могут обнаружить, что, например, я хочу добавить класс реализацииSayFranceNameImpl, в этом случае еще мало изменить конфигурационный файл, а есть класс реализации в препаке.

Не беспокойтесь об этом, это будет представлено позжеjavassist, то есть технология динамического байт-кода. Таким образом, классы Java могут динамически генерироваться во время выполнения, и нет необходимости заранее помещать в пакет класс реализации интерфейса. Для получения дополнительной информации просто обратите внимание на Feichao.

Конечно, осторожные друзья могли найти его, мне даже это не нужноspi, я использую весенниеiocВы также можете динамически внедрять различные классы реализации через файл конфигурации.

Например, при разработке dubbo я не хочу сильно полагаться на контейнер IoC Spring, но я также чувствую, что он немного перегружен для создания небольшого контейнера IoC. на любых сторонних библиотеках.Оригинальные слова из официальных документов такие

Теоретически Dubbo может полагаться только на JDK для работы без каких-либо сторонних библиотек, просто настройте и используйте стратегии реализации, связанные с JDK.

Стук по доске

Я часто вижу, как люди задают два типа вопросов

  • С таким количеством Java-людей он насыщен?
  • Почему всегда нужно брать интервью, чтобы построить ракету, а потом пойти и закрутить гайку?

Вы можете спросить своего коллегу, знаете ли вы, что такоеspi, если он не знает, как вы думаете, сколько времени ему потребуется, чтобы реализовать приведенный выше простой пример?使用На этом уровне трудно эффективно выделиться.Независимо от того, что вы делаете, если вы хотите выделиться среди конкурентов, вы должны произнести три слова.差异化.

Две области, которые легче различить в Java Foundation:JVMи并发编程Если вы остаетесь только на уровне использования, то нет смысла обращать внимание на блог Фей Чао, поэтому содержание этой статьиspiтакже нужноClassLoaderОбъединить.

учитьсяJVMи并发编程Покупка этой книги имеет важное значение, ссылка на следующее содержание实战Java虚拟机.если вы посмотрите на深入Java虚拟机Неважно, не запутайтесь в каналах получения знаний, никого не волнует, делаете ли вы пятилетний вступительный экзамен в колледж, трехлетнюю симуляцию или же королеву-голодный случай. Следующее содержание отражает часть основного содержания книги, большое спасибо за тяжелую работу автора (я надеюсь, что все поддержат настоящую книгу).

Получить spi из ClassLoader

Краткое введение в ClassLoader

Classиз装载можно условно разделить на加载类,连接类и初始化три этапа, на которых всеClassвсе поClassLoaderЗагрузка, а затем виртуальная машина Java отвечает за подключение, инициализацию и другие операции, то есть она не может пройтиClassLoaderчтобы изменить поведение соединения и инициализации класса.

Виртуальная машина Java создает три категорииClassLoader, соответственно

  • BootStrap ClassLoader(启动类加载器)
  • Extension ClassLoader(扩展类加载器)
  • APP ClassLoader(应用类加载器,也称为系统类加载器)

Кроме того, каждое приложение может также自定义ClassLoader

Родительский режим делегирования ClassLoader

существуетClassLoaderВ структуре также есть важное полеparent, это тожеClassLoaderНапример, это поле поле представляетClassLoaderтакже стать этимClassLoaderРодители класса.В процессе загрузки класса некоторые запросы могут быть переданы для обработки их собственным родителям.

Как показано на рисунке,应用类加载器родители扩展类加载器,扩展类加载器родители启动类加载器.

в системеClassLoaderПри совместной работе по умолчанию используется双亲委托模式.То есть при загрузке класса система будет определять загружен ли текущий класс.Если он загружен,то сразу вернет доступный класс.В противном случае попытается загрузить.При попытке загрузки будет сначала запросите родителей для обработки.Если запрос родителей Если это не удается, он загрузится сам.

Недостатки модели родительского делегирования

При оценке того, загружен ли класс, загрузчик класса приложения будет оценивать вверх по родительскому пути до тех пор, пока загрузчик класса не будет запущен.Но загрузчик запускаемого класса не будет запрашивать вниз, этот маршрут делегирования является односторонним, то есть класс уровня загружен загрузчиком, не может получить доступ к классам, загруженным базовым загрузчиком классов, как показано на рисунке

Класс в загрузчике классов запуска является основным классом системы.Например, в системном классе предоставляется интерфейс, а интерфейс также предоставляет фабричный метод для создания экземпляра интерфейса, но класс реализации интерфейс используется на уровне приложения, интерфейс и фабричный метод находятся в загрузчике классов запуска, возникнет проблема, заключающаяся в том, что фабричный метод не может создать экземпляр приложения, загружаемый загрузчиком класса приложения.

Есть много компонентов, которые имеют эту проблему, например,JDBC,Xml parserИ т. д. Сам JDBC является стандартом для java для подключения к базе данных. Это уровень абстракции для подключения к базе данных. Он состоит из набора классов и интерфейсов, написанных на java. Реализация интерфейса завершается каждым производителем базы данных.

Дополнение к модели родительского делегирования

В Java базовый класс (rt.jar) предоставляет внешние сервисы, которые могут быть реализованы на самом прикладном уровне.spi, Тогда давайте посмотрим, в启动类加载器, доступ к应用类加载器Принцип реализации spi интерфейса

ThreadВ классе есть два метода

public ClassLoader getContextClassLoader()//获取线程中的上下文加载器
public void setContextClassLoader(ClassLoader cl)//设置线程中的上下文加载器

Благодаря этим двум методамClassLoaderпомещается в экземпляр потока, чтобыClassLoaderСтаньте относительно общим экземпляром. Таким образом, даже код в загрузчике классов запуска может получить доступ к классам в загрузчике классов приложения. Как показано ниже

напиши в конце

Feichao — это технический публичный аккаунт, в котором основное внимание уделяется принципам, исходному коду и навыкам разработки, оригинальному тематическому анализу исходного кода в аккаунте и реальному сражению принципов исходного кода в реальных сценах (ключевые моменты).Отсканируйте QR-код нижеОбратите внимание на Фей Чао, пусть те, кто должен строить ракеты, перестанут трахаться!