Основні поняття: @Bean та @Configuration
Центральними артефактами в нових засобах підтримки Java-конфігурації в Spring є класи, позначені анотацією @Configuration, та методи, позначені анотацією @Bean.
Аннотація @Bean використовується для зазначення того, що метод створює екземпляр, конфігурує та ініціалізує новий об'єкт, яким керуватиме IoC-контейнер Spring. Для тих, хто знайомий з XML-конфігурацією <beans/> зі Spring, анотація @Bean відіграє ту ж роль, що й елемент <bean/>. Ти можеш використовувати методи, анотовані @Bean, з будь-якою анотацією @Component зі Spring. Однак найчастіше вони використовуються з бінами, анотованими @Configuration.
Анотування класу за допомогою @Configuration вказує на те, що його основне призначення — бути джерелом визначень біну. Більш того, класи, анотовані @Configuration, дозволяють визначати міжбінові залежності шляхом виклику інших методів @Bean у тому самому класі. Найпростіший можливий клас, анотований @Configuration, виглядає так:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun myService(): MyService {
return MyServiceImpl()
}
}
Попередній клас AppConfig еквівалентний наступному XML-класу <beans/> зі Spring:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
Анотації @Bean та @Configuration докладно розглянуті в наступних розділах. Однак спочатку ми розглянемо різні способи створення контейнера Spring за допомогою конфігурації на основі Java.
Створення екземпляра контейнера Spring за допомогою AnnotationConfigApplicationContext
Наступні розділи описують AnnotationConfigApplicationContext, представлений у Spring 3.0. Ця універсальна реалізація інтерфейсу ApplicationContext здатна приймати на введення не тільки класи, позначені анотацією @Configuration, а й звичайні класи, анотовані @Component, а також класи, анотовані метаданими з JSR-330.
Якщо класи, позначені анотацією @Configuration, вказані як вхідні дані, сам клас, анотований @Configuration, реєструється як визначення біна, а всі оголошені в класі методи, позначені анотацією @Bean, також реєструються як визначення біна.
Якщо згадані класи, позначені анотацією @Component, або з JSR-330, вони реєструються як визначення бінів, і передбачається, що метадані впровадження залежностей, такі як @Autowired або @Inject, використовуються в цих класах, де це необхідно.
Проста конструкція
Так само, як XML-файли Spring використовуються як вхідні дані при створенні ClassPathXmlApplicationContext, можна використовувати класи, анотовані @Configuration, як вхідні дані при створенні AnnotationConfigApplicationContext. Це дозволяє використовувати контейнер Spring повністю без XML, як показано в наступному прикладі:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = AnnotationConfigApplicationContext(AppConfig::class.java)
val myService = ctx.getBean<MyService>()
myService.doStuff()
}
Як згадувалося раніше, AnnotationConfigApplicationContext не обмежується роботою лише з класами, анотованими @Configuration. Будь-який анотований @Component або JSR-330 клас можна надати як вхід до конструктора, як показано в наступному прикладі:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = AnnotationConfigApplicationContext(MyServiceImpl::class.java, Dependency1::class.java, Dependency2::class.java)
val myService = ctx.getBean<MyService>()
myService.doStuff()
}
У попередньому прикладі передбачається, що MyServiceImpl, Dependency1 та Dependency2 використовують анотації впровадження залежностей Spring, такі як анотація @Autowired.
Побудова контейнера програмно за допомогою register(Class<?>… )
Ти можеш створити AnnotationConfigApplicationContext за допомогою конструктора без аргументів, а потім налаштувати його за допомогою методу register(). Цей підхід є особливо корисним у програмній побудові AnnotationConfigApplicationContext. У цьому прикладі показано, як це зробити:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = AnnotationConfigApplicationContext()
ctx.register(AppConfig::class.java, OtherConfig::class.java)
ctx.register(AdditionalConfig::class.java)
ctx.refresh()
val myService = ctx.getBean <MyService>()
myService.doStuff()
}
Увімкнення сканування компонентів за допомогою scan(String…)
Щоб увімкнути сканування компонентів,можна анотувати свій клас за допомогою @Configuration так:
@Configuration
@ComponentScan(basePackages = "com. acme")
public class AppConfig {
// ...
}
- Ця анотація дозволяє сканувати компоненти.
@Configuration
@ComponentScan(basePackages = ["com.acme"])
class AppConfig {
// ...
}
- Ця анотація дозволяє сканувати компоненти.
Досвідчені користувачі Spring можуть бути знайомі з еквівалентом XML-оголошення з простору імен context: у Spring, показаному в наступному прикладі:
<beans>
<context:component-scan base-package="com.acme"/>
</beans>
У попередньому прикладі пакет com.acme сканується на пошук будь-яких класів, анотованих @Component, а ці класи реєструються як визначення біна Spring у контейнері. AnnotationConfigApplicationContext відкриває метод scan(String…) для надання такої ж функціональності сканування компонентів, як показано в наступному прикладі:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
fun main() {
val ctx = AnnotationConfigApplicationContext()
ctx.scan("com.acme")
ctx.refresh()
val myService = ctx.getBean<MyService>()
}
@Configuration мета-анотовані за допомогою
@Component, тому є кандидатами на сканування компонентів. У попередньому прикладі, якщо припустити, що
AppConfig оголошено в пакеті
com.acme (або в будь-якому іншому пакеті під ним), він перехоплюється під час виклику
scan() . Після
refresh() всі його методи, анотовані
@Bean, обробляються та реєструються як визначення бінів у контейнері.
Підтримка вебдодатків за допомогою AnnotationConfigWebApplicationContext
До варіанта WebApplicationContext класу AnnotationConfigApplicationContext можна отримати доступ за допомогою AnnotationConfigWebApplicationContext. Можеш використовувати цю реалізацію у налаштуванні слухача сервлета ContextLoaderListener зі Spring, DispatcherServlet зі Spring MVC тощо. Наступний фрагмент web.xml конфігурує типовий вебдодаток у Spring MVC (зверни увагу на використання context-параметрів contextClass та init-параметрів):
<web-app>
<!-- Налаштування ContextLoaderListener для використання AnnotationConfigWebApplicationContext
замість стандартного XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Розташування конфігурації має складатися з одного або декількох розділених комами або пробілами
повних імен класів, анотованих @Configuration. Повні імена пакетів можна також -->
<context-param>
<param-name>contextConfigLocation>/param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Здійснюємо початкове завантаження контексту кореневої програми, як завжди, використовуючи ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-classм
</listener>
<!-- Оголошуємо DispatcherServlet у Spring MVC, як завжди -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Конфігуруємо DispatcherServlet на використання AnnotationConfigWebApplicationContext
замість стандартного XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Знову ж таки, розташування конфігурації повинні складатися з одного або декількох розділених комами або пробілами
і повних імен класів, анотованих @Configuration -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- зіставте всі запити для /app/* із сервлетом диспетчера -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
GenericWebApplicationContext може використовуватися як альтернатива
AnnotationConfigWebApplicationContext. Подробиці див. у javadoc за
GenericWebApplicationContext.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ