powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Как готовить SPI ?
17 сообщений из 17, страница 1 из 1
Как готовить SPI ?
    #39538797
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Читаю

https://habrahabr.ru/post/118488/

Структура проекта выглядит:


в main:

ReportRenderer reportRenderer = ReportRenderer.getInstance();
System.out.println(reportRenderer.getClass());

выводится:

авторclass my.spi.renderer.ReportRenderer

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
public class ReportRenderer { 
     ...
     public static ReportRenderer getInstance() {
        final Iterator<ReportRenderer> providers = ServiceLoader.load(ReportRenderer.class).iterator();
        if (providers.hasNext()) {
            return providers.next();
        }

        return new ReportRenderer();
    }
}



Код: java
1.
public class FileReportRenderer extends ReportRenderer { ...



Автор пишет:
авторПоместим в META-INF/services/com.example.ReportRenderer следующее:
com.example.FileReportRenderer


Чего-то я не понял куда мне конкретно это поместить. У меня нет никакого джарника.

Как это связано с jdbc? в jdbc в META-INF не надо создавать никаких новых файлов.
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538820
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЧего-то я не понял куда мне конкретно это поместить. У меня нет никакого джарника.

А у Java нет никакой IntelliJ IDEA и никаких проектов. Зато есть jar-ники.

questionerКак это связано с jdbc? в jdbc в META-INF не надо создавать никаких новых файлов.
Ты давно драйверы для JDBC писал?
mysql-connector-java-5.1.16-bin.jar\META-INF\services\java.sql.Driver
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538831
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,
BlazkowiczА у Java нет никакой IntelliJ IDEA и никаких проектов. Зато есть jar-ники.
Просто собрать любым способом джарник?

авторТы давно драйверы для JDBC писал?
не приходилось
Blazkowiczmysql-connector-java-5.1.16-bin.jar\META-INF\services\java.sql.Driver

запутался.

JDBC это API для работы с базой данных.
JDBC коннектор - вот честно не знаю, но мы подключаем именно её, когда нам надо подключить my sql driver.

Где тут вообще расширение функционала?
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538854
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerBlazkowiczА у Java нет никакой IntelliJ IDEA и никаких проектов. Зато есть jar-ники.
Просто собрать любым способом джарник?
Да. Возможно, получится в IDEA сконфигурировать артифакт и подсунуть ему META-INF каталог в качестве ресурса. Реальные проекты мы же таки из jar-ников запускаем, а не из IDE?

questionerне приходилось

Но при этом есть твердая уверенность что в JDBC никакого SPI нет.

questionerзапутался.

Бывает.

questionerJDBC это API для работы с базой данных.

Хоть здесь без заблуждений.

questionerJDBC коннектор - вот честно не знаю, но мы подключаем именно её, когда нам надо подключить my sql driver.

Опять всё напутал. :)
JDBC драйвер для MySQL называется mysql connector.

questionerГде тут вообще расширение функционала?
Эээ. Какой-то риторический вопрос. Даже не знаю как на него серьезно ответить. Вот JSE не умеет работать с MySQL. Добавляем драйвер и вот - "расширение функционала". Теперь-то умеет.
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538878
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,
добавил в гредл
Код: java
1.
2.
3.
4.
5.
jar {
    manifest {
        attributes 'Main-Class': 'my.spi.Main'
    }
}




сделал
Код: java
1.
gradle build




нашёл jar в папке

авторD:\work\SPI_test\build\libs

Разархивировал его 7zip,
в папку META-INF
положил файл с именем
Код: java
1.
my.spi.renderer.ReportRenderer



в контенте файла написал:
авторmy.spi.renderer.FileReportRender

заархивировал вновь как .zip и переименовал как .jar


пытаюсь запустить:
авторD:\work\SPI_test\build\libs>java -jar SPI_test_copy_changed.jar
Error: Invalid or corrupt jarfile SPI_test_copy_changed.jar

D:\work\SPI_test\build\libs>

Что я делаю не так?
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538893
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Проблема была в том, что архиватор всю папку заархивировал, а надо только её контент.

теперь запустилось:

D:\work\SPI_test\build\libs>java -jar SPI_test_copy_changed.jar
class my.spi.renderer.ReportRenderer

но результат то старый
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538897
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
jar это не обычный zip. Манифест jar-а должен быть первой сущностью zip-а. Обычные архиваторы это не учитывают.
Создайте файлы как ресурсы проекта и пропишити в вашем скрипте.
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538939
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowiczjar это не обычный zip. Манифест jar-а должен быть первой сущностью zip-а. Обычные архиваторы это не учитывают.
Создайте файлы как ресурсы проекта и пропишити в вашем скрипте.

Что такое первая сущность?

Могли бы подетальнее, пожалуйста. Как Вы уже поняли у меня idea + gradle

что Вы называете скриптом?
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538946
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЧто такое первая сущность?
Старость не радость. Entry же не Entity:
https://docs.oracle.com/javase/7/docs/api/java/util/zip/ZipEntry.html

questionerчто Вы называете скриптом?
Скрипт сборки проекта:
https://docs.gradle.org/current/userguide/writing_build_scripts.html
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538960
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,

ок) BlazkowiczСоздайте файлы как ресурсы проекта

Научите? и вообще про какие файлы речь?
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538963
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538969
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,



D:\work\SPI_test\build\libs>java -jar SPI_test.jar
class my.spi.renderer.ReportRenderer

...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538973
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

По ссылке META-INF/services упомянуто 9 раз. Как можно было пропустить?
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538978
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Понял. забыл добавить services в папке META-INF.

Теперь заработало.


авторD:\work\SPI_test\build\libs>java -jar SPI_test.jar
class my.spi.renderer.FileReportRenderer
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39538981
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowiczquestioner,

По ссылке META-INF/services упомянуто 9 раз. Как можно было пропустить?
Наверное
BlazkowiczСтарость не радость.
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39539005
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Blazkowicz,
Ок, стало понятно как это завести.

Не стало понятнее зачем это надо. Вот в jdbc драйвере это зачем?
Это такой функционал подменяемости?

java.sql.Drive
r:

Код: java
1.
2.
3.
4.
5.
6.
7.
package java.sql;
....
public interface Driver {

        Connection connect(String url, java.util.Properties info)
        throws SQLException;
        ....




Внутри mySql коннектора где-то написано?:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
 public static java.sql.Driver getInstance() {
        final Iterator<java.sql.Driver> providers = ServiceLoader.load(java.sql.Driver.class).iterator();
        if (providers.hasNext()) {
            return providers.next();
        }

        throw new BabaxException();
    }
...
Рейтинг: 0 / 0
Как готовить SPI ?
    #39539447
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
нашёл.

java.sql.DriverManager, который есть часть JDK имеет метод

loadInitialDrivers

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

   ....

  private static void loadInitialDrivers() {
        String drivers;
        try {
            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty("jdbc.drivers");
                }
            });
        } catch (Exception ex) {
            drivers = null;
        }
        // If the driver is packaged as a Service Provider, load it.
        // Get all the drivers through the classloader
        // exposed as a java.sql.Driver.class service.
        // ServiceLoader.load() replaces the sun.misc.Providers()

        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {

                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                /* Load these drivers, so that they can be instantiated.
                 * It may be the case that the driver class may not be there
                 * i.e. there may be a packaged driver with the service class
                 * as implementation of java.sql.Driver but the actual class
                 * may be missing. In that case a java.util.ServiceConfigurationError
                 * will be thrown at runtime by the VM trying to locate
                 * and load the service.
                 *
                 * Adding a try catch block to catch those runtime errors
                 * if driver not available in classpath but it's
                 * packaged as service and that service is there in classpath.
                 */
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });

        println("DriverManager.initialize: jdbc.drivers = " + drivers);

        if (drivers == null || drivers.equals("")) {
            return;
        }
        String[] driversList = drivers.split(":");
        println("number of Drivers:" + driversList.length);
        for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }
    }



То есть сначала ищем имя драйвера в системной переменной jdbc.drivers
а здесь делаем
Class.forName:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }




В этом куске просто грузим сервисы и гуляем итератором по ним. Гуляем чтобы класс лоадер в память загрузил класс? то же самое, что class.forName ?

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {

                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                /* Load these drivers, so that they can be instantiated.
                 * It may be the case that the driver class may not be there
                 * i.e. there may be a packaged driver with the service class
                 * as implementation of java.sql.Driver but the actual class
                 * may be missing. In that case a java.util.ServiceConfigurationError
                 * will be thrown at runtime by the VM trying to locate
                 * and load the service.
                 *
                 * Adding a try catch block to catch those runtime errors
                 * if driver not available in classpath but it's
                 * packaged as service and that service is there in classpath.
                 */
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Как готовить SPI ?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]