Gymterview
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-разработчики.