SPI
(Service Provider Interface
) Это механизм обнаружения служб, который позволяет сторонним поставщикам предоставлять реализации или расширения базовой библиотеки или основной платформы. Такая конструкция позволяет базовым библиотекам/платформам расширять функциональность за счет сторонних реализаций без изменения собственного кода.
JDK
изSPI
Главным образом черезMETA-INF/services/
Место конкретноеизфайл, чтобы указать, какие классы реализуют данныйиз Сервисный интерфейс。эти файлыиз Имя должно быть Интерфейс с полным именем,Содержимое — это полное имя класса, реализующего интерфейс.ServiceLoader
Использование классаJava
из Механизм загрузки классов изMETA-INF/services/
Загрузка и создание экземпляров поставщиков услуг в каталоге。Например,ServiceLoader.load(MyServiceInterface.class)
вернет реализациюMyServiceInterface
изитератор экземпляра。JDK
РоднойизSPI
каждый проходServiceLoader
При загрузке появляется новыйиз Пример,Класс из кеша не реализован,Расширенные функции, такие как синглтоны, также не рассматриваются.Spring
изSPI
не толькодаобнаружение службы,Он предоставляет полный набор подключаемых механизмов. Например,может бытьSpring
определить новыеизPropertySource
,ApplicationContextInitializer
ждать。JDK
изSPI
другой,Spring
изSPI
ВместоIoC
(Inversion of Control
) Интеграция контейнеров,так что вSPI
Можно использовать при реализацииSpring
из Все функции,Например, внедрение зависимостей.Spring
Предоставляется на условияхиз Механизм согласования,Это позволяет загружать только определенныеизSPI
выполнить,Например,Вы можете выбрать, какой драйвер базы данных загрузить, в зависимости от текущей рабочей среды.Spring
разрешено пройтиspring.factories
Файл находится вMETA-INF
Продолжить в каталоге Конфигурация,этотиJDK
изSPI
очень похоже,Но он предлагает больше возможностей и гибкости.Приведите пример-аналогию:
Представьте, что мы собираем телевизор.,SPI
нравитьсятелевизорначальствоизодинUSB
Джек。этотиндивидуальный Джек Различныйоборудование(НапримерUтарелка、геймпад、телевидение Большойждать),Но нас не волнует внутренняя работа этих устройств. Таким образом, вам нужно только предоставить стандартный интерфейс.,Другие компании(НапримерUтарелкапроизводитель)может бытьэтот Предоставляемый интерфейсвыполнить。так,Телевизор может использовать множество новых устройств без изменения собственного внутреннего кода.,Производители устройств также могут создавать совместимые устройства для различных телевизоров.
Суммируя,SPI
да Что-то вроде Воляинтерфейсопределениеивыполнитьразделениеизшаблон проектирования,Он поощряет третьи стороны предоставлять плагины или реализации для основного продукта или платформы.,Это позволяет основному продукту легко расширять функциональность.
существоватьJava
изв экосистеме,SPI
Это основная концепция, которая позволяет разработчикам предоставлять расширения и альтернативные реализации без необходимости изменения основной библиотеки или приложения. Вот пример для иллюстрации.
Все коды и шаги следующие:
Шаг 1:определениеодин Сервисный интерфейс,имя файла: MessageService.java
package com.example.demo.service;
public interface MessageService {
String getMessage();
}
Шаг 2:Обеспечить реализацию сервисного интерфейса, здесь будут представлены два простых класса реализации.
HelloMessageService.java
package com.example.demo.service;
public class HelloMessageService implements MessageService {
@Override
public String getMessage() {
return "Hello from HelloMessageService!";
}
}
HiMessageService.java
package com.example.demo.service;
public class HiMessageService implements MessageService {
@Override
public String getMessage() {
return "Hi from HiMessageService!";
}
}
этотнекоторыйвыполнитьнравитьсядругойбрендилимодельизUтарелкаилидругойUSB
оборудование。каждыйоборудование У каждого есть свойиз Функции и возможности,но все следуют одному и тому жеизUSB
стандартный。
Шаг 3:Служба регистрациипоставщик
существовать Каталог ресурсов(в целомдаsrc/main/resources/
)Создано пододинназванныйMETA-INF/services/
издокументпапка。существоватьэтотиндивидуальныйдокументпапкасередина,создаватьодинназванныйcom.example.demo.service.MessageService
издокумент(этотданасИнтерфейс с полным именем),Этот файл не имеет расширения,так Нет Хочу добавитьначальство.txt
такизсуффикс。документизсодержаниедолжно бытьнасиз两индивидуальныйвыполнитьдобрыйиз Полное имя,Каждое имя находится на отдельной строке:
com.example.demo.service.HelloMessageService
com.example.demo.service.HiMessageService
META-INF/services/
да Java SPI
(Service Provider Interface
) Соглашения в механизме относительно конкретных каталогов. Он выбирает не случайно, а SPI
четко определены в спецификации. Поэтому при использовании JDK
из ServiceLoader
Когда класс используется для загрузки поставщика услуг, он специально ищет файлы по этому пути.
Убедитесь, что файл имеет только одно имя в строке,и никаких лишних пробелов или скрытых символов,документиспользоватьUTF-8
кодирование。
Шаг 4:использоватьServiceLoader
нагрузкаииспользовать Служить
package com.example.demo;
import com.example.demo.service.MessageService;
import java.util.ServiceLoader;
public class DemoApplication {
public static void main(String[] args) {
ServiceLoader<MessageService> loaders = ServiceLoader.load(MessageService.class);
for (MessageService service : loaders) {
System.out.println(service.getMessage());
}
}
}
Результаты бега следующие:
этотиллюстрироватьServiceLoader
成功地нагрузка ПонятнонасдляMessageService
Предоставляемый интерфейсиз两индивидуальныйвыполнить,инас Можетсуществовать Нет ИсправлятьMain
добрыйизкодизслучай,добавив большеизвыполнитьдобрыйивозобновлятьMETA-INF/services/com.example.MessageService
документрасширятьнасиз Служить。
Представьте себе, что вы покупаете высококачественный смарт-телевизор.,этотбашнятелевидениеначальствоиметьодинили多индивидуальныйHDMI
порт,Это интерфейс, который соединяет его с внешними устройствами.
HDMI
портизстандартный。существоватьначальстволапшаизкодсередина,MessageService
Интерфейсдаэтотиндивидуальный“HDMI
порт”,Определяет способ связи с внешними устройствами.HDMI
интерфейс Производить различныеоборудование,Например, игровые консоли, проигрыватели Blu-ray или потоковые флешки. в коде,HelloMessageService
иHiMessageService
Сразудаэтотнекоторый“HDMI
оборудование”。каждыйоборудование/выполнить都иметь Что独特извыход,Но все они следуют единомуизHDMI
стандартный(MessageService
интерфейс)。HDMI
оборудование,этов целомгородсуществоватьупаковочная коробканачальствочетко обозначенный“Применимо кHDMI
”。этотнравитьсяодинлоготип,Сообщите пользователю, что он может подключиться к чему угодно с помощьюHDMI
интерфейсизтелевидение。существоватьSPI
из Пример,META-INF/services/
Оглавлениеи Чтосерединаиздокументнравитьсяэтотиндивидуальный“Этикетка”,РассказыватьJDK
КоторыйдобрыйдаMessageService
извыполнить。HDMI
оборудованиеприезжатьтелевидениеначальство,и переключитесь на правильный входной канал,Телевизор отобразит содержимое устройства. Сходным образом,В коде шага,ServiceLoader
нравитьсятелевидениеиз Функция выбора входа,способен обнаружитьииспользовать Местоиметь已连接изHDMI
оборудование(Прямо сейчасMessageService
из Местоиметьвыполнить)。 Spring
чиновниксуществовать Что文档иисточниккодсередина多次提приезжать ПонятноSPI
(Service Provider Interface
)изконцепция。Да,когданасобъяснять“Spring
изSPI
”час,в целомобратитесь киздаSpring
Фреймворк предоставляет разработчикамиз Набор расширяемыхизинтерфейсиабстрактныйдобрый,Разработчики могут реализовывать свои собственные версии на основе этих интерфейсов и абстрактных классов.
существоватьSpring
середина,SPI
изконцепцияиSpring Boot
использоватьизspring.factories
документиз Механизм не совсем тот,Но все они воплощают идеи подключаемости и расширяемости.
Spring
изосновнойрамка提供Понятно很多интерфейсиабстрактныйдобрый,нравитьсяBeanPostProcessor
, PropertySource
, ApplicationContextInitializer
ждать,этотнекоторый都можно рассматривать какдаSpring
изSPI
。Разработчик МожетвыполнитьэтотнекоторыйинтерфейсрасширятьSpring
из Функция。этотнекоторыйинтерфейс Разрешить разработчикамсуществоватьSpring
контейнеризжизненный циклиздругойэтапное вмешательство,Осознайте свою собственную логику.spring.factories
даSpring Boot
изодинхарактеристика,Разрешить разработчикам настраивать автоматические Конфигурация。проходитьspring.factories
документ,Разработчики могут определять свои собственные классы автоматической конфигурации.,этотнекоторыйдобрыйсуществоватьSpring Boot
запускатьчасбудетавтоматическийнагрузка。SpringFactoriesLoader
изиспользовать,особеннодапроходитьspring.factories
документ Приходитьнагрузкаи Примеризменятьопределениеиздобрый,можно рассматривать какдаконкретныйизSPI
выполнить Способ,но это специфично дляSpring Boot
。 существовать ТрадицияизSpring
рамкасередина,虽然没иметьпрямойиспользоватьназванный"SPI"
изтермин,но Чтоосновной Мысльвсе ещежитьсуществовать。Spring
Предоставляет несколько точек расширения,Чтосерединанаиболее представительныйиз СразудаBeanPostProcessor
。существовать Этот разделсередина,нас Воляпроходитьодин ПростойизMessageService
интерфейс及ЧтовыполнитьобсудитьнравитьсячтоиспользоватьSpring
изBeanPostProcessor
Вариант точки расширенияSPI
из Мысль。
Предоставляет два простых класса реализации.
HelloMessageService.java
package com.example.demo.service;
public class HelloMessageService implements MessageService {
@Override
public String getMessage() {
return "Hello from HelloMessageService!";
}
}
HiMessageService.java
package com.example.demo.service;
public class HiMessageService implements MessageService {
@Override
public String getMessage() {
return "Hi from HiMessageService!";
}
}
определениеBeanPostProcessor
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MessageServicePostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof MessageService) {
return new MessageService() {
@Override
public String getMessage() {
return ((MessageService) bean).getMessage() + " [Processed by Spring SPI]";
}
};
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
ИсправлятьSpring
Конфигурация
ВоляMessageServicePostProcessor
добавить вSpring
Конфигурациясередина:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MessageServiceConfig {
@Bean
public MessageService helloMessageService() {
return new HelloMessageService();
}
@Bean
public MessageService hiMessageService() {
return new HiMessageService();
}
@Bean
public MessageServicePostProcessor messageServicePostProcessor() {
return new MessageServicePostProcessor();
}
}
Выполнить программу
использоватьранее предоставленныйизDemoApplication
Примердобрый:
package com.example.demo;
import com.example.demo.configuration.MessageServiceConfig;
import com.example.demo.service.MessageService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MessageServiceConfig.class);
MessageService helloMessageService = context.getBean("helloMessageService", MessageService.class);
MessageService hiMessageService = context.getBean("hiMessageService", MessageService.class);
System.out.println(helloMessageService.getMessage());
System.out.println(hiMessageService.getMessage());
}
}
Результаты запуска:
Сейчас,КаждыйодинMessageService
выполнить Все былиBeanPostProcessor
Обработано,добавлено дополнительноеизинформация“[Processed by Spring SPI]”
。этот演示ПонятноSpring
изSPI
концепция,проходитьBeanPostProcessor
расширятьили ИсправлятьSpring
контейнерсерединаизbean
。
Возможно, кто-то заметил здесь красное предупреждение,этотиндивидуальный之前существоватьговоритьBeanPostProcessor
изчас候также提приезжать过,когдаBeanPostProcessor
само существоодинили多индивидуальныйBeanPostProcessor
иметь дело счас,Это произойдет. Проще говоря,потому чтоBeanPostProcessor
нуждатьсясуществоватьдругойbean
инициализирован раньше,так что некоторыеBeanPostProcessor
Невозможно обработать раннюю инициализациюизbean
,включать КонфигурациядобрыйидругойBeanPostProcessor
。Решение Сразудане ставьMessageServicePostProcessor
помещатьсуществовать Конфигурациядобрый初始изменять,Удалить в категории Конфигурация,сноваMessageServicePostProcessor
добавлятьначальство@Component
аннотация。
Пример начала статьи-аналогии:
Spring
приложение,КонкретнодаDemoApplication
добрый。этотиндивидуальныйосновнойприложениенуждатьсяот某индивидуальный Служить(Прямо сейчасMessageService
)Получите и распечатайтеинформация。MessageService
Интерфейсдаэтотиндивидуальный"USB
Джек"。этотелевизор提供Понятноодинстандартныйизменятьизинтерфейс,Прямо сейчасgetMessage()
метод,Но конкретного регламента, как это реализовать, не существует.HelloMessageService
иHiMessageService
。Они есть"USB
Джек"(Прямо сейчасMessageService
интерфейс)提供Понятнодругойизоборудованиеиливыполнить。одинпоказывать“Hello from HelloMessageService!”
,Другойодинпоказывать“Hi from HiMessageService!”
。USB
оборудование(Прямо сейчасMessageService
извыполнить)и попробуйотсерединаполучатьинформациячас,Этот «волшебный ящик» вмешается,идля Каждый条информациядобавить в“[Processed by Spring SPI]”
。Java
из Конфигурация Способ,Прямо сейчасMessageServiceConfig
добрый。этотиндивидуальный“использоватьиллюстрировать书”гидSpring
контейнернравитьсячтосоздаватьи管理MessageService
из Пример,ивозвращатьсягидэтонравитьсячтоиспользовать“волшебный ящик”(Прямо сейчасMessageServicePostProcessor
)Приходитьиметь дело синформация。 В общем,По сравнению с предыдущим примером,Этот новый пример обеспечивает более динамичную сцену.,ЧтосерединаSpring
изBeanPostProcessor
точки расширения позволяютнасперехватить и Исправлятьbean
из Поведение,Как интеллектуальное устройство, которое может вмешиваться и изменять отображаемый контент.
Spring Boot
иметьодиниSPI
сходствоизмеханизм,ноэтои Нетполностьюждать То же, чтоJava
изстандартныйSPI
。
Spring Boot
изавтоматический Конфигурациямеханизмв основном зависит отspring.factories
документ。этотиндивидуальныйдокумент Можетсуществовать多индивидуальныйjar
серединажитьсуществовать,иSpring Boot
загрузит все видимоеизspring.factories
документ。нас Можетсуществоватьэтотиндивидуальныйдокументсерединаобъявить сериюиз Класс автоматической настройки,Таким образом, при выполнении определенных условий,этотнекоторый КонфигурациядобрыйвстречаавтоматическийодеялоSpring Boot
приложение。
будет показано следующимSpring SPI
Мысльизхороший пример,ДаэтоиSpring Boot
тесно связанный。
Определить интерфейс
package com.example.demo.service;
public interface MessageService {
String getMessage();
}
Здесь будут представлены два простых класса реализации.
HelloMessageService.java
package com.example.demo.service;
public class HelloMessageService implements MessageService {
@Override
public String getMessage() {
return "Hello from HelloMessageService!";
}
}
HiMessageService.java
package com.example.demo.service;
public class HiMessageService implements MessageService {
@Override
public String getMessage() {
return "Hi from HiMessageService!";
}
}
Служба регистрации
существоватьresources/META-INF
Создано пододинимя файладляspring.factories
。этотиндивидуальныйдокументвнутри,Можно зарегистрироватьсяMessageService
выполнитьдобрый。
com.example.demo.service.MessageService=com.example.demo.service.HelloMessageService,com.example.demo.service.HiMessageService
Уведомлениеэтотвнутриcom.example.demo.service.MessageService
даинтерфейсизполный путь,иcom.example.demo.service.HelloMessageService,com.example.demo.service.HiMessageService
давыполнитьдобрыйизполный путь。нравиться果иметь多индивидуальныйвыполнитьдобрый,Их следует разделять запятыми.
spring.factories
документсерединаизключ входаимежду ценностями Нет能иметь换行,Прямо сейчасkey=value
формаизструктура должнасуществовать Начните с той же строки。Да,Если необходимо указать несколько значений (например, несколько классов реализации),И эти значения да разделены запятой,那么Можетиспользоватьобратная косая черта(\
)обернуть。spring.factories
из Название да условно из. Если вы попытаетесь использовать другое имя файла, то Spring Boot
Механизм автоматической настройки не распознает его.
этотвнутриspring.factories
Это также можно записать как
com.example.demo.service.MessageService=com.example.demo.service.HelloMessageService,\
com.example.demo.service.HiMessageService
прямойсуществовать逗号后лапша回车IDEA
встречаавтоматический补Полныйобратная косая черта,Просто убедитесь, что между ключами и значениями нет разрывов строк.
использоватьSpringFactoriesLoader
Приходитьнагрузка Служить
package com.example.demo;
import com.example.demo.service.MessageService;
import org.springframework.core.io.support.SpringFactoriesLoader;
import java.util.List;
public class DemoApplication {
public static void main(String[] args) {
List<MessageService> services = SpringFactoriesLoader.loadFactories(MessageService.class, null);
for (MessageService service : services) {
System.out.println(service.getMessage());
}
}
}
SpringFactoriesLoader.loadFactories
извторой параметрдадобрыйнагрузкаустройство,Здесь мы используем загрузчик классов по умолчанию,так что проходиnull
。
Результаты запуска:
этотдобрый Способиспользовать ПонятноSpring
изSpringFactoriesLoader
,Это позволяет разработчикам предоставлять несколько реализаций интерфейса.,ипроходитьspring.factories
документ Приходитьзарегистрироватьсяэто们。этотиJDK
изSPI
Мысль Оченьсходство,Толькодасуществоватьвыполнитьдетальначальствоиметь Местодругой。этоттакжедаSpring Boot
нравитьсячтоавтоматический Конфигурацияиз База,Он будет искать различныеspring.factories
документ,根据Чтосерединаопределениеиздобрый Приходить初始изменятьи Конфигурацияbean
。
Давайте продолжим использовать пример телевизора, чтобы объяснить:
Spring
приложение,нравитьсяDemoApplication
。телевизорда Проверятьдругой信号источникилирядизоборудование,Наше приложение да реализовано для запуска и использования различных сервисов.MessageService
интерфейс。USB
Джекдаодинстандартныйизинтерфейс,Позволяет подключать различные устройства,нравитьсяMessageService
интерфейспозволятьиметь多добрыйвыполнить Способ。HelloMessageService
иHiMessageService
。каждыйUSB
оборудованиесуществоватьвставлятьтелевизор Есть конкретныеизсодержаниеили Функция,Это похоже на то, что каждая реализация нашего сервиса возвращает разные сообщения.spring.factories
документ。когданас ВоляUSB
оборудованиевставлятьтелевизорчас,Телевизор проверит устройство на наличие информации или контента,spring.factories
документ РассказыватьSpring Boot
Который Служитьвыполнитьда Доступныйиз,нравитьсятелевизорзнаю, какиеUSB
оборудованиеодеяловставлять。SpringFactoriesLoader
。когданасхотетьоттелевизорначальство ПроверятьUSB
содержаниечас,Телевизор просканирует и отобразит содержимое. такой же,когдаDemoApplication
бегатьчас,SpringFactoriesLoader
встреча查找инагрузкасуществоватьspring.factories
документсерединасписокиз Служитьвыполнить。Упрощенное объяснение:
USB
оборудованиеприезжатьтелевизор,Ожидается, что телевизор сможет распознавать и отображать контент устройства.USB
оборудованиеизсодержание СразудаотMessageService
выполнитьдобрыйвозвращатьсяизинформация。spring.factories
документнравитьсятелевизориз Встроенный каталог,Рассказыватьтелевизор КоторыйUSB
оборудованиедаизвестныйизи Можетиспользоватьиз。DemoApplication
(телевизор)бегатьчас,этоиспользоватьSpringFactoriesLoader
(USB
сканирование Функция)приди и проверь Который Служить(USB
оборудование)да Доступныйиз,ивыходсоответствующийизинформация(показыватьUSB
содержание)。 Подвести итог:существоватьэтотиндивидуальныйSpring Boot
изSPI
Пример,насвыставка ПонятноосновнойSpring
приложениенравитьсячтоавтоматическийидентифицироватьииспользоватьspring.factories
документсерединазарегистрироватьсяизвыполнить,этотителевизоравтоматическийидентифицироватьииспользовать МестоиметьвставлятьизUSB
оборудованиеиметьсходствоместо。
Управление базой данныхизSPI
основная часть СейчасJDBC
водить машинуизавтоматический Обнаружитьмеханизмсередина。JDBC 4.0
引入Понятноодинхарактеристика,позволятьводить машинуавтоматическийзарегистрироватьсяприезжатьDriverManager
。этотдапроходитьиспользоватьJava
изSPI
Приходитьвыполнитьиз。водить машинуjar
包内встречаиметьодинMETA-INF/services/java.sql.Driver
документ,этотдокументсередина包含Понятно该водить машинуизDriver
выполнитьдобрыйиз Полныйдобрыйимя。так,когдадобрыйпутьсерединаиметьJDBC
водить машинуизjar
документчас,Java
приложение Можетавтоматический ОбнаружитьинагрузкаJDBC
водить машину,Без явной загрузки класса драйвера.
этот意味着任что数据Библиотека供应商都Может编写Что自己изJDBC
водить машинупрограмма,ТолькохотетьэтоследоватьJDBC
водить машинупрограммаизSPI
,это Сразу Можетодеяло任чтоиспользоватьJDBC
изJava
приложение Местоиспользовать。
когданасиспользоватьDriverManager.getConnection()
Получить подключение к базе данныхчас,За кулисамидаиспользоватьSPI
механизмнагрузка合适изводить машинупрограмма。
нижедаSPI
механизмиз Конкретная работа Способ:
здесь,интерфейсужеJava
平башняопределение,Прямо сейчасjava.sql.Driver
。
Крупнейшие поставщики баз данных(нравитьсяOracle
, MySQL
, PostgreSQL
ждать)предоставил для своей базы данныхJDBC
водить машинупрограмма,это们都выполнить Понятноjava.sql.Driver
интерфейс。Например,MySQL
изводить машинупрограммасерединаиметьодиндобрыйпохоже нанижеиздобрый:
public class com.mysql.cj.jdbc.Driver implements java.sql.Driver {
// Реализация методов интерфейса...
}
Прямо над картинкой:
дляMySQL
изводить машинупрограмма,Можетсуществовать ЧтоJAR
документизMETA-INF/services
Оглавление下找приезжатьодинназванныйjava.sql.Driver
издокумент,Содержимое файла следующее:
com.mysql.cj.jdbc.Driver
Прямо над картинкой:
看приезжатьэтотвнутрида Нетда Обнаружитьи Нет.2
модерацияизJDK SPI
из Тот же пример?Испытайте это。
когданасвызовDriverManager.getConnection(jdbcUrl, username, password)
час,DriverManager
встречаиспользоватьServiceLoader
найти всех зарегистрированныхизjava.sql.Driver
выполнить。Затем,Он будет пробовать каждый драйвер,直приезжать找приезжатьодин Можетиметь дело с给定jdbcUrl
изводить машинупрограмма。
Ниже приведен простой пример,выставканравитьсячтоиспользоватьJDBC SPI
Получить подключение к базе данных:
import java.sql.Connection;
import java.sql.DriverManager;
public class JdbcExample {
public static void main(String[] args) {
String jdbcUrl = "jdbc:mysql://localhost:3306/mydatabase";
String username = "root";
String password = "password";
try {
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
System.out.println("Connected to the database!");
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
В приведенном выше коде,нас没иметь明确обратитесь к定использовать哪индивидуальныйJDBC
водить машинупрограмма,потому чтоDriverManager
встречаавтоматическийдлянас Выберите подходящийизводить машинупрограмма。
Этот модульный и подключаемый механизм позволяет нам легко переключать драйверы для разных баз данных,Тольконуждаться更改JDBC URL
и обеспечить соответственноизводить машинупрограммаJAR
существоватьдобрыйпутьначальство Прямо сейчас Может。
существоватьSpring Boot
середина,Разработчикв целом НетвстречапрямойиJDBC
изSPI
механизмвзаимодействие Приходить Получить подключение к базе данных。Spring Boot
изавтоматический Конфигурациямеханизм隐藏Понятно许多底层деталь,Упрощает настройку и работу с базами данных.
一般встречасуществоватьapplication.properties
илиapplication.yml
середина Конфигурация Информация о подключении к базе данных。
Например:
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
В вышеуказанных шагах,Spring Boot
изавтоматический Конфигурациямеханизмвстреча根据提供изполагатьсяи Конфигурация信息Приходить初始изменятьи КонфигурацияDataSource
объект,Этот объект управляет подключениями к базе данных. на самом деле,добавить вJDBC
водить машинуполагатьсячас,Spring Boot
встречаиспользоватьJDK
изSPI
механизм(существоватьJDBC
спецификациясерединаприложение)найти и загрузить соответствующийиз Управление базой данных。Разработчик虽然НетпрямойиJDK
изSPI
взаимодействие,носуществоватьпозадиSpring Boot
Действительноиспользовать ПонятноJDK SPI
механизм Приходить Получить подключение к базе данных。
этотдобрыймеханизмиметь点добрыйпохоже наJava
изSPI
,потому чтоэтопозволятьтретья сторона Библиотека提供一некоторый默认из Конфигурация。ноэто比Java
изSPI
更для强大игибкий,потому чтоSpring Boot
Предоставлено большое количествоизаннотация(нравиться@ConditionalOnClass
、@ConditionalOnProperty
、@ConditionalOnMissingBean
ждать)контролировать Класс автоматической настройкида否应该одеялонагрузкаиприложение。
В общем,Spring Boot
изspring.factories
механизмиJava
изSPI
существоватьконцепцияначальстводасходствоиз,Но они различаются деталями реализации и использования.
Давайте создадим упрощенный практический пример,гипотезанасхотетьдлядругойизинформация Служить(нравитьсяSMS
иEmail
)создаватьавтоматический Конфигурация。
Интерфейс службы сообщений:
package com.example.demo.service;
public interface MessageService {
void send(String message);
}
Реализация смс-сервиса:
package com.example.demo.service.impl;
import com.example.demo.service.MessageService;
public class SmsService implements MessageService {
@Override
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}
Реализация почтового сервиса:
package com.example.demo.service.impl;
import com.example.demo.service.MessageService;
public class EmailService implements MessageService {
@Override
public void send(String message) {
System.out.println("Sending Email: " + message);
}
}
Класс автоматической настройки:
package com.example.demo.configuration;
import com.example.demo.service.EmailService;
import com.example.demo.service.MessageService;
import com.example.demo.service.SmsService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MessageAutoConfiguration {
@Bean
@ConditionalOnProperty(name = "message.type", havingValue = "sms")
public MessageService smsService() {
return new SmsService();
}
@Bean
@ConditionalOnProperty(name = "message.type", havingValue = "email")
public MessageService emailService() {
return new EmailService();
}
}
этотиндивидуальныйдобрый提供两индивидуальный条件性изbeans
(компоненты),соответственнодаSmsService
иEmailService
。этотнекоторыйbeans
из Творение зависит отapplication.properties
документсерединаидентификацияиззначение атрибута。
когдаapplication.properties
илиapplication.yml
серединаопределениеизсвойствоmessage.type
из Значениеsms
час,Это условиеtrue
。этотчас,smsService()
метод Воляодеяловызов,отисоздаватьодинSmsService
изbean
。
когдаapplication.properties
илиapplication.yml
серединаопределениеизсвойствоmessage.type
из Значениеemail
час,Это условиеtrue
。этотчас,emailService()
метод Воляодеяловызов,отисоздаватьодинEmailService
изbean
。
файл Spring.factories:
существоватьsrc/main/resources/META-INF
Оглавление Создано пододинspring.factories
документ,Содержание следующее:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.configuration.MessageAutoConfiguration
файл application.properties:
message.type=sms
Компонент MessageTester:
package com.example.demo;
import com.example.demo.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class MessageTester {
@Autowired
private MessageService messageService;
@PostConstruct
public void init() {
messageService.send("Hello World");
}
}
Основная программа DemoApplication:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Результаты запуска:
В приведенном выше примере,нассоздавать ПонятноодинMessageService
интерфейси两индивидуальныйвыполнить(SmsService
иEmailService
)。Затем,Мы создали класс автоматической конфигурации.,Чтосередина包含两индивидуальныйbean
определение,этот两индивидуальныйbean
определениесоответственнона основеapplication.properties
серединаиззначение атрибута条件性地создавать。существоватьspring.factories
документсередина,Мы объявляем этот класс автоматической конфигурации.,так чтоSpring Boot
существоватьзапускатьчасможетавтоматическийнагрузкаэто。
Здесь продолжайте использовать пример телевизора, чтобы сублимировать понимание.
аналогия с ТВ
TV
)даодинJava
приложение。HDMI
、USB
、VGA
ждать,можно рассматривать какприложениесерединаизSPI
интерфейс。DVD
игрок、игровая консоль、USB
водить машинуустройствождать)можно рассматривать какSPI
извыполнить。DVD
игрок,Также возможна даигровая консоль。HDMI
стандартный),Просто подключите его и заставьте его работать.Java
изSPI
механизм:для Понятно能让多индивидуальный供应商提供выполнить,Java
определение Понятноодининтерфейс,Поставщики предоставляют конкретные реализации.Spring Boot
изавтоматический Конфигурация:когдаSpring Boot
приложениезапускатьчас,оно проверитclasspath
начальствоиз Библиотека,И автоматически применяется Конфигурация на основе существующей библиотеки.Spring Boot
серединаизspring.factories
и各добрый@Conditional
...аннотация。это们决定существовать什么条件下进行哪добрый Конфигурация。Spring Boot
,Если вы хотите добавить новые функции или библиотеки в свое приложение,Просто добавьте соответствующие зависимости,ЗатемSpring Boot
встречаавтоматический识别и Конфигурацияэтотнекоторый新Функция。 По этой аналогии,телевизоризслотиавтоматическийнастраивать Функциядлянас提供Понятноодин Интуитивныйиз Способ Приходить理解Java
изSPI
механизмиSpring Boot
изавтоматический Конфигурациянравитьсячто工作,и как они помогают разработчикам приложений.
SPI
,то есть интерфейс поставщика услуг,да Особый шаблон проектирования. Это позволяет платформе или базовой библиотеке предоставлять предопределенный интерфейс сторонним разработчикам.,Это позволяет им предоставлять собственные реализации или расширения платформы.
основные цели:
SPI
механизм让рамкаизосновной Вместо Расширения остаютсяразвязка,Сделайте основной код независимым от конкретной реализации.Java
изServiceLoader
)动态地Обнаружитьинагрузка Место需извыполнить。ценить:
SPI и «Принцип открытия и закрытия»:
Принцип «открыто-закрытости» предполагает, что программные объекты должны быть открыты для расширений.,Но закрыт для модификации. То есть без изменения существующего кода,Добавляйте новые функции через расширения.
Как SPI воплощает в себе «принцип открытия-закрытия»:
SPI
提供Понятно Что-то вродестандартныйизменятьиз Способ,Позволяет сторонним разработчикам предоставлять новые реализации или функции для существующих систем.SPI
выполнить Может独立地进изменятьиразвивать,Не влияйте друг на друга. Суммируя,SPI
да Что-то вроде使软件рамкаили Библиотека更добавлять模块изменять、Может扩展и Может维护изиметь效метод。проходитьследовать“принцип открытия-закрытия”,SPI
обеспечил системуизстабильностьигибкий性,Таким образом, удовлетворяя постоянно меняющиеся потребности бизнеса.
Добро пожаловать в тройное соединение в один клик~
Если у вас есть какие-либо вопросы, оставьте сообщение, и давайте обсудим и поучимся вместе.
----------------------Talk is cheap, show me the code-----------------------