Основы работы Spring: аннотация @Configuration

Аннотация @Configuration является частью основной структуры фреймворка Spring. Она указывает, что класс содержит методы определения @Bean. Таким образом, контейнер Spring может обрабатывать класс и генерировать Spring Beans, которые можно использовать в приложении.

Как работает @Configuration

@Configuration позволяет нам использовать аннотации для внедрения зависимостей. Давайте разберемся, как создавать классы конфигурации Spring.

Читайте также: Внедрение зависимостей в Spring

Давайте создадим простой класс java bean.

package com.journaldev.spring;

public class MyBean {

                public MyBean() {
                               System.out.println("MyBean instance created");
                }
}

Прежде чем использовать какой-либо из классов фреймворка Spring, нам нужно добавить его зависимости в проект.

<dependency>
                               <groupId>org.springframework</groupId>
                               <artifactId>spring-context</artifactId>
                               <version>5.0.6.RELEASE</version>
</dependency>

Теперь давайте создадим класс Configuration.

package com.journaldev.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfiguration {

    @Bean
    public MyBean myBean() {
                               return new MyBean();
                }

}

Затем мы напишем простой класс и настроим наш configuration класс Spring.

package com.journaldev.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MySpringApp {

                public static void main(String[] args) {
                               AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
                               ctx.register(MyConfiguration.class);
                               ctx.refresh();

                               // MyBean mb1 = ctx.getBean(MyBean.class);

                               // MyBean mb2 = ctx.getBean(MyBean.class);

                               ctx.close();
                }

}

Если вы запустите приложение, которое мы создали выше, оно выдаст следующий результат:

May 23, 2018 12:34:54 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@ff5b51f: startup date [Wed May 23 12:34:54 IST 2018]; root of context hierarchy
MyBean instance created
May 23, 2018 12:34:54 PM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@ff5b51f: startup date [Wed May 23 12:34:54 IST 2018]; root of context hierarchy

Обратите внимание: Spring загружает bean-компоненты в свой контекст еще до того, как мы его запросили. Это делается для того, чтобы убедиться, что все bean-компоненты правильно настроены, а приложение будет работать быстро, если что-то пойдет не так. Также необходимо вызвать ctx.refresh(), иначе мы получим следующую ошибку, если попытаемся извлечь из контекста любой компонент.

Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@f0f2775 has not been refreshed yet
                at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1076)
                at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1106)
                at com.journaldev.spring.MySpringApp.main(MySpringApp.java:11)

Если вы раскомментируете операторы, в которых мы извлекаем экземпляры MyBean, вы заметите, что он не вызывает конструктор MyBean. Это связано с тем, что областью действия bean-компонентов в Spring по умолчанию является Singleton. Мы можем изменить эту область с помощью аннотации @Scope.

Что, если мы удалим аннотацию @Configuration?

Давайте посмотрим, что произойдет, если мы удалим аннотацию @Configuration из класса MyConfiguration.

Класс будет по-прежнему работать так, как ожидалось, а bean-компоненты будут регистрироваться и извлекаться как одноэлементные классы. Но если в этом случае мы вызовем метод myBean(),то у нас получится простой вызов метода Java, в результате чего мы извлечем новый экземпляр MyBean, который не будет одноэлементным. Чтобы доказать это, давайте определим другой компонент, который будет использовать экземпляр MyBean.

package com.journaldev.spring;

public class MyBeanConsumer {

                public MyBeanConsumer(MyBean myBean) {
                               System.out.println("MyBeanConsumer created");
                               System.out.println("myBean hashcode = "+myBean.hashCode());
                }

}

Обновленный класс Configuration выглядит так:

package com.journaldev.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//@Configuration
public class MyConfiguration {

                @Bean
    public MyBean myBean() {
                               return new MyBean();
                }

                @Bean
    public MyBeanConsumer myBeanConsumer() {
                               return new MyBeanConsumer(myBean());
                }
}

При запуске класс MySpringApp генерирует следующий вывод:

MyBean instance created
MyBean instance created
MyBeanConsumer created
myBean hashcode = 1647766367

Итак, MyBean больше не является одноэлементным. Теперь давайте снова аннотируем MyConfiguration с помощью @Configuration и запустим класс MySpringApp. На этот раз вывод будет таким:

MyBean instance created
MyBeanConsumer created
myBean hashcode = 1095088856

Как видите, использовать аннотацию @Configuration лучше с классами конфигурации, — это гарантирует, что контейнер Spring ведет себя так, как мы этого хотим. Если по каким-либо причинам вы не хотите использовать аннотацию @Configuration, вы все равно можете создать класс configuration – для этого не нужно вызывать метод myBean(), достаточно использовать переменную экземпляра MyBean, настроенную с помощью аннотации @Autowired. Выглядит это примерно так:

package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//@Configuration
public class MyConfiguration {

                @Autowired
                MyBean myBean;

                @Bean
    public MyBean myBean() {
                               return new MyBean();
                }

                @Bean
    public MyBeanConsumer myBeanConsumer() {
                               return new MyBeanConsumer(myBean);
                }
}

Теперь вы знаете, как работает аннотация Configuration в Spring. В следующих руководствах мы рассмотрим другие аннотации Spring.

Загрузить код можно из этого репозитория GitHub.

Tags:

Добавить комментарий