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

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
19.10.2017, 15:35
    #39538820
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
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
19.10.2017, 15:44
    #39538831
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
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
19.10.2017, 15:57
    #39538854
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
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
19.10.2017, 16:12
    #39538878
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
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
19.10.2017, 16:22
    #39538893
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
Проблема была в том, что архиватор всю папку заархивировал, а надо только её контент.

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

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

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

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

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

что Вы называете скриптом?
...
Рейтинг: 0 / 0
19.10.2017, 16:59
    #39538946
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
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
19.10.2017, 17:09
    #39538960
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
Blazkowicz,

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

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



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

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

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

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


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

По ссылке META-INF/services упомянуто 9 раз. Как можно было пропустить?
Наверное
BlazkowiczСтарость не радость.
...
Рейтинг: 0 / 0
19.10.2017, 17:38
    #39539005
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
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
20.10.2017, 11:58
    #39539447
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как готовить SPI ?
нашёл.

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
Форумы / Java [игнор отключен] [закрыт для гостей] / Как готовить SPI ? / 17 сообщений из 17, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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