1. Обзор
Проще говоря, ядро Spring Framework — это контейнер IoC, используемый для управления bean-компонентами.
В Spring есть два основных типа контейнеров — Bean Factory и Application Context. Первый предоставляет базовые функции, которые представлены здесь ; последний является надмножеством первого и наиболее широко используется.
ApplicationContext
— это интерфейс в пакете org.springframework.context
, который имеет несколько реализаций, и ClassPathXmlApplicationContext
— одна из них.
В этой статье мы сосредоточимся на полезных функциях, предоставляемых ClassPathXmlApplicationContext
.
2. Основное использование
2.1. Инициализировать контейнер и управлять компонентами
ClassPathXmlApplicationContext
может загружать конфигурацию XML из пути к классам и управлять его компонентами:
У нас есть студенческий
класс:
public class Student {
private int no;
private String name;
// standard constructors, getters and setters
}
Мы настраиваем компонент Student в
classpathxmlapplicationcontext-example.xml
и добавляем его в путь к классам:
<beans ...>
<bean id="student" class="com.foreach.applicationcontext.Student">
<property name="no" value="15"/>
<property name="name" value="Tom"/>
</bean>
</beans>
Теперь мы можем использовать ClassPathXmlApplicationContext
для загрузки конфигурации XML и получения bean- компонента Student
:
@Test
public void testBasicUsage() {
ApplicationContext context
= new ClassPathXmlApplicationContext(
"classpathxmlapplicationcontext-example.xml");
Student student = (Student) context.getBean("student");
assertThat(student.getNo(), equalTo(15));
assertThat(student.getName(), equalTo("Tom"));
Student sameStudent = context.getBean("student", Student.class);
assertThat(sameStudent.getNo(), equalTo(15));
assertThat(sameStudent.getName(), equalTo("Tom"));
}
2.2. Несколько конфигураций XML
Иногда мы хотим использовать несколько конфигураций XML для инициализации контейнера Spring. В этом случае нам просто нужно добавить несколько мест конфигурации при создании ApplicationContext
:
ApplicationContext context
= new ClassPathXmlApplicationContext("ctx.xml", "ctx2.xml");
3. Дополнительные возможности
3.1. Изящно завершите работу контейнера Spring IoC
Когда мы используем контейнер Spring IoC в веб-приложении, веб- реализации Spring ApplicationContext
корректно завершат работу контейнера при закрытии приложения, но если мы используем его в не-веб-среде, например, в автономном настольном приложении, мы должны самостоятельно зарегистрировать обработчик завершения работы с JVM, чтобы убедиться, что контейнер Spring IoC корректно закрыт, и вызывает методы уничтожения для освобождения ресурсов.
Давайте добавим метод destroy()
в класс Student :
public void destroy() {
System.out.println("Student(no: " + no + ") is destroyed");
}
Теперь мы можем настроить этот метод как метод уничтожения бина - ученика :
<beans ...>
<bean id="student" class="com.foreach.applicationcontext.Student"
destroy-method="destroy">
<property name="no" value="15"/>
<property name="name" value="Tom"/>
</bean>
</beans>
Теперь мы зарегистрируем хук выключения:
@Test
public void testRegisterShutdownHook() {
ConfigurableApplicationContext context
= new ClassPathXmlApplicationContext(
"classpathxmlapplicationcontext-example.xml");
context.registerShutdownHook();
}
Когда мы запускаем тестовый метод, мы видим, что вызывается метод destroy() .
3.2. Интернационализация с MessageSource
Интерфейс ApplicationContext
расширяет интерфейс MessageSource
, поэтому обеспечивает функциональность интернационализации.
Контейнер ApplicationContext
автоматически ищет bean-компонент MessageSource
при своей инициализации, и этот bean-компонент должен быть назван messageSource
.
Вот пример использования разных языков с MessageSource
:
Во-первых, давайте добавим каталог диалога
в путь к классам и добавим в каталог диалога два файла: dialog_en.properties
и dialog_zh_CN.properties
.
dialog_en.properties
:
hello=hello
you=you
thanks=thank {0}
dialog_zh_CN.properties
:
hello=\u4f60\u597d
you=\u4f60
thanks=\u8c22\u8c22{0}
Настройте bean-компонент messageSource
в classpathxmlapplicationcontext-internationalization.xml
:
<beans ...>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>dialog/dialog</value>
</list>
</property>
</bean>
</beans>
Затем давайте получим диалоговые слова разных языков с помощью MessageSource
:
@Test
public void testInternationalization() {
MessageSource resources
= new ClassPathXmlApplicationContext(
"classpathxmlapplicationcontext-internationalization.xml");
String enHello = resources.getMessage(
"hello", null, "Default", Locale.ENGLISH);
String enYou = resources.getMessage(
"you", null, Locale.ENGLISH);
String enThanks = resources.getMessage(
"thanks", new Object[] { enYou }, Locale.ENGLISH);
assertThat(enHello, equalTo("hello"));
assertThat(enThanks, equalTo("thank you"));
String chHello = resources.getMessage(
"hello", null, "Default", Locale.SIMPLIFIED_CHINESE);
String chYou = resources.getMessage(
"you", null, Locale.SIMPLIFIED_CHINESE);
String chThanks = resources.getMessage(
"thanks", new Object[] { chYou }, Locale.SIMPLIFIED_CHINESE);
assertThat(chHello, equalTo("你好"));
assertThat(chThanks, equalTo("谢谢你"));
}
4. Ссылка на ApplicationContext
Иногда нам нужно получить ссылку на ApplicationContext
внутри управляемых им bean-компонентов, для этого мы можем использовать ApplicationContextAware
или @Autowired
. Давайте посмотрим, как работает ApplicationContextAware
:
У нас есть класс курса
с именем:
public class Course {
private String name;
// standard constructors, getters and setters
}
У нас есть класс учителя
, который собирает свои курсы в соответствии с компонентами контейнера:
public class Teacher implements ApplicationContextAware {
private ApplicationContext context;
private List<Course> courses = new ArrayList<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
@PostConstruct
public void addCourse() {
if (context.containsBean("math")) {
Course math = context.getBean("math", Course.class);
courses.add(math);
}
if (context.containsBean("physics")) {
Course physics = context.getBean("physics", Course.class);
courses.add(physics);
}
}
// standard constructors, getters and setters
}
Давайте настроим bean-компоненты курса
и bean-компонента учителя
в classpathxmlapplicationcontext-example.xml
:
<beans ...>
<bean id="math" class="com.foreach.applicationcontext.Course">
<property name="name" value="math"/>
</bean>
<bean name="teacher" class="com.foreach.applicationcontext.Teacher"/>
</beans>
Затем — протестируйте инъекцию свойства курсов :
@Test
public void testApplicationContextAware() {
ApplicationContext context
= new ClassPathXmlApplicationContext(
"classpathxmlapplicationcontext-example.xml");
Teacher teacher = context.getBean("teacher", Teacher.class);
List<Course> courses = teacher.getCourses();
assertThat(courses.size(), equalTo(1));
assertThat(courses.get(0).getName(), equalTo("math"));
}
Помимо реализации интерфейса ApplicationContextAware
, такой же эффект дает использование аннотации @Autowired .
Давайте изменим класс учителя на это:
public class Teacher {
@Autowired
private ApplicationContext context;
private List<Course> courses = new ArrayList<>();
@PostConstruct
public void addCourse() {
if (context.containsBean("math")) {
Course math = context.getBean("math", Course.class);
courses.add(math);
}
if (context.containsBean("physics")) {
Course physics = context.getBean("physics", Course.class);
courses.add(physics);
}
}
// standard constructors, getters and setters
}
Затем запустите этот тест, мы увидим, что результат тот же.
5. Вывод
ApplicationContext
— это контейнер Spring с большим количеством функций, специфичных для предприятия, по сравнению с BeanFactory
, а ClassPathXmlApplicationContext
— одна из наиболее часто используемых его реализаций.
Итак, в этой статье мы представили несколько аспектов ClassPathXmlApplicationContext
, в том числе его базовое использование, его функциональность регистрации завершения работы, его функциональность интернационализации и получение его ссылки.
Как всегда, полный исходный код примера доступен на GitHub .