1. Общ преглед
Започвайки с Spring 2.5, рамката въвежда инжектиране на зависимостта, управлявано от анотации . Основната анотация на тази функция е @Autowired . Позволява на Spring да разрешава и инжектира боб, който си сътрудничи, в нашия боб.
В този урок първо ще разгледаме как да активираме автоматично свързване иразличниначини за автоматично свързване на зърна. След това ще говорим за разрешаване на конфликти на компоненти с помощта на анотация @Qualifier , както и потенциални сценарии за изключения.
2. Активиране на @Autowired Анотации
Структурата Spring позволява автоматично инжектиране на зависимост. С други думи, чрез деклариране на всички зависимости на боб в пролетен конфигурационен файл, Spring контейнер може автоматично да свързва връзки между сътрудничещите бобчета . Това се нарича Springwin autowiring .
За да използваме Java-базирана конфигурация в нашето приложение, нека активираме инжектиране, управлявано от анотацииза да заредим нашата Spring конфигурация:
@Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {}
Като алтернатива, анотацията се използва главно за активиране на анотациите за инжектиране на зависимост в Spring XML файлове.
Освен това Spring Boot въвежда анотацията @SpringBootApplication . Тази единична анотация е еквивалентна на използването на @Configuration , @EnableAutoConfiguration и @ComponentScan .
Нека използваме тази анотация в основния клас на приложението:
@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } }
В резултат на това, когато стартираме това приложение Spring Boot, то автоматично ще сканира компонентите в текущия пакет и неговите подпакети . По този начин той ще ги регистрира в контекста на приложението на Spring и ще ни позволи да инжектираме боб с помощта на @Autowired .
3. Използване на @Autowired
След като активираме инжектирането на анотации, можем да използваме автоматично свързване на свойства, сетери и конструктори .
3.1. @Autowired на Properties
Нека да видим как можем да анотираме свойство с помощта на @Autowired . Това елиминира нуждата от гетери и сетери.
Първо, нека дефинираме боб fooFormatter :
@Component("fooFormatter") public class FooFormatter { public String format() { return "foo"; } }
След това ще инжектирате този боб в FooService боб с помощта @Autowired на определението на полето:
@Component public class FooService { @Autowired private FooFormatter fooFormatter; }
В резултат на това Spring инжектира fooFormatter, когато се създава FooService .
3.2. @Autowired on Setters
Сега нека опитаме да добавим @Autowired анотация на метод за настройка.
В следващия пример методът за задаване се извиква с екземпляра на FooFormatter, когато се създава FooService :
public class FooService { private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }
3.3. @Autowired на конструктори
И накрая, нека използваме @Autowired върху конструктор.
Ще видим, че екземпляр на FooFormatter се инжектира от Spring като аргумент на конструктора FooService :
public class FooService { private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }
4. @ Автоматични и незадължителни зависимости
Когато се изгражда боб, трябва да са налични зависимостите @Autowired . В противен случай, ако Spring не може да разреши боб за окабеляване, ще изведе изключение .
Следователно, той пречи на Spring контейнера да се стартира успешно, с изключение на формата:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
За да поправим това, трябва да декларираме боб от необходимия тип:
public class FooService { @Autowired(required = false) private FooDAO dataAccessor; }
5. Автоматично премахване на двузначността
По подразбиране Spring решава записите @Autowired по тип. Ако в контейнера са налични повече от един боб от същия тип, рамката ще изведе фатално изключение .
За да разрешим този конфликт, трябва изрично да кажем на Spring кой боб искаме да инжектираме.
5.1. Автоматично свързване от @Qualifier
Например, нека видим как можем да използваме анотацията @Qualifier, за да посочим необходимия боб.
Първо ще дефинираме 2 зърна от тип Formatter :
@Component("fooFormatter") public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@Component("barFormatter") public class BarFormatter implements Formatter { public String format() { return "bar"; } }
Сега нека се опитаме да инжектираме Bean Formatter в класа FooService :
public class FooService { @Autowired private Formatter formatter; }
В нашия пример има две конкретни реализации на Formatter, налични за контейнера Spring. В резултат Spring ще хвърли изключение NoUniqueBeanDefinitionException при конструирането на FooService :
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.autowire.sample.Formatter] is defined: expected single matching bean but found 2: barFormatter,fooFormatter
Можем да избегнем това, като стесним изпълнението с помощта на анотация @Qualifier :
public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }
Когато има няколко зърна от един и същи вид, е добре да използвате @Qualifier, за да избегнете неясноти.
Моля, обърнете внимание, че стойността на анотацията @Qualifier съвпада с името, декларирано в анотацията @Component на нашата реализация FooFormatter .
5.2. Автоматично свързване от потребителски квалификатор
Spring също ни позволява да създадем своя собствена анотация @Qualifier . За целта трябва да предоставим анотацията @Qualifier с дефиницията:
@Qualifier @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType { String value(); }
След това можем да използваме FormatterType в различни изпълнения, за да зададем персонализирана стойност:
@FormatterType("Foo") @Component public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@FormatterType("Bar") @Component public class BarFormatter implements Formatter { public String format() { return "bar"; } }
И накрая, нашата персонализирана анотация на Qualifier е готова за използване за автоматично свързване:
@Component public class FooService { @Autowired @FormatterType("Foo") private Formatter formatter; }
Стойността, посочена в мета-анотацията @Target, ограничава къде да приложите квалификатора, който в нашия пример е полета, методи, типове и параметри.
5.3. Автоматично свързване по име
Spring използва името на зърното като стандартна стойност на квалификатора. Той ще инспектира контейнера и ще потърси боб с точното име като свойство, за да го свърже автоматично.
Следователно, в нашия пример, Пролет съвпада с fooFormatter името собственост на FooFormatter изпълнението. Следователно той инжектира тази конкретна реализация при конструирането на FooService :
public class FooService { @Autowired private Formatter fooFormatter; }
6. Заключение
В тази статия обсъдихме автоматичното свързване и различните начини за неговото използване. Също така разгледахме начини за разрешаване на две общи изключения за автоматично свързване, причинени или от липсващ боб, или от неясна инжекция на боб.
Изходният код на тази статия е достъпен в проекта GitHub.