middle
Как работает Spring в плагинах Jira Data Center?
Плагины Jira DC используют Atlassian Spring Scanner — обёртку над Spring Framework, адаптированную для работы в OSGi-среде. Это не стандартный Spring Boot: здесь нет автоконфигурации, component-scan по конвенциям, и аннотации отличаются.
Ключевые аннотации
Пример
import javax.inject.Inject;
import javax.inject.Named;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
// @Named — аналог @Component/@Service в Spring Boot
// @Inject — аналог @Autowired
// @ComponentImport — импорт сервиса из Jira (host application)
// @ExportAsService — публикация компонента как OSGi-сервиса
Пример компонента плагина
Пример
@Named
public class IssueHelperService {
private final IssueManager issueManager;
private final UserManager userManager;
private final JiraAuthenticationContext authContext;
@Inject
public IssueHelperService(
@ComponentImport IssueManager issueManager,
@ComponentImport UserManager userManager,
@ComponentImport JiraAuthenticationContext authContext) {
this.issueManager = issueManager;
this.userManager = userManager;
this.authContext = authContext;
}
public MutableIssue getIssue(String key) {
ApplicationUser user = authContext.getLoggedInUser();
return issueManager.getIssueByCurrentKey(key);
}
}
Spring Scanner 2.x vs 1.x
| Аспект | Scanner 1.x | Scanner 2.x |
|---|---|---|
| Сканирование | Runtime (медленно) | Compile-time (быстро) |
| Конфигурация | XML + аннотации | Преимущественно аннотации |
| Производительность | Медленный старт плагина | Быстрый старт |
| component-import в XML | Обязательно | Не нужно (через @ComponentImport) |
Отличия от стандартного Spring Boot
| Spring Boot | Jira Plugin (Spring Scanner) |
|---|---|
@Service, @Component |
@Named (javax.inject) |
@Autowired |
@Inject (javax.inject) |
| Component scan по пакетам | Spring Scanner — compile-time генерация |
@Configuration + @Bean |
Ограничено, чаще — XML или @Named |
@Value("${prop}") |
SAL PluginSettings или System.getProperty() |
| ApplicationContext | OSGi BundleContext |
| Spring Data JPA | Active Objects |
Экспорт сервиса для других плагинов
Пример
@ExportAsService({NotificationService.class})
@Named
public class NotificationServiceImpl implements NotificationService {
@Inject
public NotificationServiceImpl(@ComponentImport MailServerManager mailManager) {
// ...
}
@Override
public void notify(String userKey, String message) {
// реализация
}
}
// Другой плагин может импортировать этот сервис:
@Named
public class ConsumerComponent {
@Inject
public ConsumerComponent(
@ComponentImport NotificationService notificationService) {
// использование сервиса из другого плагина
}
}
Частые ошибки
- Использование
@Autowiredвместо@Inject— может не работать в OSGi-контексте - Использование
@Service/@Componentвместо@Named— Spring Scanner их не обнаруживает - Забыть
@ComponentImportпри инжекции Jira-сервиса — получите NoSuchBeanDefinitionException - Циклические зависимости между компонентами — Spring Scanner не всегда корректно их разрешает
- Попытка использовать Spring Boot стартеры — они несовместимы с OSGi
Как используется в 2026
- Spring Scanner 2.x — стандарт для всех новых плагинов
- Compile-time сканирование стало нормой — runtime-сканирование считается legacy
- Многие разработчики приходят из Spring Boot и допускают типичные ошибки — знание различий критично
- Atlassian не планирует переход на Spring Boot для DC-плагинов — OSGi-модель остаётся
На собеседовании: главное — чётко показать отличия от стандартного Spring Boot.
@Namedвместо@Service,@Injectвместо@Autowired,@ComponentImportтолько для сервисов из Jira/других плагинов. Всегда используйте constructor injection. Это одна из тем, где ошибки допускают даже опытные Spring-разработчики.