Статьи

Spring Java Config 101

После моей последней статьи были некоторые вопросы о том, как подробно работает конфигурация Java, и мы можем расширить ее в соответствии с нашими потребностями. Поэтому я постараюсь ответить на эти вопросы в этом посте 🙂

Механизм конфигурации Java в основе Spring —   классы @Configuration . Это место, где мы можем определить все свойства нашего контекста Spring.

Предполагая, что наше приложение опирается на аннотации (что должно быть верно, если мы хотим использовать конфигурацию java), мы создаем bean-компоненты с использованием   аннотации @Component (с производными, такими как  @Repository , @Service  и  @Controller ). Различные аннотации применяются для разных слоев:

@Составная часть универсальный для любых компонентов
@Repository персистентный слой
@Обслуживание уровень обслуживания
@Составная часть уровень представления

Компонентное сканирование

После аннотирования обязательных классов мы теперь хотим добавить их в контекст Spring. Для достижения этой цели мы должны аннотировать наш  @Configuration  класс по  @ComponentScan :

@Configuration
@ComponentScan("my.package.containing.beans")
public class SpringConfig {
}

В этом случае стоит рассмотреть использование строковых литералов, представляющих пакеты, — легко допустить ошибку, которую трудно найти, потому что даже такие причудливые IDE, как IntelliJ, не заметят совершенную опечатку. К счастью, эта аннотация предлагает безопасную альтернативу, которая позволяет нам использовать   параметр basePackageClasses, чтобы указать, например, интерфейс маркера, лежащий в желаемом пакете.

По умолчанию  @ComponentScan  включает только упомянутые ранее аннотации, но мы можем легко расширить его, чтобы использовать любую пользовательскую аннотацию, например,  @ConventionSucks  :). Просто нужно добавить  элемент includeFilters :

@Configuration
@ComponentScan(basePackageClasses = BeansPackageMarker.class,
includeFilters = @ComponentScan.Filter(ConventionSucks.class))
public class SpringConfig {
}

@ ComponentScan.Filter  очень универсален и позволяет использовать различные стратегии по  типу  ( FilterType ): 

АННОТАЦИЯ помечены данной аннотацией
ASSIGNABLE_TYPE присваивается данному типу
AspectJ Шаблон типа AspectJ, переданный   атрибутом pattern
REGEX использует   класс Pattern с переданным   атрибутом pattern
CUSTOM пользовательский фильтр, реализующий  TypeFilter

Те же фильтры можно применять к  атрибуту excludeFilters  . У нас есть еще один атрибут, который обрабатывает фильтрацию —  useDefaultFilters включает  импорт всех объектов, аннотированных  @Component  производными)

Проводка бобов


Теперь мы знаем, как настроить Spring для распознавания наших bean-компонентов, но мы до сих пор не рассмотрели тему об определении зависимостей bean-компонентов (связывание bean-компонентов).
Здесь можно выделить два случая:
  • бобы, которые мы создали (у нас есть полный контроль)
  • внешние бобы

Пользовательские бины


В случае, когда мы реализуем классы, мы можем использовать 
 аннотацию
@Autowired .
@Component
public class UserBeanB {
private final UserBeanA userBeanA;
@Autowired
public UserBeanB(UserBeanA userBeanA) {
this.userBeanA = userBeanA;
}
}

Мы можем использовать   аннотацию @Autowired для конструкторов, полей, методов и аннотаций. Существует много дискуссий о том, как лучше внедрить зависимости, но мы не будем говорить об этом в этом посте.

Вместо специфической для  Spring  аннотации @Autowired мы можем использовать  @Inject,  представленный в  JSR-330 .

Внешние бобы


Это особенно важно, когда мы интегрируем некоторые внешние фреймворки или библиотеки (например, SpringSecurity)
@Configuration
public class SpringConfig {
@Bean
public ExternalObjectA externalObjectA() {
return new ExternalObjectA();
}
@Bean
public ExternalObjectB externalObjectB1() {
return new ExternalObjectB(externalObjectA());
}
@Bean
public ExternalObjectB externalObjectB2() {
return new ExternalObjectB(externalObjectA());
}
}

Обратите внимание, что   аннотация  @Bean в методе externalObjectA ()  очень важна, даже если вы не используете этот компонент вне своего класса конфигурации. Если вы примените   аннотацию @Bean, Spring во время загрузки контекста обнаружит ее и вызовет этот метод только один (даже если мы будем использовать его много раз при настройке наших bean-компонентов). Без этой аннотации метод будет рассматриваться как обычный метод Java. Также помните, что имя метода также будет использоваться как имя компонента.

Соединение разных конфигураций


Нередко при внедрении Spring Java Config возникает ситуация, когда мы хотим расширить работающее приложение (например, введя новый модуль) или очистить текущую конфигурацию, удалив явно объявленные bean-компоненты.
Также в реальных решениях мы предпочитаем иметь несколько источников конфигурации, а не просто большое большое приложение в одном гигантском классе. В такой ситуации то, что объединяет множество конфигураций, становится необходимым. Весна приносит два решения:
 Аннотация @Import для импорта различных классов конфигурации и
@ImportResource  — импортировать конфигурацию из XML-файла (вы можете использовать префиксы, такие как classpath: или file 🙂

И все — ничего странного;)