Просто хочу, чтобы вы поняли Spring-IOC

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

Зачем вводить МОК?

class Programer {
    Computer computer = new Mac2015();
    private void work() {
        computer.help();
    }
}

В настоящее время существует проблема, связанная с тем, что компьютер и программатор связаны друг с другом. Программатор не масштабируется (использует только Mac2015). Если компания в это время меняет партию компьютеров на Mac2016, ей необходимо воссоздать класс программиста.Очевидно неразумно.
从设计的角度来讲,类本身就是定义的一个模板亦或是一种抽象,如果抽象和具体的实现绑定或者耦合在一起,那么就不是纯粹的抽象了。Это также нарушает правило шаблонов проектирования «не звони мне». Итак, в это время компьютер и программист должны быть отделены друг от друга, метод разделения очень прост. Конкретная реализация компьютера допустима, если вызывающая сторона указывает ее, а не указывает ее в самом классе. Затем классу необходимо открыть некоторые интерфейсы для внешнего мира, чтобы реализовать функцию внедрения.
Есть три распространенных метода

  • Внедрение конструктора
  • установка впрыска
  • интерфейсная инъекция

Это основная идея IOC, а для нашей веб-разработки коллера вообще нет (фактически есть только на уровне контейнера), поэтому как обеспечить динамическую инъекцию атрибутов в классе, это будет представлен весной
Далее, как выбрать, какой метод внедрения и какие свойства необходимо внедрить, будут уведомлены Spring? Есть два распространенных метода

  • аннотация
  • Файл конфигурации (xml/свойства)

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

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>

class指向的是包含工厂方法的类,并非工厂方法返回的类Ниже приведен способ инъекции через обычную фабрику.

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

Классификация контейнеров МОК

  • BeanFactory

    Отложенная загрузка по умолчанию, поэтому начинайте быстрее Обычно используется класс реализации DefaultListableBeanFactory, который также реализует интерфейс BeanDefinitionRegistry, играющий роль регистра управления регистрацией Bean-компонентов registerBeanDefinition#BeanDefinitionRegistry. Компонент будет зарегистрирован в BeanDefinitionRegistry в форме beanDefinition. В интерфейсе BeanFactory определены только некоторые методы запроса о bean-компонентах, а для реальной работы требуются другие определения интерфейса, реализованные его подклассами~

  • ApplicationContext

    Построен на базе BeanFactory, не ленив и долго запускается, помимо основных функций BeanFactory предоставляет и некоторые дополнительные функции (публикация событий, международная информационная поддержка и т.д.)

Ручной и автоматический

  • Внедрение на основе профиля, которое мы называем ручным

    <bean> <name="propertyName" ref="otherBean">

  • Внедрение на основе аннотаций мы называем полностью автоматическим

    @Conponet/@Autowire/@Resource + <componet-scan>

  • Также есть полуавтоматическая аннотация + настройка

    <bean> + @autowire/@resource

О бинах в xml

Как правило, верхний уровень — это тег bean-компонентов, который имеет несколько уникальных свойств, действительных для всех содержащихся в нем bean-компонентов.

  • default-lazy-init

    Все ли bean-компоненты лениво загружены

  • default-autowire

    Все bean-компоненты вводятся внутри с помощью no (по умолчанию)/byName/byType/constrctor/autodetect
    Здесь byName/byType ≈ @resource/@autowire

  • default-dependency-check

    Делать ли проверку зависимостей нет (по умолчанию)

  • default-init-method

    Все методы инициализации компонента, такие как init

  • default-destroy-method

    Уничтожить методы всех bean-компонентов, такие как destroy

По сути, все свойства bean-компонентов могут быть сопоставлены с bean-компонентами, вот свойство области видимости bean-компонентов. О синглтоне и прототипе Бобы типа singleton живут до тех пор, пока контейнер Жизненный цикл bean-компонента типа прототипа не поддерживается контейнером, контейнер больше не имеет ссылки на текущий объект, и он предоставлен самому себе.

Подумайте о проблеме, которая была решена в начале, удерживая ссылку на объект (new/reflect), но объект не был внедрен, как использовать Spring для его внедрения?

     applicationContext.getAutowireCapableBeanFactory().
     autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_NO, true);

Жизненный цикл фасоли

Сначала поставьте заключение, а затем демонстрацию конкретного кода (лучше сочетать изображения и тексты).

Практика — единственный критерий проверки истины, например

public class Car implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {
    private String carName;
    private BeanFactory beanFactory;
    private String beanName;

    public Car() {
        System.out.println("bean的构造函数");
    }

    public void setCarName(String carName) {
        System.out.println("属性注入");
        this.carName = carName;
    }

    // 这是BeanFactoryAware接口方法
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("BeanFactoryAware.setBeanFactory()");
        this.beanFactory = arg0;
    }

    // 这是BeanNameAware接口方法
    public void setBeanName(String arg0) {
        System.out.println("BeanNameAware.setBeanName()");
        this.beanName = arg0;
    }

    // 这是InitializingBean接口方法
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("InitializingBean.afterPropertiesSet()");
    }

    // 这是DiposibleBean接口方法
    public void destroy() throws Exception {
        System.out.println("DiposibleBean.destory()");
    }

    // 通过<bean>的init-method属性指定的初始化方法
    public void myInit() {
        System.out.println("<bean>的init-method属性指定的初始化方法");
    }

    // 通过<bean>的destroy-method属性指定的初始化方法
    public void myDestory() {
        System.out.println("<bean>的destroy-method属性指定的初始化方法");
    }
}
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("BeanPostProcessor构造函数");
    }

    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {
        if (arg1.equals("car")) {
            System.out
                    .println("BeanPostProcessor.postProcessAfterInitialization()");
        }
        return arg0;
    }

    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {
        if (arg1.equals("car")) {
            System.out
                    .println("BeanPostProcessor.postProcessBeforeInitialization()");
        }
        return arg0;
    }
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("BeanFactoryPostProcessor构造函数");
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out.println("BeanFactoryPostProcessor.postProcessBeanFactory()");
        System.out.println("我现在可以修改beanDefination但是我这里就不修改了");
    }
}
public class MyInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {

    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out
                .println("InstantiationAwareBeanPostProcessorAdapter构造函数");
    }

    // 接口方法、实例化Bean之前调用
    @Override
    public Object postProcessBeforeInstantiation(Class beanClass,
                                                 String beanName) throws BeansException {
        if(beanName.equals("car")) {
            System.out
                    .println("InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()");
        }
        return null;
    }

    // 接口方法、实例化Bean之后调用
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if(beanName.equals("car")) {
            System.out
                    .println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()");
        }
        return true;
    }
    
    // 接口方法、设置某个属性时调用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {
        if(beanName.equals("car")) {
            System.out
                    .println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues()");
        }
        return pvs;
    }
}
<bean id="beanPostProcessor" class="test.MyBeanPostProcessor"/>
<bean id="instantiationAwareBeanPostProcessor" class="test.MyInstantiationAwareBeanPostProcessor"/>
<bean id="beanFactoryPostProcessor" class="test.MyBeanFactoryPostProcessor"/>
<bean id="car" class="test.Car" init-method="myInit"
destroy-method="myDestory" scope="singleton" p:carName="BMW"/>

Давайте станем свидетелями всего процесса

public static void main(String[] args) {
        System.out.println("开始启动容器");
        ApplicationContext factory = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
        System.out.println("容器初始化成功");
        Car car = factory.getBean("car",Car.class);
        System.out.println("开始关闭容器");
        ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
    }

Окончательный вывод консоли:

开始启动容器
BeanFactoryPostProcessor构造函数
BeanFactoryPostProcessor.postProcessBeanFactory()
我现在可以修改beanDefination但是我这里就不修改了
InstantiationAwareBeanPostProcessorAdapter构造函数
BeanPostProcessor构造函数
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
bean的构造函数
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
InstantiationAwareBeanPostProcessor.postProcessPropertyValues()
属性注入
BeanNameAware.setBeanName()
BeanFactoryAware.setBeanFactory()
BeanPostProcessor.postProcessBeforeInitialization()
InitializingBean.afterPropertiesSet()
<bean>的init-method属性指定的初始化方法
BeanPostProcessor.postProcessAfterInitialization()
容器初始化成功
开始关闭容器
DiposibleBean.destory()
<bean>的destroy-method属性指定的初始化方法

1) Этап запуска контейнера
Контейнер должен полагаться на некоторые классы инструментов (BeanDefinitionReader) для синтаксического анализа и анализа загруженных метаданных конфигурации, маршалирования проанализированной информации в соответствующее BeanDefinition и, наконец, для регистрации этих BeanDefinitions, которые сохраняют необходимую информацию для определений компонентов в соответствующем BeanDefinitionRegistry. работа по запуску контейнера.
BeanDefinitionReader
1) Используется для работы с конфигурационными файлами
2) Отвечает за чтение содержимого из соответствующего файла конфигурации и сопоставление bean-компонентов с BeanDefinition.
3) Затем зарегистрируйте BeanDefinition в BeanDefinitionRegistry.
например: PropertiesBeanDefinitionReader, XmlBeanDefinitionReader

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanDefinitionRegistry);
reader.loadBeanDefinitions("classpath:xxx");
return (BeanFactory) beanDefinitionRegistry;

Единственный большой парень, который может вмешаться в стадию запуска контейнера-----BeanFactoryPostProcessorИзмените информацию BeanDefinition, зарегистрированную в контейнере, до того, как контейнер создаст экземпляр объекта.
Ниже приведены еще несколько типичных BeanFactoryPostProcessor.

  • PropertyPlaceholderConfigurer

Замените заполнители в конфигурации bean-компонента фактическими значениями перед созданием экземпляра bean-компонента.

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean>

<bean id="dataSource" destroy-method="close"
        class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>
# jdbc.properties
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

Во время выполнения содержимое заполнителя будет заменено соответствующим значением в файле свойств.Эту работу выполняет PlaceholderConfiguer.Нетрудно заметить, что этот класс должен реализовывать BeanFactoryPostProcessor.

  • CustomEditorConfigurer

То есть то, что контейнер считывает из XML-файла, находится в виде строк, но конечное приложение состоит из различных типов объектов. Для завершения преобразования строк в конкретные объекты (независимо от того, кто в итоге выполняет преобразование) требуется информация о правилах преобразования, и CustomEditorConfigurer помогает нам передать подобную информацию.
Нам нужно преобразовать 2018/07/27 типа String в дату следующим образом

<bean id="dateFoo" class="...DateFoo">
    <property name="date">
        <value>2018/07/27</value>
    </property>
</bean>

Пользователи могут настроить CustomEditorConfigurer для указания преобразования строки в конкретный тип в логику.

  • Пример практического применения BeanFactoryPostProcessor

В предыдущем проекте JUNIT использовался для модульного тестирования, но каждый модульный тест должен был загружать все bean-компоненты.Если масштаб проекта был большим, запуск модульного теста занимал много времени.Чтобы решить эту проблему, простой Был разработан BeanFactoryPostProcessor, принцип очень прост, он заключается в том, чтобы перевести все бины в режим ленивой загрузки, экземпляр какого из них создается в юнит-тесте

public class LazyBeanFactoryProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        DefaultListableBeanFactory fac = (DefaultListableBeanFactory) beanFactory;
        Map<String, AbstractBeanDefinition> map = (Map<String, AbstractBeanDefinition>) ReflectionTestUtils.getField(fac, "beanDefinitionMap");
        for (Map.Entry<String, AbstractBeanDefinition> entry : map.entrySet()) {
            entry.getValue().setLazyInit(true);
        }
    }
}

2) Этап создания экземпляра компонента1.InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class beanClass,String beanName)Перед выполнением конструктора бобов, поэтому, если есть инстанциониальныйawareBeanPostProcessor, сначала выполнит свое постпроцессфуинтэнстанция (), чтобы вернуться в это время, если боба не нулея, мы не будем продолжать выполнять последующие процессы Bean, выполняющие только постпроцессафициализацию (), что приведет к «короткое замыкание» Одно следует отметить, ссылаясь на метод InstantiationAwareBeanPostProcessor лучшее время, чтобы указать параметры, потому что он имеет несколько параметров в то же имя по-разному, подверженным путанице

2.对bean进行实例化Контейнер использует шаблон стратегии, чтобы решить, как инициализировать экземпляр компонента (отражение или CGLIB по умолчанию). Если сконфигурированный bean-компонент имеет поиск или замену, вам необходимо использовать CGLIB для создания прокси-класса.

3.InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Class beanClass,String beanName)

4.InstantiationAwareBeanPostProcessor.postProcessPropertiesValues(PropertyValues pvs,PropertyDescriptor[] pds, Object bean, String beanName)

5.对bean进行依赖注入Экземпляр продукта представляет собой экземпляр BeanWrapper, который является пакетом для компонента, а затем устанавливает значение свойства для этого пакета. Ps С помощью Wrapper свойства объекта можно внедрять унифицированным способом, а BeanWrapper будет использовать PropertyEditor для преобразования типов свойств

6.检查是否实现Aware接口(BeanFactory独有)BeanNameAware: установите BeanName для текущего экземпляра BeanClassLoaderAware: установите ClassLoader, который загружает текущий компонент в текущий экземпляр. BeanFactoryAware: установите BeanFactory на текущий экземпляр

7.BeanPostProcessor.postProcessBeforeInitializationМногие интерфейсы Aware, уникальные для ApplicationContext, также внедряются через BeanPostPorcessor.

public Object postProcessBeforeInitialization(Object bean, String beanName) throws  BeansException {
 if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher 
(this.applicationContext); }
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
   ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }
    return bean;
}

8.InititalizingBean.afterPropertiesSet()

9.init-method

10.BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)

11.容器初始化成功,正常执行业务逻辑

12.DisposableBean.destroy()

13.destroy-method

круговая зависимость

Spring обрабатывает циклические зависимости между одноэлементными bean-компонентами (внедрение набора), другими словами, singleton-внедрение конструктора и bean-компоненты типа прототипа не могут обрабатывать циклические зависимости. Предполагая, что A зависит от B, а B зависит от A, при инстанцировании A полуфабрикат A будет помещен в кеш, а затем будет инстанцирован зависимый B, и в процессе инстанцирования B A необходимо В это время полуфабрикат A непосредственно загружается в B, и создание экземпляра циклического зависимого компонента завершено.

О BeanPostProcessor

  • BeanPostProcessor обрабатывает все подходящие BeanDefinitions в контейнере.
    Ps Соблюдаются условия или нет судите сами в переопределенном методе if(beanName==xxx)
  • A bean post-processor typically checks for callback interfaces or may wrap a bean with a proxy. Some Spring AOP infrastructure classes are implemented as bean post-processors in order to provide proxy-wrapping logic.
    АОП реализует кражу и замену столбцов через BeanPostProcessor.
  • Classes that implement the BeanPostProcessor interface are special and are treated differently by the container. All BeanPostProcessors and beans that they reference directly are instantiated on startup, as part of the special startup phase of the ApplicationContext
    Бин, который реализует этот интерфейс, очень особенный.Он и бины, от которых он зависит, должны быть запущены первыми.Это можно рассматривать как этап запуска контейнера. И бины (или зависимые бины), которые реализуют этот интерфейс, не могут его динамически проксировать, т.к. сам динамический прокси реализован через BeanPostProcessor, можно понять как "Геркулес не может поднять себя"