Pull to refresh

Пишем свой spring-boot-starter

Reading time 5 min
Views 61K
Большинство java-разработчиков уже познакомились с проектом Spring Boot, позволяющим быстро написать приложение, использующее различные компоненты Spring Framework (Spring MVC, Spring Data и многие другие).

Всё удобство Spring Boot основано на использовании так называемых Starter, которые позволяют получить набор сконфигурированных бинов, готовых к использованию и доступных для конфигурации через properties-файлы. Но что делать, если для нужной технологии еще не написано стартера?

В этой статье мне бы хотелось рассказать о том, как создаются стартеры на примере стартера для Spring-social-vkontakte. Spring Social это один из модулей Spring Framework, используемый для интеграции с социальными сетями. В проект Spring Boot включены стартеры для таких социальных сетей как Facebook (spring-boot-starter-social-facebook), Twitter (spring-boot-starter-social-twitter) и LinkedIn (spring-boot-starter-social-twitter), основанные на использовании соответствующих Social-модулей. Большинство разработчиков из СНГ интересует в первую очередь социальная сеть Вконтакте, для которой существует сторонний модуль spring-social-vkontakte. Соответственно, стартера для этого модуля еще нет. Написанием этого стартера мы и займемся в этой статье.

Краеугольным камнем инфраструктуры Spring Boot являются AutoConfiguration-классы, которые Spring Boot находит при запуске приложения и использует для автоматического создания и конфигурирования бинов.

Создадим такой класс для нашего стартера:

@Configuration
@ConditionalOnClass({SocialConfigurerAdapter.class, VKontakteConnectionFactory.class})
@ConditionalOnProperty(prefix= "ru.shadam.social-vkontakte", name = { "client-id", "client-secret"})
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class VKontakteAutoConfiguration {
}

Мы используем аннотации, чтобы указать SpringBoot, что наш класс является конфигурацией (@Configuration), аннотации, чтобы задать условия, при которых наш AutoConfiguration будет использоваться для создания бинов, а также аннотации, чтобы указать каково место нашей автоконфигурации в процедуре инициализации приложения.

Таким образом:

@ConditionalOnClass({SocialConfigurerAdapter.class, VKontakteConnectionFactory.class})

означает, что бины будут создаваться при наличии в classpath SocialConfigurerAdapter(входит в модуль Spring-Social) и VKontakteConnectionFactory (входит в модуль Spring-Social-Vkontakte). Таким образом, без нужных для нашего стартера зависимостей бины создаваться не будут.

@ConditionalOnProperty(prefix= "ru.shadam.social-vkontakte", name = { "client-id", "client-secret"})

означает, что бины будут создаваться только при наличии property ru.shadam.social-vkontakte.client-id и ru.shadam.social-vkontakte.client-secret.

@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)

означает, что наш бин будет инициализироваться после WebMvc и до SocialWeb. Это нужно, чтобы к моменту инициализации SocialWeb наши бины уже были зарегистрированы.

Теперь перейдем к тому, какие бины мы сконфигурируем в нашем AutoConfiguration.

VKontakteAutoConfiguration.java
@Configuration
@ConditionalOnClass({SocialConfigurerAdapter.class, VKontakteConnectionFactory.class})
@ConditionalOnProperty(prefix= "ru.shadam.social-vkontakte", name = { "client-id", "client-secret"})
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class VKontakteAutoConfiguration {

    @Configuration
    @EnableSocial
    @EnableConfigurationProperties(VKontakteProperties.class)
    @ConditionalOnWebApplication
    protected static class VKontakteConfigurationAdapter extends SocialConfigurerAdapter {

        @Autowired
        private VKontakteProperties properties;

        @Bean
        @ConditionalOnMissingBean
        @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
        public VKontakte vkontakte(ConnectionRepository repository) {
            Connection<VKontakte> connection = repository.findPrimaryConnection(VKontakte.class);
            if (connection != null) {
                return connection.getApi();
            }
            return new VKontakteTemplate(this.properties.getClientId(), this.properties.getClientSecret());
        }

        private ConnectionFactory<?> createConnectionFactory() {
            return new VKontakteConnectionFactory(this.properties.getClientId(), this.properties.getClientSecret());
        }

        @Override
        public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) {
            connectionFactoryConfigurer.addConnectionFactory(createConnectionFactory());
        }
    }
}


Расширяем SocialConfigurationAdapter, который нужен для того чтобы зарегистрировать нашу ConnectionFactory. Для этого в SocialConfigurerAdapter есть callback-метод:

addConnectionFactories(ConnectionFactoryConfigurer, Environment)

Его мы и переопределим, добавляя нашу ConnectionFactory.

Также зарегистрируем request-scoped бин Vkontakte, которые представляет собой интерфейс для доступа к API Вконтакте. При этом, если пользователь авторизуется через приложение, то операции взаимодействия с API будет выполнено с использованием auth_token.

Рассмотрим также класс VkontakteProperties, который используется для получения конфигурации из properties-файлов приложения

VkontakteProperties.java
@ConfigurationProperties(prefix = "ru.shadam.social-vkontakte")
public class VKontakteProperties  {
    private String clientId;
    private String clientSecret;

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public String getClientSecret() {
        return clientSecret;
    }

    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }
}


За получение значений из properties файлов отвечает аннотация:

@ConfigurationProperties(prefix = "ru.shadam.social-vkontakte")

Она сообщает SpringBoot, что нужно попытаться все проперти, начинающиеся с префикса ru.shadam.social-vkontakte поместить в соответствующие поля класса.

Последним нашим шагом будет создание файла, позволяющего SpringBoot найти наш AutoConfiguration класс. Для этого существует специальный файл spring.factories, который нужно поместить в META-INF папку получающегося jar-файла.

В этом файле нам надо указать наш AutoConfiguration-класс.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=ru.shadam.spring.boot.vkontakte.VKontakteAutoConfiguration

Теперь, подключив получившийся jar к нашему Spring Boot проекту и задав в конфигурации ru.shadam.social-vkontakte.client-id и ru.shadam.social-vkontakte.client-secret, мы получим в нашем приложении сконфигруированные пути /connect/vkontakte и бин Vkontakte, который мы можем использовать для доступа к API Вконтакте.

Использованные материалы:

  1. docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html
  2. Ссылка на проект на github: github.com/saladinkzn/social-vkontakte-spring-boot-starter
Tags:
Hubs:
+16
Comments 0
Comments Leave a comment

Articles