Анализ контейнеров Spring IOC

Java задняя часть Spring контейнер

Оригинальный адрес блога:блог Пимайка

предисловие

в предыдущих статьяхАнализ Spring IoC и DIОсновные концепции и взаимосвязи IOC и DI кратко описаны в разделе В общем, IOC — это метод привязки объектов, который может помочь нам разделить зависимости между бизнес-объектами Spring предоставляет два типа контейнеров для поддержки IOC Way. Два типа:

  • BeanFactory: базовый тип контейнера IOC, обеспечивающий полную поддержку службы IOC.
  • ApplicationContext: ApplicationContext построен на основе BeanFactory и представляет собой относительно продвинутую реализацию контейнера.Помимо всей поддержки BeanFactory, ApplicationContext предоставляет другие расширенные функции.

Отношения наследования между ApplicationContext и BeanFactory следующие:

applicationContext

Вы можете видеть, что ApplicationContext косвенно наследуется от BeanFactory.

BeanFactory

Введение в BeanFactory

BeanFactory — это контейнер IoC базового типа, обеспечивающий полную поддержку службы IoC. Если не указано, по умолчаниюСтратегия ленивой инициализации (ленивая загрузка).Только когда клиентскому объекту требуется доступ к управляемому объекту в контейнере, управляемый объект инициализируется и выполняется работа по внедрению зависимостей..

Регистрация объекта BeanFactory

BeanFactory — это фабрика, которая производит Java Bean.Как базовый контейнер IoC, предоставляемый Spring, BeanFactory помогает завершитьРегистрация бизнес-объектов и привязка зависимостей между объектами.

На самом деле BeanFactory — это просто интерфейс,Он отвечает за определение того, как получить доступ к bean-компонентам, управляемым в контейнере, а конкретный класс реализации каждой BeanFactory отвечает за регистрацию и управление конкретными bean-компонентами.. Ниже приведен код интерфейса BeanFactory:

package org.springframework.beans.factory;

public interface BeanFactory {

    /**
     * 用来引用一个实例,或把它和工厂产生的Bean区分开,就是说,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory
     */
    String FACTORY_BEAN_PREFIX = "&";

    /*
     * 四个不同形式的getBean方法,获取实例
     */
    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    boolean containsBean(String name); // bean是否存在

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 是否为单实例

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 是否为原型(多实例)

    boolean isTypeMatch(String name, Class<?> targetType)
            throws NoSuchBeanDefinitionException;// 名称、类型是否匹配

    Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 获取类型

    String[] getAliases(String name);// 根据实例的名字获取实例的别名

}

Давайте протестируем конкретный класс реализации интерфейса BeanFactory в целом:


// 实体类
@Component
public class Demo {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

//Junit测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
    @Autowired
    private BeanFactory beanFactory;
    @Test
    public void test() {
        System.out.println("concrete factory is: " + beanFactory.getClass());
        Assert.assertTrue("Factory can't be null",beanFactory != null);
        Demo demo = (Demo) beanFactory.getBean("demo");
        System.out.println("Found the demo bean: "+demo.getClass());
    }

}

Результат выглядит следующим образом:

concrete factory is: class org.springframework.beans.factory.support.DefaultListableBeanFactory
Found the demo bean: class com.pjmike.spring.Demo

Из результатов видно, что конкретная фабрикаorg.springframework.beans.factory.support.DefaultListableBeanFactoryпример. посмотри сноваBeanFactoryНаследование отражает:

BeanFactory

Как видно из рисунка, BeanFactory управляет тремя подклассами:

  • ListableBeanFactory: наследуя этот интерфейс, можно перечислить все bean-компоненты или только bean-компоненты, соответствующие ожидаемому типу.
  • HierarchicalBeanFactory: поддерживает управление иерархическими bean-компонентами, позволяя BeanFactory поддерживать функцию управления родительским контейнером IOC.
  • AutowireCapableBeanFactory: может заполнять bean-компоненты, не контролируемые Spring

Система подклассов из трех классов - это больше, пожалуйста, обратитесь к исходному коду Spring для получения подробной информации.

Давайте посмотрим на ранее упомянутоеDefaultListableBeanFactory, который также является классом реализации самого низкого уровня на приведенном выше рисунке:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
		...
}

Этот класс на самом делеBeanFactoryКласс реализации по умолчанию более общего класса реализации BeanFactory, который не только косвенно реализует интерфейс BeanFactory, но также реализуетBeanDefinitionRegistryинтерфейс,Этот интерфейс является ролью управления регистрацией Bean в реализации BeanFactory., который абстрактно определяет логику регистрации Bean Конечно, конкретная реализация должна полагаться наDefaultListableBeanFactoryЭто класс реализации.

ApplicationContext

Введение в ApplicationContext

ApplicationContext построен на основе BeanFactory.Да, это относительно продвинутая реализация контейнера.Помимо всей поддержки BeanFactory, ApplicationContext также предоставляет другие расширенные функции, такие как:

  • Единая политика загрузки ресурсов
  • Международная информационная поддержка
  • Механизм публикации внутренних событий контейнера

После запуска контейнера ApplicationContext вся инициализация и привязка завершаются по умолчанию., поэтому для BeanFactory ApplicationContext часто требует больше системных ресурсов

Реализация ApplicationContext

Контекст весной

Spring предоставляет реализацию XmlBeanFactory (унаследованную от DefaultListableBeanFactory) для базового контейнера типа BeanFactory, а также следующие общие реализации для контейнера типа ApplicationContext:

  • org.springframework.context.support.FileSystemXmlApplicationContext: Реализации ApplicationContext, которые по умолчанию загружают определения bean-компонентов и связанные ресурсы из файловой системы.
  • org.springframework.context.support.ClassPathXmlApplicationContext: по умолчанию реализация ApplicationContext определений компонентов и связанных ресурсов загружается из пути к классам.
  • org.springframework.web.context.support.XmlWebApplicationContext: Предоставленная Spring реализация ApplicationContext для веб-приложений.

В традиционных проектах Spring на основе XML часто используются вышеуказанные классы реализации.

Контекст в Spring Boot

В официальной документации приведена ситуация соответствующего контекста для приложения SpringBoot:

context

  • Для веб-приложений контекстAnnotationConfigServletWebServerApplicationContext
  • Для адаптивных приложений контекстAnnotationConfigReactiveWebServerApplicationContext
  • Для обычных не веб-приложений контекстAnnotationConfigApplicationContext

НадcontextНа самом деле понялApplicationContextинтерфейс

Простая практика с ApplicationContext

Все мы знаем, что контейнеры IOC обычно имеют два метода внедрения объектов: на основе файла конфигурации XML и на основе аннотаций. Давайте посмотрим, как использовать ApplicationContext с этих двух точек зрения.

Файл конфигурации на основе XML

  1. определить класс сущности
public class User {
    private Integer id;

    private String username;

    public User(Integer id, String username) {
        this.id = id;
        this.username = username;
    }

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}
  1. Настройте файл конфигурации XML, который объявляет пользовательский компонент
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.pjmike.spring.domain.User">
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="username" value="pjmike"/>
    </bean>
</beans>
  1. основная программа
public class XmlBootStrap {
    public static void main(String[] args) {
        //构建一个 ApplicationContext 上下文
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
        //设置此应用上下文的配置路径
        context.setConfigLocations("classpath:/META-INF/spring/context.xml");
        //调用 refresh 方法,完成配置的解析、各种BeanFactoryPostProcessor和BeanPostProcessor的注册、国际化配置的初始化、web内置容器的构造
        context.refresh();
        User user = context.getBean("user", User.class);
        System.out.print("user.getName() = "+ user.getUsername());
    }
}

выходной результат

user.getName() = pjmike

на основе аннотаций

  1. объявить класс конфигурации
@Configuration
public class UserConfiguration {
    @Bean(name = "user")
    public User user() {
        User user = new User();
        user.setUsername("pj");
        return user;
    }
}
  1. основная программа
public class AnnotationBootStrap {
    public static void main(String[] args) {
        // 构建一个 ApplicationContext 应用上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册一个配置 Bean
        context.register(UserConfiguration.class);
        // 调用 refresh 启动容器
        context.refresh();
        User user = context.getBean("user", User.class);
        System.out.println("user.getName() = "+user.getUsername());
    }
}

выходной результат

user.getName() = pj

Простое сравнение XML и Annotation

Из приведенных выше двух примеров видно, что способ внедрения bean-компонентов на основе XML и аннотаций отличается.ClassPathXmlApplicationContextПуть конфигурации должен быть установлен в зависимости от контекста приложения аннотации.AnnotationConfigApplicationContextКонфигурационный компонент должен быть зарегистрирован, но тот же шаг для них заключается в том, что они должны быть вызваныrefresh()метод, этот метод можно рассматривать как метод запуска контейнера IOC, он будет выполнять множество операций, таких как завершение анализа конфигурации, регистрация различных BeanFactoryPostProcessors и BeanPostProcessors, инициализация конфигурации интернационализации, построение веб-встроенного контейнера и т. д., не вызывайте его, контейнер не может запуститься. Это лишь краткое описание, а более подробное введение будет представлено в следующей статье.

Сейчас популярен этап springboot, способ, основанный на файлах конфигурации XML, постепенно заменяется способом, основанным на аннотациях, в современных проектах больше способов использования аннотаций. Более подробное сравнение XML и аннотаций см. в статье Kaitao:Этот год — год Дракона. ITeye.com/blog/187991…

резюме

Вышеприведенная статья кратко суммирует BeanFactory и ApplicationContext, закладывая основу для последующего анализа подробного процесса инициализации Spring IOC и загрузки Spring Beans.

Ссылки и благодарности