Введение в Spring ClassPathXmlApplicationContext

1. Обзор

Проще говоря, ядро ​​Spring Framework - это контейнер IoC, используемый для управления bean-компонентами.

В Spring есть два основных типа контейнеров - Bean Factory и Application Context. Первый обеспечивает основные функциональные возможности, которые вводятся по ссылке:/spring-beanfactory[здесь]; последний является надмножеством первого и наиболее широко используется.

ApplicationContext - это интерфейс в пакете org.springframework.context , он имеет несколько реализаций, и ClassPathXmlApplicationContext является одним из них.

В этой статье мы сосредоточимся на полезных функциях, предоставляемых ClassPathXmlApplicationContext .

2. Основное использование

2.1. Инициализация контейнера и управление компонентами

ClassPathXmlApplicationContext может загрузить конфигурацию XML из пути к классам и управлять его bean-компонентами:

У нас есть класс Student :

public class Student {
    private int no;
    private String name;

   //standard constructors, getters and setters
}

Мы настраиваем bean-компонент Student в classpathxmlapplicationcontext-example.xml и добавляем его в путь к классам:

<beans ...>
    <bean id="student" class="com.baeldung.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 в веб-приложении, веб-реализации ApplicationContext в Spring будут корректно завершать работу контейнера при завершении работы приложения, но если мы используем его в не-веб-среде, например в автономном настольном приложении, Мы должны самостоятельно зарегистрировать перехватчик в JVM, чтобы убедиться, что контейнер Spring IoC корректно завершил работу и вызывает методы destroy для освобождения ресурсов.

Давайте добавим метод destroy () в класс Student :

public void destroy() {
    System.out.println("Student(no: " + no + ") is destroyed");
}

Теперь мы можем настроить этот метод как метод уничтожения бина student :

<beans ...>
    <bean id="student" class="com.baeldung.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 в путь к классам и добавим два файла в каталог диалогов: 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 :

У нас есть класс Course с именем:

public class Course {

    private String name;

   //standard constructors, getters and setters
}

У нас есть класс Teacher , который собирает свои курсы согласно бинам контейнера:

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-компонент course и bean-компонент teacher в classpathxmlapplicationcontext-example.xml :

<beans ...>
    <bean id="math" class="com.baeldung.applicationcontext.Course">
        <property name="name" value="math"/>
    </bean>

    <bean name="teacher" class="com.baeldung.applicationcontext.Teacher"/>
</beans>

Затем - протестируйте внедрение свойства courses :

@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 имеет тот же эффект.

Давайте изменим класс Teacher на этот:

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 https://github.com/eugenp/tutorials/tree/master/spring-core/src/test/java/com/baeldung/applicationcontext/ [over на GitHub.