Большинство 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.
@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-файлов приложения
@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 Вконтакте.
Использованные материалы:
- docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html
- Ссылка на проект на github: github.com/saladinkzn/social-vkontakte-spring-boot-starter
Автор: saladinkzn