Что такое @Autowire в Spring? Как его использовать и как он работает?

Rmag Breaking News

Начиная с версии 2.5 Spring поддерживает Dependency Injection при помощи аннотаций. Одной из ключевых, такого рода аннотаций, является @Autowired. Она позволяет резолвить и инжектить зависимости во время инициализации бина.

Использование @Autowired

Автовайринг можно использовать на полях класса, сеттерах и конструкторах.

Смотрите документацию тут: Using @Autowired

Пример автовайринга полей класса:

@Component
public class MyService {
@Autowired
private MyDependency myDependency;
}

@Component(“myDependency”)
public class MyDependency {
……
}

Также можно автовайрить массив бинов одного типа:

public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
}

Т.е. если у нас в ApplicationContext много бинов одного и того же типа MovieCatalog, все они будут заинжекчены в массив movieCatalogs.
Автовайринг также работает для конструктора класса:

public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;

@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
….
}

И для сеттеров:

public class SimpleMovieLister {
private MovieFinder movieFinder;

@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
….
}

Начиная с версии Spring Framework 4.3, аннотация @Autowired для конструктора больше не требуется, если в бине только один конструктор. Однако, если в нем несколько конструкторов, то хотя бы один из конструкторов должен быть аннотирован @Autowired, чтобы указать контейнеру, какой из них использовать.

По умолчанию, если зависимость нельзя зарезолвить, то будет брошено исключение NoSuchBeanDefinitionException. Если мы все равно хотим создать бин, даже если не получается зарезолвить зависимость, то можно использовать required = false:

public class FooService {
@Autowired(required = false)
private FooDAO dataAccessor;
}

В таком случае бин FooService будет создан даже если бин FooDAO не может быть зарезолвен.
Или можно использовать Optional:

public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder)
{
….
}
}

Начиная с версии Spring 5.0 можно использовать @Nullable:

public class SimpleMovieLister {

@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {

}
}

Можно автовайрить коллекции одного типа:

public class MovieRecommender {

private Set<MovieCatalog> movieCatalogs;

@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}

// …
}

Если нам нужно, чтобы бины инжектились в коллекцию в определенном порядке, то можно использовать на бинах аннотацию @Order или @Priority.
Также можно инжектить Map, у которого ключ – строка. Это строка будет именем бина:

public class MovieRecommender {

private Map<String, MovieCatalog> movieCatalogs;

@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}

// …
}

Резолвинг зависимостей

По умолчанию Spring резолвит @Autowired зависимости по типу. Если у нас больше одного бина одного и того же типа и мы не инжектим коллекцию или Map, то может быть брошено исключение, если мы не зарезолвим конфликты при помощи @Qualifier или по имени.

Например:

@Component(“fooFormatter”)
public class FooFormatter implements Formatter {
public String format() {
return “foo”;
}
}

@Component(“barFormatter”)
public class BarFormatter implements Formatter {
public String format() {
return “bar”;
}
}
public class FooService {
@Autowired
private Formatter formatter;
}

В данном случае будет брошено исключение NoUniqueBeanDefinitionException, т.к. у нас два бина одного и того же и типа и при попытке заинжектить зависимость при помощи автовайринга, Spring не сможет зарезолвить какой из бинов инжектить.
Для решения этой проблемы можно использовать @Qualifier для указания какой именно бин нам нужен:

public class FooService {
@Autowired
@Qualifier(“fooFormatter”)
private Formatter formatter;
}

Если @Qualifier не указывать, то Spring попытается заметчить имя поля с именем бина:

public class FooService {
@Autowired
private Formatter fooFormatter;
}

Как включить Автовайринг?

Если вы используете Spring Boot, то @SpringBootApplication аннотация включает в себя @Configuration, @EnableAutoConfiguration, и @ComponentScan. Что достаточно, чтобы работал Автовайринг:

@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

В результате Spring будет сканировать бины в рамках текущего package и всех его sub-packages. Регистрировать их в Application Context и инжектить бины используя автовайринг.

Если мы не используем Spring Boot, то можно включить автовайринг в Java конфигурации:

@Configuration
@ComponentScan(“com.mypackage”)
public class AppConfig {}

Или если мы используем XML-конфиги, то нужно добавить

<context:annotation-config/>

в наш XML-конфиг.

Leave a Reply

Your email address will not be published. Required fields are marked *