1, spi механизм в JDK
1.1 Цель разработки spi
В объектно-ориентированном проектировании модули программируются на основе интерфейсов, а классы реализации не жестко запрограммированы между модулями. Как только в код вовлекается конкретный класс реализации, нарушается принцип подключаемости: если нужно заменить реализацию, нужно модифицировать код. Для того, чтобы понять, что при сборке модуля в модуль не пишется мертвый код, для чего нужен механизм обнаружения сервисов. Java spi должен предоставить такой механизм: механизм поиска реализации службы для интерфейса. Немного похоже на идею IOC, заключающуюся в том, чтобы вынести управление сборкой за пределы кода.
То есть у механизма SPI есть интерфейс, а затем несколько классов реализации, при выполнении кода необходимо определить, какой класс реализации запускать, и эти классы реализации также являются подключаемыми.
1.2 Конкретное соглашение спи
Когда поставщик услуг (поставщик) предоставляет несколько реализаций интерфейса, файл с тем же именем интерфейса обычно создается в каталоге META-INF/services/ пакета jar. Содержимое этого файла — это имя конкретного класса реализации интерфейса службы. Когда модуль загружается извне, конкретное имя класса реализации можно получить через файл конфигурации в jar-пакете META-INF/services/, а экземпляр загружается для завершения сборки модуля.
Вот два примера:
1. Например, загрузите определенный пакет драйвера sql, такой как mysql:mysql-connector-java-5.1.35.jar\META-INF\services\java.sql.Driver — это точка расширения spi oracle:ojdbc6-11.2.0.1. .0.jar \META-INF\services\java.sql.Драйвер
2. Например, загрузите ServletContainerInitializer Spring-web: spring-web-4.2.0.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer
1.3 Практические примеры jdk
1. Напишите команду интерфейса
public interface Command {
public void execute();
}
2. Напишите классы реализации двух интерфейсов соответственно TurnOnCommand и TurnOffCommand.
public class TurnOnCommand implements Command {
public void execute() {
System.out.println("Trun on....");
}
}
public class TurnOffCommand implements Command {
public void execute() {
System.out.println("Trun off....");
}
}
3. Создайте новый файл конфигурации spi com.abc.spi.Command в каталоге resources\META-ING\services проекта, содержимое которого представляет собой два класса реализации интерфейса.
Содержание:
com.abc.spi.TurnOnCommand
com.abc.spi.TurnOffCommand
4. Напишите тестовый класс Test
public class Test {
public static void main(String[] args) {
// 加载jdk的spi接口Command.class
ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class);
// 遍历加载的jdk的接口
for(Command command:serviceLoader){
command.execute();
}
}
}
На следующем рисунке показаны результаты теста:
1.4, недостатки механизма JDK SPI
1. Стандартный SPI JDK будет создавать экземпляры всех реализаций точки расширения одновременно.Если есть реализации расширения, инициализация занимает много времени, но если они не используются, они будут загружены, что приведет к пустой трате ресурсов.
2. Механизм SPI JDK не поддерживает Ioc и AOP, поэтому dubbo использует собственный механизм spi: он добавляет поддержку точек расширения IoC и AOP, а точка расширения может напрямую внедрять сеттеры в другие точки расширения.
2. Конвенция dubbo's spi
2.1 Где хранится spi-файл dubbo?
Файлы в каталоге dubbo-2.5.3.jar\META-INF\dubbo\internal в созданном пакете dubbo jar являются механизмами расширения spi.
2.2 Каковы соглашения SPI dubbo
1. Путь хранения файла spi находится в каталоге META-INF\dubbo\internal, а имя файла представляет собой полное имя интерфейса = имя пакета интерфейса + имя интерфейса,
Например: dubbo-2.5.3.jar\META-INF\dubbo\internal\com.alibaba.dubbo.rpc.Protocol
2. Формат в каждом файле spi определяется следующим образом: расширение=имя конкретного класса, например registries=com.alibaba.dubbo.registry.RegistriesPageHandlerpages.
3. Как продлить spi dubbo
Например, если вы хотите расширить протокол dubbo, вам необходимо выполнить следующие шаги:
1. Создайте новый проект, создайте новый файл, например org.apache.dubbo.rpc.Protocol, в каталоге src/main/resources/META-INF/dubbo и напишите внутри него содержимое: xxProtocal=com.abc.XxxProtocol.
Каталог проекта выглядит следующим образом:
2. Затем создайте новый класс XxxProtocol в этом проекте, чтобы реализовать интерфейс протокола и реализовать связанные методы.
XxxProtocal.java:
package com.xxx;
import org.apache.dubbo.rpc.Protocol;
public class XxxProtocol implements Protocol {
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return new XxxExporter(invoker);
}
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
return new XxxInvoker(type, url);
}
}
x спасибо exporter.Java:
package com.xxx;
import org.apache.dubbo.rpc.support.AbstractExporter;
public class XxxExporter<T> extends AbstractExporter<T> {
public XxxExporter(Invoker<T> invoker) throws RemotingException{
super(invoker);
// ...
}
public void unexport() {
super.unexport();
// ...
}
}
x Спасибо Invoker.Java:
package com.xxx;
import org.apache.dubbo.rpc.support.AbstractInvoker;
public class XxxInvoker<T> extends AbstractInvoker<T> {
public XxxInvoker(Class<T> type, URL url) throws RemotingException{
super(type, url);
}
protected abstract Object doInvoke(Invocation invocation) throws Throwable {
// ...
}
}
3. Вы можете упаковать этот проект в пакет jar, а затем положиться на пакет spi jar прямо сейчас в своем собственном проекте поставщика dubbo и настроить его в файле конфигурации spring следующим образом:
<dubbo:protocol name=”XxxProtocol” port=”20000” />
Ссылаться на:Хироши Ватанабэ.apache.org/en-US/index…