Заметки об основной идее Spring

Spring

В этой статье обобщаются соответствующие знания о Spring, включая преимущества Spring, структуру его фреймворка и основные идеи, а также вручную реализуются идеи IoC и AOP для улучшения понимания основных идей Spring. После этого вводятся методы реализации и характеристики Spring IoC и АОП, а идеи их реализации понимаются в сравнении с исходным кодом.

  • Источник вывода содержания статьи: Lagou Education Java High-paying Training Camp;

Весеннее преимущество

  • Легкая развязка и упрощенная разработка

    [Примечание: IOC (уменьшить связанность компонентов), DI (уменьшить сложность замены бизнес-объектов)]

  • Идея АОП-программирования

    [Примечание: общие задачи управляются централизованно, что упрощает повторное использование кода]

  • Декларативная поддержка транзакций

    [Примечание: @Транзакция]

  • Легкий фреймворк, минимальное вмешательство в код, свободный выбор некоторых компонентов фреймворка

  • Легко интегрировать различные отличные фреймворки

Структура весной ядра

  • Контейнер для вестового сердечника (Core Container): контейнер - это основная часть пружинного каркаса, созданная бобов управления (IOC), конфигурация (DI) и управление (контекст), все пружинные модули построены сверху контейнера.
  • Аспектно-ориентированное программирование (АОП): основа для разработки аспектов в системе приложений Spring, разделения кода и расширенного повторного использования.
  • Доступ к данным и интеграция. Модули Spring JDBC и DAO инкапсулируют большой объем шаблонного кода, делая код базы данных кратким и избегая проблем, вызванных сбоями выпуска ресурсов базы данных. Он состоит из таких модулей, как JDBC, Transactions (поддержка модуля AOP), ORM, OXM и JMS.
  • Интернет: предоставляет платформу SpringMVC для веб-приложений, а также предоставляет множество схем удаленного вызова для создания и взаимодействия с другими приложениями. Платформа SpringMVC улучшает уровень слабой связи приложений на веб-уровне.
  • Тест Чтобы облегчить разработчикам тестирование, Spring предоставляет тестовый модуль для тестирования приложений Spring. С помощью этого модуля Spring предоставляет ряд реализаций фиктивных объектов для написания модульных тестов с использованием Servlet, JNDI и т. д.

смысл

IoC (Инверсия управления) Инверсия управления

IoC — это техническая идея, и Spring ее реализует.

Инверсия управления: право на создание объекта (создание экземпляра, управление) передается внешней среде (инфраструктура Spring, контейнер IoC)

Решить проблему: решить проблему связи между объектами

Разница между IoC и DI

DI (внедрение зависимостей) внедрение зависимостей

IoC и DI описывают одно и то же (создание объекта и обслуживание зависимостей), но с другой точки зрения.

IoC: с точки зрения объектов создание объектов и управление ими передаются контейнеру.

DI: с точки зрения контейнера, контейнер будет внедрять другие объекты, от которых зависит объект.

АОП (аспектно-ориентированное программирование) Аспектно-ориентированное программирование

ООП против АОП

ООП — это система вертикального наследования (три характеристики: инкапсуляция, наследование и полиморфизм).

Чтобы решить проблему вертикального повторения, АОП извлекает код горизонтальной логики, разделяет бизнес-логику и сквозную логику и разделяет

АОП решает проблемы

Решите вертикальные проблемы дублирования, извлечь горизонтальный логический код, отдельная бизнес-логика и перекрестная логика, а также отделение

Ручная реализация IoC и AOP

IoC и внедрение внедрения зависимостей

  1. Определите файл beans.xml, который определяет:
    • Идентификатор и полное имя класса создаваемого объекта ⇒ Reflection создает объект, id — это идентификатор.
    • Имя свойства и идентификатор зависимого объекта ⇒ внедрить свойства зависимостей через метод Set в соответствующем классе
  2. Определение BeanFactory, чтение и синтаксический анализ xml, создание экземпляров объектов посредством отражения, единообразное управление ими и предоставление методов интерфейса для внешнего получения объектов.

Управление транзакциями АОП

  1. Привяжите соединение к текущему потоку и вручную управляйте транзакцией соединения JDBC (отключите транзакцию автоматической фиксации)
  2. Создайте класс прокси-фабрики и выполните расширение транзакций в классе прокси.
  3. Используйте объект прокси-класса вместо объекта, чтобы вызвать метод

Приложение Spring IoC

Реализация IoC и соответствующий метод запуска

  1. Чистая реализация xml (определения информации о bean-компонентах все настроены в xml)

    // JavaSE 应用启动
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    // 或者读取绝对路径下的配置文件(不推荐)
    ApplicationContext applicationContext = new FileSystemXmlApplicationContext("c:/beans.xml");
    
    // JavaWeb 应用
    /**
    	配置 ContextLoaderListener 类(web.xml)
    	监听器机制加载 xml
    */
    
    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
        <display-name>Archetype Created Web Application</display-name>
        <!--配置Spring ioc容器的配置⽂件-->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
        <!--使⽤监听器启动Spring的IOC容器-->
        <listener>
            <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
        </listener>
    </web-app>
    
  2. xml + аннотации (некоторые bean-компоненты определяются с помощью xml, а некоторые bean-компоненты определяются с помощью аннотаций)

    В соответствии с чистой реализацией xml

  3. Чистые аннотации (все bean-компоненты определяются с помощью аннотаций)

    // JavaSE 应用启动
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring.class);
    
    // JavaWeb 应用
    /**
    	配置 ContextLoaderListener 类(web.xml)
    	监听器机制加载 注解配置类
    */
    
    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
        <display-name>Archetype Created Web Application</display-name>
        <!--告诉ContextloaderListener知道我们使⽤注解的⽅式启动ioc容器-->
        <context-param>
            <param-name>contextClass</param-name>
            <paramvalue>org.springframework.web.context.support.AnnotationConfigWebAppli cationContext</param-value>
        </context-param>
        <!--配置启动类的全限定类名-->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.lagou.edu.SpringConfig</param-value>
        </context-param>
        <!--使⽤监听器启动Spring的IOC容器-->
        <listener>
            <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
        </listener>
    </web-app>
    

Разница между BeanFactory и ApplicationContext

BeanFactory — это интерфейс верхнего уровня контейнера IoC в среде Spring, который используется только для определения некоторых основных функций и базовых спецификаций, а ApplicationContext является его подинтерфейсом, поэтому ApplicationContext имеет все функции, предоставляемые BeanFactory.

ApplicationContext — высокоуровневый интерфейс контейнера, по сравнению с BeanFactory имеет больше функций, таких как поддержка интернационализации и доступ к ресурсам (xml, класс конфигурации java) и т. д.

Три способа создания экземпляров bean-компонентов

  1. Использовать конструктор без аргументов

    <!--配置service对象-->
    <bean id="userService" class="com.lagou.service.impl.TransferServiceImpl">
    </bean>
    
  2. Создать статическим методом

    <!--使⽤静态⽅法创建对象的配置⽅式-->
    <bean id="userService" class="com.lagou.factory.BeanFactory" factory-method="getTransferService"></bean>
    
  3. Создать с помощью метода инстанцирования

    <!--使⽤实例⽅法创建对象的配置⽅式-->
    <bean id="beanFactory" class="com.lagou.factory.instancemethod.BeanFactory"></bean>
    <bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean>
    

Объем и жизненный цикл компонента

  • singleton (одиночный шаблон)

    Жизненный цикл объекта bean шаблона singleton такой же, как у контейнера.

  • прототип (режим нескольких экземпляров)

    Объект bean многоэкземплярного режима, среда Spring отвечает только за создание, а не за уничтожение

Свойства тегов компонентов в схеме Xml

  • id: уникальный идентификатор бина
  • class: полное имя класса созданного объекта bean-компонента.
  • name: Укажите одно или несколько имен для bean-компонента.
  • factory-bean: указывает уникальный идентификатор фабричного компонента, который создал текущий объект компонента (если этот атрибут указан, атрибут класса недействителен)
  • factory-method: указывает фабричный метод для создания текущего объекта.
    • Примечание: Если вы используете фабричный компонент, свойство Class недействительно.Если вы используете свойство Class, метод должен быть изменен статически.
  • Область действия: домен действия Bean, по умолчанию Singleton
  • init-method: определяет метод инициализации объекта bean-компонента, который вызывается после сборки bean-компонента и должен быть методом без аргументов.
  • destroy-method: указывает метод уничтожения объекта bean-компонента, который выполняется до того, как bean-компонент будет уничтожен, и работает только в том случае, когда область действия является одноэлементной (поскольку инфраструктура Spring отвечает только за создание в режиме с несколькими экземплярами).

xml для внедрения зависимостей DI

  • Классификация внедрения зависимостей

    • Классификация по способу введения

      1. Конструктор инъекции
        • Примечание. При отсутствии построения без параметров необходимо указать параметры конфигурации, соответствующие количеству и типу данных параметров построения.
        • Используйте тег для присвоения значений конструкторам со следующими атрибутами:
          • имя: соответствующее имя параметра
          • index: соответствует индексу, указанному в конструкторе
          • значение: Укажите базовый тип или данные типа String.
          • ref: указывает данные других типов bean-компонентов, значением является идентификатор bean-компонента.
      2. Установите метод впрыска
        • Используйте тег для соответствия установленному методу, а свойства тега следующие:
          • name: Имя метода set, вызываемого при вставке, удаляет суффикс после set
          • значение: Укажите базовый тип или данные типа String.
          • ref: указывает данные других типов bean-компонентов, значением является идентификатор bean-компонента.
    • Классифицируется по введенному типу данных

      1. Основной тип, Строка

      2. Сложные типы [массив, список, набор, карта, свойства]

        Пример (Возьмите метод SET в качестве примера, вводится конструктор):

        <!-- Array -->
        <property name="myArray">
        	<array>
                <value>array1</value>
                <value>array2</value>
            </array>
        </property>
        
        <!-- List -->
        <property name="myArray">
        	<list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        
        <!-- Set -->
        <property name="mySet">
        	<set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
        
        <!-- Map -->
        <property name="myMap">
        	<map>
                <entry key="key1" value="value1"/>
                <entry key="key2" value="value2"/>
            </map>
        </property>
        
        <!-- Properties -->
        <property name="myProperties">
        	<map>
                <prop key="key1" value="value1"/>
                <prop key="key2" value="value2"/>
            </map>
        </property>
        

        Когда вводятся данные коллекции структуры List, три тега массива, списка и набора являются общими.Кроме того, тег значения аннотации может напрямую записывать значение или использовать тег bean-компонента для настройки объекта или использовать тег ref для ссылки на него.Используйте уникальный идентификатор сопряженного компонента. При внедрении данных коллекции структуры карты тег карты использует вложенный тег записи для внедрения данных, а тег записи может использовать атрибуты ключа и значения для указания данных, хранящихся в карте. Используйте атрибут value-ref, чтобы указать ссылку на уже настроенный bean-компонент. В то же время тег ref также можно использовать в теге entry, но нельзя использовать тег bean. И теги свойств не могут использовать теги ref или bean для ссылки на объекты.

      3. Другие типы бобов

Соответствие между аннотациями и тегами xml

В комбинированном режиме xml и аннотаций bean-компоненты в сторонней банке обычно определяются в xml, а определения bean-компонентов, разработанные сами по себе, используют аннотации.

  1. Конфигурация

    • Аннотация @Configuration, соответствующая файлу beans.xml
    • Аннотация @ComponentScan вместо
    • @PropertySource, импортировать файлы конфигурации внешних свойств
    • @Import представляет другие классы конфигурации
    • @Value присваивает значение переменной, вы можете присвоить его напрямую или использовать ${} для чтения информации в файле конфигурации ресурса.
    • @Bean добавляет объект возврата метода в контейнер SpringIoC
  2. IoC

    XML-форма Соответствующая форма аннотации
    тег @Component("accountDao"), аннотация добавляется в класс. Содержимое атрибута id бина настраивается непосредственно после аннотации. Если он не настроен, id бина определяется по умолчанию как класс имя класса.Первая буква строчная;
    Кроме того, для многоуровневой разработки кода предоставляются три псевдонима @Componenet, @Controller, @Service и @Repository, которые используются для определений bean-компонентов уровня управления, уровня обслуживания и уровня dao соответственно. совершенно то же самое. только для более четкого различия
    свойство области действия @Scope("prototype"), синглтон по умолчанию, аннотация добавляется в класс
    атрибут init-method тега @PostConstruct, аннотация добавляется к методу, который вызывается после инициализации
    свойство сюжетного метода @PreDestory, аннотация добавляется к методу, который вызывается перед уничтожением
  3. DI

    • @Autowired
      • Внедрение по типу, если есть несколько значений bean-компонента, используйте @Qualifier(name="")
    • @Resource
      • Предоставленный J2EE, @Resource был удален в Jdk 11, используйте пакет импорта javax.annotation.Resource
      • Правила инъекции:
        • Если указаны и имя, и тип, уникальный соответствующий bean-компонент будет найден из контекста Spring для сборки, и если он не будет найден, будет выдано исключение.
        • Если указано имя, ищите боб с соответствующим именем (ID) из контекста для сборки и выбросить исключение, если он не найден.
        • Если тип указан, файл сверху вниз внизу в одном списке, чтобы найти аналогичный ⼀ боб в ⾏ сборке, не могу найти или найти больше, выкинут исключение.
        • Если не указано ни имя, ни тип, то он будет собран автоматически по методу byName;

Общие черты Spring IoC

lazy-Init ленивая загрузка

  • Отложенная загрузка отключена (по умолчанию): поведение контейнера ApplicationContext по умолчанию заключается в том, чтобы заранее создавать экземпляры всех одноэлементных компонентов при запуске сервера.
  • Включить ленивую загрузку: экземпляр компонента не будет создаваться заранее при запуске ApplicationContext, но при первом запросе контейнера для компонента через getBean.
    1. Предоставляется в Lazy-init = «True», контроль отдельный боб
    2. Установите default-lazy-init = "true" в , контролируйте все Beans в этом контейнере

эффект:

  1. Включите отложенную загрузку, чтобы в определенной степени улучшить запуск и производительность контейнера.
  2. Установите ленивую загрузку для бинов, которые не часто используются, чтобы они загружались, когда используются время от времени, и бину не нужно занимать ресурсы с самого начала.

FactoryBean и BeanFactory

  • Интерфейс BeanFactory: интерфейс верхнего уровня контейнера, определяющий некоторые базовые функции поведения контейнера.

  • Интерфейс FactoryBean: с его пользовательским компонентом Bean, статическими методами и методами создания экземпляров, аналогичными тому, как создаются компоненты Bean.

    инструкции

    1. Создайте класс Factory, соответствующий Bean, реализуйте интерфейс FactoryBean и переопределите getObject(), getObjectType() и isSingleton().

    2. Настройте класс Factory в xml

    3. Во время инициализации контейнера объект Factory создается автоматически, а его getObject() вызывается и управляется.

      Примечание. Если вам нужен объект Factory, вы можете получить объект &${id} в контейнере.

      <bean id="testBean" class="com.test.TestBeanFactory"></bean>
      
      <!--
      	getBean("testBean") 获取的是 TestBean 对象
      	getBean("&testBean") 获取的是 TestBeanFactory 对象
      -->
      

постпроцессор

Весна предоставляет интерфейс расширенной после обработки бобов

  • BeanPostProcessor: экземпляр объекта Bean создается и вызывается после сборки

    Этот интерфейс предоставляет два метода:

    1. postProcessBeforeInitialization: перед методом инициализации Bean
    2. postProcessAfterInitialization: после метода инициализации Bean
  • BeanFactoryPostProcessor: вызывается после инициализации BeanFactory (экземпляр компонента не был создан, и компонент был только что проанализирован в объект BeanDefinition)

    Этот интерфейс предоставляет метод, параметр метода — ConfigurableListableBeanFactory, тип параметра определяет некоторые методы, один из которых называется getBeanDefinition, по этому методу мы можем найти объект BeanDefinition нашего определения бина. Затем мы можем внести изменения в определенные свойства.

    **Объект BeanDefinition:** Мы определяем тег bean-компонента в XML, Spring анализирует тег bean-компонента в JavaBean, и этот JavaBean является BeanDefinition.

Анализ исходного кода Spring IoC

Система наследования контейнеров Spring IoC

![](img/Spring IoC наследование контейнера system.jpg)

Ключевые моменты жизненного цикла бобов

Вызовы на уровне кода в несколько ключевых моментов времени создания объекта Bean находятся в методе обновления класса AbstractApplicationContext.

ключевой момент код триггера
Конструктор refresh#finishBeanFactoryInitialization(beanFactory)(beanFactory)
Инициализация BeanFactoryPostProcessor refresh#invokeBeanFactoryPostProcessors(beanFactory)
Вызов метода BeanFactoryPostProcessor refresh#invokeBeanFactoryPostProcessors(beanFactory)
Инициализация BeanPostProcessor registerBeanPostProcessors(beanFactory)
Вызов метода BeanPostProcessor refresh#finishBeanFactoryInitialization(beanFactory)

Исходный код выглядит следующим образом:

public void refresh() throws BeansException, IllegalStateException {
	// 对象锁加锁
	synchronized (this.startupShutdownMonitor) {
		/*
			Prepare this context for refreshing.
			刷新前的预处理
			表示在真正做refresh操作之前需要准备做的事情:
				设置Spring容器的启动时间,
				开启活跃状态,撤销关闭状态
				验证环境信息里一些必须存在的属性等
		*/
		prepareRefresh();

		/*
			Tell the subclass to refresh the internal bean factory.
			获取BeanFactory;默认实现是DefaultListableBeanFactory
			加载BeanDefition 并注册到 BeanDefitionRegistry
		*/
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		/*
			Prepare the bean factory for use in this context.
			BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)
		*/
		prepareBeanFactory(beanFactory);

		try {
            /*
            	Allows post-processing of the bean factory in context subclasses.
            	BeanFactory准备工作完成后进行的后置处理工作
            */
            postProcessBeanFactory(beanFactory);

            /*
            	Invoke factory processors registered as beans in the context.
            	实例化实现了BeanFactoryPostProcessor接口的Bean,并调用接口方法
            */
            invokeBeanFactoryPostProcessors(beanFactory);

            /*
            	Register bean processors that intercept bean creation.
            	注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行
            */
            registerBeanPostProcessors(beanFactory);
            
            /*
            	Initialize message source for this context.
            	初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
            */
            initMessageSource();

            /*
            	Initialize event multicaster for this context.
            	初始化事件派发器
            */
            initApplicationEventMulticaster();

            /*
            	Initialize other special beans in specific context subclasses.
            	子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器
            */
            onRefresh();

            /*
            	Check for listener beans and register them.
            	注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean
            */
            registerListeners();

            /*
            	Instantiate all remaining (non-lazy-init) singletons.
            	初始化所有剩下的非懒加载的单例bean
            	初始化创建非懒加载方式的单例Bean实例(未设置属性)
            	填充属性
            	初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
            	调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
            */
            finishBeanFactoryInitialization(beanFactory);

            /*
            	Last step: publish corresponding event.
            	完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)
            */
            finishRefresh();
		}catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);}
            
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}

Процесс создания BeanFactory

Получить подпроцесс BeanFactory

Подпроцесс загрузки и регистрации BeanDefinition

  1. Позиционирование ресурсов: процесс инкапсуляции файлов XML в объекты ресурсов.
  2. Загрузка BeanDefinition: определяемый пользователем объект Javabean представлен в виде структуры данных внутри контейнера IoC, а структура данных внутри контейнера — это BeanDefinition.
  3. Зарегистрируйте BeanDefinition в контейнере IoC

Процесс создания бина

Примечание. См. временную диаграмму циклической зависимости IoC.

Принцип ленивого механизма загрузки

public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    // 所有bean的名字
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    // 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
    for (String beanName : beanNames) {
        // 合并父BeanDefinition对象
        // map.get(beanName)
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                // 如果是FactoryBean则加&
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController
                            .doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext());
                    }else {
                        isEagerInit = (factory instanceof SmartFactoryBean 
                                       && ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }else {
                // 实例化当前bean
                getBean(beanName);
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

Например, исходный код:

  • Для bean-компонентов, оформленных как lazy-init, контейнер Spring не будет выполнять инициализацию и внедрение зависимостей на этапе инициализации, он будет инициализирован и внедрен только при первом выполнении getBean.
  • Для неленивых загружаемых компонентов getBean будет получен из заголовка кеша, поскольку компонент был инициализирован и кэширован на этапе инициализации контейнера.

Проблема циклической зависимости Spring IoC

  • Циклическая зависимость параметра конструктора одноэлементного компонента (не может быть разрешена)

  • круговая зависимость прототипа прототипа bean-компонента (не может быть разрешена)

    Для процесса инициализации прототипа bean-компонента, будь то циклическая зависимость через параметры конструктора или циклическая зависимость, сгенерированная методом setXxx, Spring сообщит об ошибке напрямую.

  • Бины-одиночки имеют циклические зависимости через setXxx или @Autowired.

    Теория циклической зависимости Spring основана на передаче по ссылке Java.Когда ссылка на объект получена, свойства объекта могут быть установлены позже, но конструктор должен быть до получения ссылки.

Приложение Spring АОП

Связанные концепции

  • joinPoint (точка соединения): специальные временные точки, такие как начало и конец метода, завершение нормальной операции, ненормальный метод и т. д., точка соединения является точкой-кандидатом.
  • pointCut (pointcut): указать конкретный метод, затронутый АОП, описать интересующий метод
  • Совет (уведомление/улучшение): метод, используемый для предоставления улучшений в классе аспектов, а также представляет собой тип рекомендаций, которые классифицируются следующим образом:Предварительная уведомление, послеведочное уведомление, исключение, окончательное уведомление, уведомление об окружающей среде
    • сквозная логика
    • точка пеленга
  • Цель (время назначения стандартных объектов): прокси-объект
  • Прокси (proxy): прокси-объект
  • Плетение: процесс применения улучшений к целевым объектам для создания новых прокси-объектов. Spring использует динамическое переплетение прокси, в то время как AspectJ использует переплетение во время компиляции и во время загрузки классов.
  • Аспект: Аспект, на котором фокусируется расширенный код. [Пример: класс TransactionManage]
    • Аспект: Концепция аспекта представляет собой синтез вышеуказанных концепций.
    • Аспект аспекта = точка входа + расширение = точка входа (метод блокировки) + точка аспекта (специальное время в методе блокировки) + сквозная логика

Выбор прокси для AOP в Spring

  • Spring реализует идею АОП с использованием технологии динамических прокси

  • по умолчанию

    если проксируемый классреализовать интерфейс⇒ Выберите динамический прокси JDK.

    иначе ⇒ выбрать динамический прокси CGLIB

  • Настраиваемые параметры для принудительного использования динамического прокси CGLIB.

Весенняя реализация АОП

1. XML-схема

  1. импортировать зависимости
  2. Передать бобы руководству Spring
  3. настроить
    • Настроить аспект
    • Улучшено уведомление о конфигурации в поверхности разреза, одно — ориентация, второе — точка разреза.

Обратите внимание:

  1. выражение pointcut

    Относится к строке, которая соответствует определенной грамматической структуре и используется для улучшения грамматически отформатированных точек соединения.

// 示例
// 全限定⽅法名 访问修饰符 返回值 包名.包名.包名.类名.⽅法名(参数列表)
// 全匹配⽅式:
public void com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account) // 访问修饰符可以省略
void com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account) 
// 返回值可以使⽤*,表示任意返回值
* com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account)
// 包名可以使⽤.表示任意包,但是有⼏级包,必须写⼏个
* ....TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account)
// 包名可以使⽤..表示当前包及其⼦包
* ..TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account)
// 类名和⽅法名,都可以使⽤.表示任意类,任意⽅法
* ...(com.lagou.pojo.Account)
// 参数列表,可以使⽤具体类型 基本类型直接写类型名称 : int
// 引⽤类型必须写全限定类名:java.lang.String
// 参数列表可以使⽤*,表示任意参数类型,但是必须有参数
* *..*.*(*)
// 参数列表可以使⽤..,表示有⽆参数均可。有参数可以是任意类型
* *..*.*(..)
// 全通配⽅式:
* *..*.*(..)
  1. Изменить конфигурацию прокси

    • Настройка с помощью тега

      <aop:config proxy-target-class="true">
      
    • Используйте конфигурацию тега .

      <!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解配置AOP 的⽀持-->
      <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectjautoproxy>
      
  2. Пять типов уведомлений

    1. Перед советом: перед выполнением метода выполнения начальной точки

      <aop:before>

    2. Опубликовать уведомление: выполнить после нормального выполнения метода pointcut.

      <aop:after-returning>

    3. Уведомление об исключении: выполняется после выполнения метода pointcut, генерирует исключение

      <aop:after-throwing>

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

      <aop:after>

    5. Окружное уведомление: это специальное использование интерфейса ProceedingJoinPoint и его класса реализации для ручного запуска вызова метода pointcut.

2. XML + режим аннотации

  1. XML открыт весной AOP, держа заметки на ⽀

    <!--开启spring对注解aop的⽀持-->
    <aop:aspectj-autoproxy/>
    
  2. Пример

    /**
    * 模拟记录⽇志
    */
    @Component
    @Aspect
    public class LogUtil {
        /**
        * 我们在xml中已经使⽤了通⽤切⼊点表达式,供多个切⾯使⽤,那么在注解中如何使⽤呢?* 第⼀步:编写⼀个⽅法
        * 第⼆步:在⽅法使⽤@Pointcut注解
        * 第三步:给注解的value属性提供切⼊点表达式
        * 细节:
        *	1.在引⽤切⼊点表达式时,必须是⽅法名+(),例如"pointcut()"。
        *	2.在当前切⾯中使⽤,可以直接写⽅法名。在其他切⾯中使⽤必须是全限定⽅法名。
        */
        @Pointcut("execution(* com.lagou.service.impl.*.*(..))")
        public void pointcut(){}
        
        @Before("pointcut()")
        public void beforePrintLog(JoinPoint jp){
            Object[] args = jp.getArgs();
            System.out.println("前置通知:beforePrintLog,参数是:"+Arrays.toString(args));
        }
        
        @AfterReturning(value = "pointcut()",returning = "rtValue")
        public void afterReturningPrintLog(Object rtValue){
            System.out.println("后置通知:afterReturningPrintLog,返回值是:"+rtValue);
        }
    
        @AfterThrowing(value = "pointcut()",throwing = "e")
        public void afterThrowingPrintLog(Throwable e){
            System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);
        }
    
        @After("pointcut()")
        public void afterPrintLog(){
            System.out.println("最终通知:afterPrintLog");
        }
    
        /**
        * 环绕通知
        * @param pjp
        * @return
        */
        @Around("pointcut()")
        public Object aroundPrintLog(ProceedingJoinPoint pjp){
            //定义返回值
            Object rtValue = null;
            try{
                //前置通知
                System.out.println("前置通知");
                //1.获取参数
                Object[] args = pjp.getArgs();
                //2.执⾏切⼊点⽅法
                rtValue = pjp.proceed(args);
                //后置通知
                System.out.println("后置通知");
            }catch (Throwable t){
                //异常通知
                System.out.println("异常通知");
                t.printStackTrace();
            }finally {
                //最终通知
                System.out.println("最终通知");
            }
            return rtValue;
        }
    }
    

3. Режим аннотации

  1. Добавьте @EnableAspectJAutoProxy в класс конфигурации, чтобы включить поддержку Spring для аннотаций AOP.

Поддержка декларативных транзакций Spring

**Программная транзакция: **Добавьте код управления транзакцией в бизнес-код, такой механизм управления транзакцией называется программной транзакцией.

** Декларативная транзакция: ** Цель управления транзакцией достигается с помощью конфигурации xml или аннотаций, которая называется декларативной транзакцией.

Четыре характеристики дела

  1. ** Атомарность: ** Атомарность означает, что транзакция является неделимой единицей работы, и операции в транзакции либо выполняются, либо не выполняются ни разу.

    Отдействоватьописывается с точки зрения

  2. Последовательность:Транзакция должна вызывать переход базы данных из одного согласованного состояния в другое.

    отданныеописание угла

  3. **Изоляция: **Изоляция транзакции заключается в том, что когда несколько пользователей одновременно обращаются к базе данных, база данных открывает транзакцию для каждого пользователя, и каждая транзакция не может быть нарушена данными операций других транзакций. Параллельные транзакции должны быть изолированы. друг от друга.

  4. **Долговечность: **Долговечность означает, что после фиксации транзакции ее изменения в данных в базе данных являются постоянными, и даже если база данных выходит из строя, это не должно иметь никакого влияния на нее.

Уровень изоляции транзакции

проблема:

  • Грязное чтение: ⼀ темы в чужих делах ⼀ читать темуне отправленДанные.
  • Неповторяющееся чтение: транзакция в одном потоке читается в другом потоке.уже отправленоизupdateданные (до и после содержимое отличается)
  • Привязанность (магическое чтение): транзакция в потоке читает другой поток.уже отправленовставить или удалить данные (количество до и после разное)

Существует четыре уровня изоляции базы данных:

  • Сериализуемый: он может избежать возникновения грязных чтений, неповторяемых чтений и виртуальных чтений. (сериализованный) самый высокий

  • Повторяемое чтение: позволяет избежать грязных чтений и неповторяющихся чтений. (Может произойти фантомное чтение) Второй

    В соответствии с этим механизмом обновляемая строка будет заблокирована.

  • Read committed(读已提交):可避免脏读情况发⽣。不可重复读和幻读⼀定会发⽣。 третий

  • Читайте незарегистрированные (прочитайте Unmized): самый низкий уровень, вышеизложенное их не может быть гарантировано. (Прочитайте не менее) минимум

Примечание: Уровень увеличивается, а эффективность уменьшается.

Уровень изоляции MySQL по умолчанию: REPEATABLE READ

Поведение распространения транзакции

Обычно используются первые два (жирный шрифт)

PROPAGATION_REQUIRED Если текущей транзакции нет, создать новую транзакцию, если транзакция уже есть, присоединиться к этой транзакции. Это самый распространенный выбор.
PROPAGATION_SUPPORTS Поддерживать текущую транзакцию, если текущей транзакции нет, она будет выполнена в нетранзакционном режиме.
PROPAGATION_MANDATORY Используйте текущую транзакцию или создайте исключение, если текущей транзакции нет.
PROPAGATION_REQUIRES_NEW Создать новую транзакцию. Если есть текущая транзакция, приостановить текущую транзакцию.
PROPAGATION_NOT_SUPPORTED Выполнить операцию нетранзакционным способом и приостановить текущую транзакцию, если текущая транзакция существует.
PROPAGATION_NEVER Выполняется нетранзакционным образом, вызывая исключение, если в данный момент есть транзакция.
PROPAGATION_NESTED Если транзакция уже существует, выполните ее во вложенной транзакции. Если текущих транзакций нет, сделайте что-то похожее на PROPAGATION_REQUIRED.

Конфигурация декларативной транзакции Spring

Примечание. Подобно настройке AOP, настройте .

Открытая весна ⽀ комментарий о делах холдинга

<tx:annotation-driven transactionmanager="transactionManager"/>или@EnableTransactionManagement

Анализ исходного кода Spring AOP

Связь вызова метода класса анализа исходного кода АОП

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
调⽤
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
调⽤
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization(后置处理器AbstractAutoProxyCreator完成bean代理对象创建)
调⽤
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
调⽤
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy(在这⼀步把委托对象的aop增强和通⽤拦截进⾏合并,最终给代理对象)
调⽤
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
调⽤
org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader )

Spring декларативный контроль транзакций

@EnableTransactionManagement 注解
1)通过@import引⼊了TransactionManagementConfigurationSelector类
    它的selectImports⽅法导⼊了另外两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration 
2)AutoProxyRegistrar类分析
    ⽅法registerBeanDefinitions中,引⼊了其他类,通过AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)引⼊
InfrastructureAdvisorAutoProxyCreator,它继承了AbstractAutoProxyCreator,是⼀个后置处理器类
3)ProxyTransactionManagementConfiguration 是⼀个添加了@Configuration注解的配置类 (注册bean)
    注册事务增强器(注⼊属性解析器、事务拦截器)
    属性解析器:AnnotationTransactionAttributeSource,内部持有了⼀个解析器集合Set<TransactionAnnotationParser> annotationParsers;具体使⽤的是SpringTransactionAnnotationParser解析器,⽤来解析@Transactional的事务属性
    事务拦截器:TransactionInterceptor实现了MethodInterceptor接⼝,该通⽤拦截会在产⽣代理对象之前和aop增强合并,最终⼀起影响到代理对象
        TransactionInterceptor的invoke⽅法中invokeWithinTransaction会触发原有业
务逻辑调⽤(增强事务)