Рубрики
Без рубрики

Исключение переопределения определения компонента в Spring Boot

Узнайте об исключении переопределения определения компонента в Spring Boot и о том, как с ним работать.

Автор оригинала: Yavuz Tas.

1. введение

Обновление Spring Boot 2.1 удивило нескольких людей неожиданным появлением BeanDefinitionOverrideException . Это может сбить с толку некоторых разработчиков и заставить их задуматься о том, что случилось с поведением переопределения бобов весной.

В этом уроке мы разберемся с этой проблемой и посмотрим, как лучше всего ее решить.

2. Зависимости Maven

Для нашего примера проекта Maven нам нужно добавить зависимость Spring Boot Starter :


    org.springframework.boot
    spring-boot-starter
    2.3.3.RELEASE

3. Переопределение бобов

Весенние бобы идентифицируются по их именам в ApplicationContext .

Таким образом, быть переопределением-это поведение по умолчанию, которое происходит, когда мы определяем компонент в ApplicationContext , который имеет то же имя, что и другой компонент . Он работает, просто заменяя прежний компонент в случае конфликта имен.

Начиная с весны 5.1, было введено исключение переопределения определения компонента , позволяющее разработчикам автоматически создавать исключение, чтобы предотвратить любое неожиданное переопределение компонента . По умолчанию исходное поведение по-прежнему доступно, что позволяет переопределять компоненты.

4. Изменение конфигурации для Spring Boot 2.1

Spring Boot 2.1 отключил переопределение компонентов по умолчанию в качестве защитного подхода. Основная цель состоит в том, чтобы заранее заметить повторяющиеся имена компонентов, чтобы предотвратить случайное переопределение компонентов .

Поэтому, если наше приложение Spring Boot полагается на переопределение компонентов, оно, скорее всего, столкнется с исключением BeanDefinitionOverrideException после обновления версии Spring Boot до версии 2.1 и более поздних версий.

В следующих разделах мы рассмотрим пример, в котором будет возникать исключение переопределения определения Bean , а затем обсудим некоторые решения.

5. Выявление конфликтующих сторон

Давайте создадим две различные конфигурации Spring, каждая из которых имеет метод testBean () , чтобы создать исключение BeanDefinitionOverrideException:

@Configuration
public class TestConfiguration1 {

    class TestBean1 {
        private String name;

        // standard getters and setters

    }

    @Bean
    public TestBean1 testBean(){
        return new TestBean1();
    }
}
@Configuration
public class TestConfiguration2 {

    class TestBean2 {
        private String name;

        // standard getters and setters

    }

    @Bean
    public TestBean2 testBean(){
        return new TestBean2();
    }
}

Далее мы создадим наш тестовый класс Spring Boot:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {TestConfiguration1.class, TestConfiguration2.class})
public class SpringBootBeanDefinitionOverrideExceptionIntegrationTest {

    @Test
    public void whenBeanOverridingAllowed_thenTestBean2OverridesTestBean1() {
        Object testBean = applicationContext.getBean("testBean");

        assertThat(testBean.getClass()).isEqualTo(TestConfiguration2.TestBean2.class);
    }
}

Запуск теста приводит к исключению переопределения определения компонента /. Однако это исключение дает нам некоторую полезную информацию:

Invalid bean definition with name 'testBean' defined in ... 
... com.baeldung.beandefinitionoverrideexception.TestConfiguration2 ...
Cannot register bean definition [ ... defined in ... 
... com.baeldung.beandefinitionoverrideexception.TestConfiguration2] for bean 'testBean' ...
There is already [ ... defined in ...
... com.baeldung.beandefinitionoverrideexception.TestConfiguration1] bound.

Обратите внимание, что исключение раскрывает две важные части информации.

Первый-это конфликтующее имя компонента, testBean :

Invalid bean definition with name 'testBean' ...

А второй показывает нам полный путь затронутых конфигураций:

... com.baeldung.beandefinitionoverrideexception.TestConfiguration2 ...
... com.baeldung.beandefinitionoverrideexception.TestConfiguration1 ...

В результате мы видим, что два разных компонента идентифицируются как testBean , вызывающие конфликт. Кроме того, компоненты содержатся в классах конфигурации Тестовая конфигурация 1 и Тестовая конфигурация 2 .

6. Возможные решения

В зависимости от вашей конфигурации компоненты Spring имеют имена по умолчанию, если мы не зададим их явно.

Поэтому первое возможное решение-переименовать наши бобы.

Есть несколько распространенных способов задать имена бобов весной.

6.1. Изменение имен Методов

По умолчанию Spring принимает имена аннотированных методов в качестве имен компонентов .

Поэтому, если у нас есть бобы, определенные в классе конфигурации, как в нашем примере, то простое изменение имен методов предотвратит исключение BeanDefinitionOverrideException :

@Bean
public TestBean1 testBean1() {
    return new TestBean1();
}
@Bean
public TestBean2 testBean2() {
    return new TestBean2();
}

6.2. Аннотация @Bean

Аннотация Spring @Bean – очень распространенный способ определения боба.

Таким образом, другой вариант-установить имя свойство @Bean аннотации:

@Bean("testBean1")
public TestBean1 testBean() {
    return new TestBean1();
}
@Bean("testBean2")
public TestBean1 testBean() {
    return new TestBean2();
}

6.3. Аннотации стереотипов

Другой способ определения компонента-это аннотации стереотипов . С включенной функцией Spring @ComponentScan мы можем определить имена наших компонентов на уровне класса, используя аннотацию @Component :

@Component("testBean1")
class TestBean1 {

    private String name;

    // standard getters and setters

}
@Component("testBean2")
class TestBean2 {

    private String name;

    // standard getters and setters

}

6.4. Бобы, Поступающие Из Сторонних Библиотек

В некоторых случаях можно столкнуться с конфликтом имен, вызванным компонентами, происходящими из сторонних библиотек, поддерживаемых spring|/.

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

Однако, если мы не можем изменить ни одно из определений компонентов, при настройке Spring Boot, чтобы разрешить переопределение компонентов, может быть обходным путем.

Чтобы включить переопределение компонентов, давайте установим для свойства spring.main.allow-bean-definition-overriding значение true в нашем файле application.properties :

spring.main.allow-bean-definition-overriding=true

Делая это, мы говорим Spring Boot разрешить переопределение компонентов без каких-либо изменений в определениях компонентов.

В качестве заключительного замечания мы должны знать, что трудно угадать, какой компонент будет иметь приоритет, поскольку порядок создания компонента определяется отношениями зависимостей, на которые в основном влияют во время выполнения . Поэтому разрешение быть переопределением может привести к неожиданному поведению, если мы недостаточно хорошо не знаем иерархию зависимостей ваших компонентов.

7. Заключение

В этом уроке мы объяснили, что означает Bean Definition Override Exception в Spring, почему оно внезапно появляется и как его устранить после обновления Spring Boot 2.1.

Как всегда, полный исходный код этой статьи можно найти на GitHub .