Весенняя серия вопросов для интервью

Spring

1. Аннотации, используемые springmvc, какова функция и принцип.

@Контроллер аннотацияВ пакете Spring org.springframework.stereotype тип аннотации org.springframework.stereotype.Controller используется для указания того, что экземпляр класса Spring является контроллером, а класс, аннотированный с помощью @Controller, не должен наследовать определенный родительский класс. или реализовать конкретный Интерфейс, по сравнению с предыдущей версией реализация интерфейса Контроллера стала проще. Класс реализации интерфейса Controller может обрабатывать только одно действие запроса, в то время как контроллер с аннотацией @Controller может поддерживать одновременную обработку нескольких действий запроса, что делает разработку программы более гибкой. Пользователи @Controller отмечают класс, и класс, отмеченный им, является объектом контроллера Spring MVC, то есть классом контроллера. Spring использует механизм сканирования для поиска всех классов контроллеров на основе аннотаций в приложении.Процессор распределения просканирует метод с помощью аннотации и определит, использует ли метод аннотацию @RequestMapping, а метод, использующий аннотацию @RequestMapping, является реальной обработкой , обработчик запроса. Чтобы убедиться, что Spring может найти контроллер, нам нужно сделать две вещи:

1. Введите spring-context в заголовок конфигурационного файла Spring MVC; 2. Используйтеcontext:component-scan/Функция этого элемента — запустить функцию сканирования пакетов, чтобы классы, аннотированные с помощью @Controller, @Service, @repository, @Component и т. д., были зарегистрированы как Spring bean-компоненты.

Аннотация @RequestMapping

Существует множество аннотаций для привязки параметров в Spring MVC, все они находятся в пакете org.springframework.web.bind.annotation Их можно разделить на четыре категории (общие типы) в соответствии с различным содержанием обрабатываемых ими запросов.

Первая категория: аннотации, обрабатывающие часть тела запроса: @RequestParam и @RequestBody. Вторая категория: аннотации, относящиеся к части запроса uri: @PathVaribale Третья категория: аннотации, обрабатывающие часть заголовка запроса: @RequestHeader и @CookieValue. Четвертая категория: аннотации, относящиеся к типам атрибутов: @SessionAttributes и @MoelAttribute.

@RequestParam аннотация

Поговорим о третьей аннотации в рамках пакета org.springframework.web.bind.annotation, а именно: аннотации @RequestParam, которая используется для присвоения заданного параметра запроса формальному параметру в методе. Итак, какие свойства имеет аннотация @RequestParam? Он имеет 4 свойства, которые будут представлены одно за другим ниже:

1. атрибут имени Тип этого свойства — тип String, который может указывать имя привязки заголовка запроса; 2, значение атрибута Тип свойства — тип String, который может быть установлен как псевдоним свойства имени; 3. обязательный атрибут Тип этого свойства является логическим типом, который может указать, должен ли указанный параметр быть привязанным; 4, свойство defaultValue Тип свойства — тип String, его можно настроить на использование значения по умолчанию, если параметр не передается.

Аннотация @PathVaribaleДавайте поговорим о четвертой аннотации в пакете org.springframework.web.bind.annotation, а именно: аннотация @PathVaribale, этот тип аннотации может легко получить динамические параметры в URL-адресе запроса. Аннотация @PathVaribale поддерживает только одно значение атрибута, тип String, который представляет имя привязки. Если он опущен, параметр с тем же именем привязывается по умолчанию.

Наиболее часто используются приведенные выше, если вы хотите узнать больше, вы можете обратиться к следующим ссылкам:blog.CSDN.net/before_eat/art…

2. Почему нельзя определить локальные переменные в методе контроллера springmvc? .

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

Как теперь решить эту проблему?

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

Второй способ: jdk предоставляет java.lang.ThreadLocal, что дает новую идею многопоточного параллелизма.

Третий тип: используйте @Scope("session"), уровень сеанса

    @Controller  
    //把这个bean 的范围设置成session,表示这bean是会话级别的,  
    @Scope("session")  
    public class XxxController{  
        private List<String> list ;  
 
      //@PostConstruct当bean加载完之后,就会执行init方法,并且将list实例化;  
        @PostConstruct  
        public void init(){  
            list = new ArrayList<String>();  
        }  
 
    } 

Четвертое: Изменить область действия контроллера с синглтона на прототип, то есть объявить scope="prototype" в конфигурационном файле spring Controller, и каждый раз создавать новый контроллер

3. Процесс инициализации DispatcherServlet в Springmvc.

4. Процесс и принцип выполнения SpringMVCПроцесс SpringMVC:

01. Пользователь отправляет запрос на интерфейсный контроллер DispatcherServlet.

02. DispatcherServlet получает запрос и вызывает HandlerMapping (сопоставитель обработчиков).

03. HandlerMapping находит конкретный процессор (вы можете найти конфигурацию xml или конфигурацию аннотаций), генерирует объект процессора и перехватчик процессора (если есть) и вместе возвращает их DispatcherServlet.

04. DispatcherServlet вызывает HandlerAdapter (адаптер обработчика).

05. HandlerAdapter вызывает определенные обработчики (Handler/Controller) после адаптации.

06. Контроллер возвращается к объекту ModelAndView после завершения выполнения.

07. HandlerAdapter возвращает результат выполнения контроллера ModelAndView в DispatcherServlet.

08. DispatcherServlet передает ModelAndView в ViewReslover (преобразователь представлений).

09. ViewReslover возвращается к определенному представлению после синтаксического анализа.

10. DispatcherServlet визуализирует представление в соответствии с представлением (то есть заполняет представление данными модели).

11. DispatcherServlet отвечает пользователю.

5. Разница между @autowire и @resource

Контраст @Autowire @Resource
Источник аннотации Весенние аннотации Аннотации JDK (стандартные аннотации JSR-250, принадлежащие J2EE)
Метод сборки приоритет по типу первый по имени
Атрибуты required имя, тип
Сфера Поля, сеттеры, конструкторы Поля, методы настройки

6. В чем разница между перехватчиком в SpringMVC и фильтром в Servlet?

Прежде всего, суть в том, что фокус перехвата у них разный.Перехватчик в SpringMVC реализован с опорой на отражение JDK.Перехватчик SpringMVC в основном перехватывает запросы и перехватывает их при обработке обработчиков, которые объявлены первыми. Метод preHandle в перехватчике будет выполнен первым, но его метод postHandle (который находится между после обработки дела и перед возвратом результата) и метод afterCompletion будут выполнены позже. А перехватчики Spring перехватываются в порядке конфигурации.

Фильтр Servlet — это фильтр, основанный на обратном вызове функции.Фильтр в основном выполняет кодирование для URL-адреса, отфильтровывает бесполезные параметры и выполняет проверку безопасности (более общую, например, вход в систему или не вход в систему).

7. Расскажите о процессе загрузки Spring.

Инициализировать среду -> загрузить файл конфигурации -> создать экземпляр bean-компонента -> вызвать bean-компонент для отображения информации

Прежде всего, мы объясним основные шаги, потому что в Spring слишком много специфических процессов загрузки и классов.

(1) Сначала вызовите метод doGetBean (name, requiredType, final Object[] args, boolean typeCheckOnly [это для того, чтобы решить, создавать ли bean-компонент или просто использовать его для проверки типов]) из AbstractBeanFactory, а затем первый шаг что делать Первое — преобразовать имя входящего параметра, т.к. можно передать name="&XXX" и т.д., нужно убрать символ &

(2), а затем вызовите метод getSingleton(). Фактически, этот метод упоминался в предыдущем вопросе интервью. Этот метод заключается в использовании «трехуровневого кеша», чтобы избежать возникновения циклических зависимостей. [Добавьте сюда, проблема круговой зависимости будет решена только в случае синглтона]

(3) Компонент, полученный из кеша, на самом деле является самым примитивным компонентом и еще не вырос, поэтому необходимо вызвать метод getObjectForBeanInstance (Object beanInstance, String name, String beanName, RootBeanDefinition mbd) для его создания.

(4), а затем попытаться решить циклическую зависимость в случае синглтона.Если isPrototypeCurrentlyInCreation(beanName) возвращает true, он переходит к следующему шагу, в противном случае генерируется новое исключение BeanCurrentlyInCreationException(beanName);

(5), потому что, если в кеше нет данных на третьем шаге, перейдите непосредственно к parentBeanFactory, чтобы получить bean-компонент, а затем определите containsBeanDefinition (beanName), чтобы проверить, содержит ли загруженный XML-файл такой bean-компонент. не существует Если да, рекурсивно перейдите к getBean(), чтобы получить его, если нет, перейдите к следующему шагу

(6) Этот шаг заключается в преобразовании GernericBeanDifinition, хранящегося в файле конфигурации XML, в объект RootBeanDifinition. Здесь в основном преобразование, если bean-компонент родительского класса не пуст, свойства родительского класса будут объединены вместе

(7) Суть этого шага заключается в том, что все зависимые компоненты, связанные с этим компонентом, должны быть загружены, прямо сейчас получить все имена компонентов через объект RootBeanDifinition, а затем зарегистрировать зависимости компонента через registerDependentBean (dependsOnBean, beanName)

(8), а затем этот шаг состоит в том, чтобы определить область действия, когда мы определяем область действия компонента, а затем принимаем решение о создании различных стратегий (таких как isSingleton, isPrototype)

(9) Это последний шаг преобразования типов, который проверяет, соответствует ли требуемый тип фактическому типу компонента для выполнения преобразования типов. Spring предоставляет множество преобразователей типов

8. Принцип реализации Spring АОП.

АОП (аспектно-ориентированное программирование, аспектно-ориентированное программирование): это дополнение и улучшение ООП. ООП вводит инкапсуляцию, наследование, полиморфизм и т. д. для установления иерархии объектов (связь сверху вниз). Когда необходимо ввести общее поведение для разрозненных объектов (связь слева направо), ООП бессилен. Например: функция журнала. Код ведения журнала обычно распространяется горизонтально по всем иерархиям объектов и не имеет ничего общего с основной функциональностью объекта. Такой код называется сквозным кодом, а такие вещи, как безопасность, обработка исключений, прозрачное сохранение и т. д., также называются сквозным кодом. В ООП-дизайне они приводят к большому количеству дублирования кода, что не способствует повторному использованию модулей.

АОП — это противоположность ООП, использующая «сквозную» технологию для инкапсуляции общего поведения, влияющего на несколько классов, в многоразовый модуль под названием Aspect. Проще говоря, это инкапсуляция логики, которая не имеет ничего общего с бизнесом, но обычно вызывается бизнес-модулями, что удобно для сокращения повторяющегося кода системы, уменьшения связи между модулями и облегчения работы в будущем. и ремонтопригодность. Основная идея АОП состоит в том, чтобы «отделить бизнес-логику в приложении от общих сервисов, которые ее поддерживают». Spring предоставляет два способа создания прокси-объектов: JDKProxy и Cglib используют метод для создания, который определяется AopProxyFactory в соответствии с конфигурацией объекта AdvisedSupport. Стратегия по умолчанию заключается в использовании технологии динамического прокси JDK, если целевой класс является интерфейсом, в противном случае используйте Cglib для создания прокси.

9. Расскажите о свойствах распространения транзакций Spring.

1), PROPAGATION_REQUIRED — поддерживать текущую транзакцию, если текущей транзакции нет, создать новую транзакцию. (Общий выбор) Например, уровень транзакции ServiceB.methodB определен как PROPAGATION_REQUIRED, тогда, поскольку ServiceA.methodA уже начал транзакцию при выполнении ServiceA.methodA, в это время вызывается ServiceB.methodB, и ServiceB.methodB видит что он уже запущен в ServiceA Внутри транзакции .methodA новая транзакция не запускается. И если ServiceA.methodA запустится и обнаружит, что он не в транзакции, он назначит себе транзакцию. Таким образом, если в ServiceA.methodA или где-либо в ServiceB.methodB возникнет исключение, транзакция будет отменена. Даже если транзакция ServiceB.methodB была зафиксирована, но ServiceA.methodA будет откатываться при следующем сбое, ServiceB.methodB также будет откатываться. 2), PROPAGATION_SUPPORTS — поддерживать текущую транзакцию, если текущей транзакции нет, она будет выполнена нетранзакционным способом. 3), PROPAGATION_MANDATORY — поддерживает текущую транзакцию, если текущей транзакции нет, будет выброшено исключение. 4), PROPAGATION_REQUIRES_NEW - поддерживать текущую транзакцию, если текущей транзакции нет, текущая транзакция будет приостановлена. Например, уровень транзакции ServiceA.methodA — PROPAGATION_REQUIRED, а уровень транзакции ServiceB.methodB — PROPAGATION_REQUIRES_NEW, тогда при выполнении ServiceB.methodB транзакция, в которой находится ServiceA.methodA, зависнет, а ServiceB.methodB запустит новая транзакция. После ожидания завершения транзакции ServiceB.methodB A продолжит выполнение. Разница между ним и PROPAGATION_REQUIRED заключается в степени отката транзакции. Поскольку ServiceB.methodB — это новая транзакция, это две разные транзакции. Если ServiceB.methodB был отправлен, то ServiceA.methodA завершается ошибкой и откатывается, но ServiceB.methodB не откатывается. В случае сбоя ServiceB.methodB и отката, если исключение, которое он выдает, перехвачено ServiceA.methodA, транзакция ServiceA.methodA все еще может быть зафиксирована. 5), PROPAGATION_NOT_SUPPORTED — выполнить текущую операцию нетранзакционным способом и приостановить транзакцию, если текущая транзакция существует. 6), PROPAGATION_NEVER — выполнять нетранзакционным образом, если есть текущая транзакция, генерировать исключение. 7), PROPAGATION_NESTED — если в данный момент есть транзакция, она будет выполнена внутри вложенной транзакции, ключ — точка сохранения. Если текущих транзакций нет, сделайте что-то похожее на PROPAGATION_REQUIRED. Отличие от PROPAGATION_REQUIRES_NEW заключается в том, что транзакция NESTED зависит от своей родительской транзакции, а ее фиксация заключается в ожидании фиксации родительской транзакции. То есть, если родительская транзакция откатывается последней, она также откатывается.

10. Как Spring управляет транзакциями.

Управление транзакциями Spring в основном включает три интерфейса, а транзакции Spring в основном выполняются следующими тремя: 1), PlatformTransactionManager: менеджер транзакций, в основном используемый для управления транзакциями, связанными с платформой. В основном он включает три метода: ①, commit: фиксация транзакции. ②, откат: транзакция откатывается. ③, getTransaction: получить статус транзакции.

2), TransacitonDefinition: информация об определении транзакции, используемая для определения атрибутов, связанных с транзакцией, существует четыре основных метода использования этого интерфейса для диспетчера транзакций PlatformTransactionManager: ①, getIsolationLevel: получение уровня изоляции. ②, getPropagationBehavior: получить поведение распространения. ③, getTimeout, чтобы получить время ожидания. ④, isReadOnly: доступно ли только для чтения (свойство становится ложным при сохранении, обновлении и удалении — чтение-запись и истинно при запросе — только для чтения) Менеджер транзакций может оптимизировать на основе этого возвращаемого значения.Информация о конфигурации всех этих транзакций можно настроить через конфигурационные файлы.

3) TransationStatus: конкретное текущее состояние транзакции, информация о состоянии транзакции в каждый момент времени в процессе управления транзакциями. Например: ①, hasSavepoint(): возвращает, содержит ли транзакция точку сохранения. ②, isCompleted(): возвращает, была ли транзакция завершена, то есть была ли она зафиксирована или отменена. ③, isNewTransaction(): определяет, является ли текущая транзакция новой транзакцией.

11. Как Spring настраивает транзакции (укажите некоторые ключевые элементы xml).

Существует два способа настройки транзакций: 1), конфигурация транзакций на основе XML.

<?xml version="1.0" encoding="UTF-8"?>
<!-- from the file 'context.xml' -->  
<beans xmlns="http://www.springframework.org/schema/beans"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:aop="http://www.springframework.org/schema/aop"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
     xsi:schemaLocation="  
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
      
  <!-- 数据元信息 -->  
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>  
  	<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>  
  	<property name="username" value="root"/>  
  	<property name="password" value="root"/>  
  </bean>  
  
  <!-- 管理事务的类,指定我们用谁来管理我们的事务-->  
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  	<property name="dataSource" ref="dataSource"/>  
  </bean>   
  
  <!-- 首先我们要把服务对象声明成一个bean  例如HelloService -->  
  <bean id="helloService" class="com.yintong.service.HelloService"/>  
  
  <!-- 然后是声明一个事物建议tx:advice,spring为我们提供了事物的封装,这个就是封装在了<tx:advice/>中 -->
  <!-- <tx:advice/>有一个transaction-manager属性,我们可以用它来指定我们的事物由谁来管理。
      默认:事务传播设置是 REQUIRED,隔离级别是DEFAULT -->
  <tx:advice id="txAdvice" transaction-manager="txManager">  
	  <!-- 配置这个事务建议的属性 -->  
	  <tx:attributes>  
	    <!-- 指定所有get开头的方法执行在只读事务上下文中 -->  
	    <tx:method name="get*" read-only="true"/>  
	    <!-- 其余方法执行在默认的读写上下文中 -->  
	    <tx:method name="*"/>  
	  </tx:attributes>  
  </tx:advice>  
    
  <!-- 我们定义一个切面,它匹配FooService接口定义的所有操作 -->  
  <aop:config>  
	 <!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示com.yintong.service.helloService包下的任意方法。 -->
 	 <aop:pointcut id="helloServiceOperation" expression="execution(* com.yintong.service.helloService.*(..))"/>  
	 <!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 -->
  	 <aop:advisor advice-ref="txAdvice" pointcut-ref="helloServiceOperation"/>  
  </aop:config>  
 
</beans>  

2), конфигурация транзакций на основе аннотаций.

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:aop="http://www.springframework.org/schema/aop"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
     xsi:schemaLocation="  
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
    
  <bean id="helloService" class="com.yintong.service.HelloService"/>  
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
     <property name="dataSource" ref="dataSource"/>  
  </bean>
  <!-- 配置注解事务 -->  
  <tx:annotation-driven transaction-manager="txManager"/>  
</beans>

Аннотация транзакции @Transactional в основном определяется в классе следующим образом:

//@Transactional 注解可以声明在类上,也可以声明在方法上。在大多数情况下,方法上的事务会首先执行
@Transactional(readOnly = true)    
public class HelloService{  
    public Foo getFoo(String fooName) {  
    }  
    //@Transactional 注解的事务设置将优先于类级别注解的事务设置   propagation:可选的传播性设置 
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)      
    public void updateFoo(Hel hel) {
    }
}  

12. Расскажите о своем понимании Spring

1), Spring — это среда с открытым исходным кодом, предназначенная главным образом для упрощения разработки приложений корпоративного уровня. Может выполнять функции, которые может выполнять EJB, Spring представляет собой контейнерную среду IOC и AOP. ♧ Инверсия управления (IOC): Контейнер Spring использует фабричный шаблон для создания необходимых нам объектов. Нам не нужно создавать их самостоятельно, когда мы их используем. Мы можем напрямую вызывать объекты, предоставленные Spring. Это идея инверсии управления. ♧ Внедрение зависимостей (DI): Spring использует метод Set объекта Java Bean или конструктор с параметрами, чтобы автоматически устанавливать требуемое значение его свойств, когда мы создаем требуемый объект, что является основной идеей внедрения зависимостей. ♧ Аспектно-ориентированное программирование (АОП): В идее объектно-ориентированного программирования (ООП) мы абстрагируем вещи вертикально в объекты один за другим. В аспектно-ориентированном программировании мы горизонтально абстрагируем некоторые схожие аспекты каждого объекта в аспект, а процесс выполнения некоторых общих операций, таких как проверка разрешений, управление транзакциями, ведение журналов и т. д., в этом аспекте является идеей аспект- ориентированное программирование. 2) В Spring все управление — это объекты JavaBean, а BeanFactory и ApplicationContext — это IOC-контейнеры фреймворка Spring Сейчас вообще используется ApplicationContext, который не только включает в себя роль BeanFactory, но и имеет больше расширений.

13. Принцип несинглтонной инъекции Spring

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

14. Принцип внедрения зависимостей Spring

Мы знаем, что в Spring существует четыре способа внедрения зависимостей, а именно внедрение метода get/set, внедрение конструктора, внедрение метода статической фабрики и внедрение метода фабрики экземпляров.

Блог Woohoo.cn на.com/model backstage/afraid/…

15. Жизненный цикл спрингбина

Благодаря этой картинке можно примерно понять жизненный цикл весны и подробно объяснить:

Сначала создайте экземпляр объекта bean Затем установите свойство bean-компонента Далее идет BeanNameAware (фактически, чтобы позволить контейнеру Spring получить имя компонента), BeanFactoryAware (чтобы BeanFactory компонента вызывала службы контейнера) и ApplicationContextAware (чтобы текущий applicationContext компонента вызывал службы контейнера Spring). Затем он реализует два метода в интерфейсе BeanPostProcessor, в основном pre-initialization postProcessBeforeInitialization вызывающего интерфейса. Здесь в основном вызывается метод инициализации init-method="xxxx", определенный вами в xml Затем продолжайте вызывать postProcessAfterInitialization() для метода пост-инициализации в интерфейсе BeanPostProcessor. На самом деле, на этом шаге инициализация этого компонента практически завершена, и он находится в состоянии готовности. Затем, когда контейнер Spring будет завершен, будет вызван метод destroy(). Наконец, мы выполним наш собственный определенный метод уничтожения, чтобы уничтожить, а затем завершим жизненный цикл.

16. Как решить круговую зависимость bean-компонентов в Spring?

Циклическая зависимость Spring на самом деле возникает, когда выполняется getBean, объект A зависит от объекта B, а объект B зависит от объекта C, но объект C зависит от объекта A, в результате три объекта A, B , а C не может быть Создание экземпляра завершено, и существует циклическая зависимость. Будет бесконечный цикл, который в итоге приведет к ошибке переполнения памяти.

, Как разрешить циклические зависимости Spring? 1. Сначала узнайте, что такое «трехуровневый кеш» Spring: это следующие три больших объекта Map, потому что теоретическая основа циклической зависимости в Spring на самом деле основана на передаче значений в java, а затем на самом деле синглтон в Spring Object создание делится на три этапа:

createBeanInstance, по сути, первым шагом является создание экземпляра объекта с помощью метода построения. Но этот шаг — всего лишь объект-экземпляр, и свойства объекта в него не внедряются. Затем этот шаг заключается в том, чтобы внедрить свойства объекта экземпляра, то есть заполнить свойства, указанные в spring xml, с этого шага. Последний шаг — фактически инициализировать метод init в XML, чтобы окончательно завершить создание экземпляра объекта. Однако шаги метода AfterPropertiesSet будут сосредоточены на первом и втором шагах.

singletonObjects指单例对象的cache (一级缓存)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

singletonFactories指单例对象工厂的cache(三级缓存)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

earlySingletonObjects指提前曝光的单例对象的cache(二级缓存)
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

  1. Тогда как конкретно использовать этот кеш L3, или идею кеша L3?

Первый шаг — вызвать getSingleton(String beanName, boolean allowEarlyReference) в Spring, чтобы получить желаемый одноэлементный объект. Затем первым шагом является получение объекта через кэш-коллекцию singletonObjects первого уровня.Если это не удалось, и используйте isSingletonCurrentlyInCreation(beanName), чтобы определить, создается ли соответствующий объект-одиночка (то есть когда объект-одиночка создается). Не инициализирован полностью, перейдите к первому шагу или второй раз инициализации), если он создается, он перейдет к следующему шагу Затем он продолжит получать этот объект из EarlySingletonObjects, если объект singleton не получен, и передаст флаг allowEarlyReference, переданный в качестве параметра, чтобы увидеть, разрешено ли singletonFactories (кеш-коллекция уровня 3) получать объект экземпляра, если если allowEarlyReference верно, то переходите к следующему шагу В настоящее время желаемый объект экземпляра не был получен из кэш-коллекции второго уровня EarlySingletonObjects на предыдущем шаге, и, наконец, объект экземпляра может быть получен только из кэш-памяти третьего уровня singletonFactories (коллекция фабрики синглетонов), Затем поместить полученный объект в EarlySingletonObjects (кэш второго уровня) через Put(beanName, singletonObject), а затем удалить объект из коллекции в singletonFactories (кеш третьего уровня) для удаления объекта (beanName). Прикрепите основной код

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
 从一级缓存获取
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
       从二级缓存获取
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
          从三级缓存获取
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return (singletonObject != NULL_OBJECT ? singletonObject : null);}

  1. Объясните, почему это может решить проблему циклической зависимости в Spring.

Фактически, когда экземпляр объекта фактически не создан, объект был произведен, хотя он и не совершенен (второй и третий этапы инициализации не выполнены), он может быть опознан людьми (по объекту. может найти объект в куче), поэтому Spring заранее предоставляет этот объект для всех, чтобы знать и использовать Первый завершил первый шаг инициализации и заранее представил себя singletonFactory.В это время, на втором шаге инициализации, он обнаружил, что он зависит от объекта B. В это время он попытался получить(B) и обнаружил что B не был создан. , поэтому в процессе создания B обнаружил, что зависит от объекта A при инициализации первого шага, поэтому он попытался получить (A), попробовал кэш первого уровня singletonObjects (конечно, нет, потому что A не была полностью инициализирована) и попробовал кэш второго уровня EarlySingletonObjects (Нет), попробуйте трехуровневый кэш singletonFactory, потому что A заранее раскрывает себя через ObjectFactory, поэтому B может получить объект A через ObjectFactory.getObject (хотя A еще не был полностью инициализирован, но это лучше, чем ничего), B принимает После достижения объекта A успешно завершаются этапы инициализации 1, 2 и 3. После завершения инициализации он помещает себя в кэш первого уровня singletonObjects. В это время, вернувшись к A, A может получить объект B и успешно завершить этапы 2 и 3 своей инициализации. B получил ссылку на объект A, объект A, которым теперь владеет B, также преобразился до совершенства! Все так волшебно! !

Резюме: Прыжок через трехуровневый кеш плюс механизм «раннего раскрытия» в сочетании с принципом ссылки на объект Java в некоторых случаях прекрасно решает проблему циклической зависимости!

blog.CSDN.net/IT Mr Chen/AR… blog.CSDN.net/QQ_36520235…

17. Когда создается экземпляр bean-компонента контейнера Spring?

(1) Если вы используете BeanFactory в качестве фабричного класса Spring Bean, все bean-компоненты создаются при первом использовании bean-компонента. (2) Если вы используете ApplicationContext в качестве фабричного класса Spring Bean, он делится на следующие ситуации: Если областью действия bean-компонента является singleton, а lazy-init имеет значение false (по умолчанию false, поэтому вам не нужно его устанавливать), экземпляр bean-компонента создается при запуске ApplicationContext, и экземпляр bean-компонента помещается в кеш. структуры карты, при следующем использовании компонента он будет взят непосредственно из кеша. Если областью действия bean-компонента является singleton, а lazy-init имеет значение true, экземпляр bean-компонента создается при первом использовании bean-компонента. Если областью действия bean-компонента является прототип, экземпляр bean-компонента создается при первом использовании bean-компонента.

18. Как реализован нижний уровень АОП в Spring?

Реализация нижнего уровня АОП в Spring фактически основана на динамическом прокси JDK и динамическом прокси динамически созданного класса cglib:

  1. Принцип первого динамического прокси на основе JDK:

Несколько ключевых членов, которые необходимо использовать InvocationHandler (все объекты, которые вы хотите сгенерировать через динамический прокси-сервер, должны реализовывать этот интерфейс) Реальный объект, который необходимо проксировать (объект, для которого вы проксируете) Прокси-объект (в пакете java.lang.reflect в JDK)

Ниже показано, как динамически использовать эти три компонента для создания прокси-объектов.

(1) Прежде всего, объект, который вы действительно хотите проксировать, должен реализовать интерфейс InvocationHandler и переопределить метод invoke(Object proxyObject, Method method, Object[] args) этого интерфейса.ProxyObject параметра метода в Invoker — это то, что вы хотите проксировать. Реальный целевой объект, вызов метода будет переадресован методу invoke() этого класса, method — это класс Method, который вызывает метод в реальном объекте, а Object[] args — это параметр вызывающего метода в реальном объекте

(2) Затем вызовите метод newProxyInstance(classLoader, interfaces, handler) через класс Proxy, classLoader ссылается на загрузчик классов реального прокси-объекта, интерфейсы ссылаются на интерфейс, который должен реализовать реальный прокси-объект, и вы можете указать несколько интерфейсов одновременно, обработчик Фактический обработчик вызова метода (фактически объекта, который вы проксируете), вызов метода прокси-объекта будет перенаправлен сюда, а затем нужный вам класс объекта может быть сгенерирован напрямую.

В конце концов

Если вы заинтересованы в Java и больших данных, нажмите и удерживайте QR-код, чтобы следовать за волной, и я сделаю все возможное, чтобы принести вам пользу. Если вы чувствуете, что даже небольшая помощь вам полезна, пожалуйста, помогите, поставьте лайк или сделайте ретвит. Обратите внимание на публичный аккаунт** [love code],Ответить2019** содержит соответствующую информацию.