предисловие
SpringКак решить циклическую зависимость — популярный вопрос на собеседованиях по Java за последние два года.
Собственно, сам авторисходный код фреймворкаВсе еще скептически.
Если бы я был интервьюером, я мог бы спросить что-то вроде «Что, если внедренное свойствоnull, с каких сторон вы бы исследовали этивопрос сцены.
Ну, раз уж я написал эту статью, хватит сплетничать и взглянитеКак Spring решает циклические зависимости, и покажу вам, в чем суть циклических зависимостей.
текст
Вообще говоря, если вы спросите Spring, как внутренне разрешать циклические зависимости, это должно быть одно значение по умолчанию.синглтонВ Bean - сцена, в которой атрибуты ссылаются друг на друга.
Например, взаимные ссылки между несколькими bean-компонентами:
Даже "циклически" зависят от себя:
Предпосылка первая:прототип(Прототип) сценарийне поддерживаетсяЦиклические зависимости, обычно идут вAbstractBeanFactory
Следующее суждение в классе вызывает исключение.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
Причина хорошо понятна, создаваяновый АКогда обнаруживается инъекцияПрототип поля B, что создаетновый Бнайдено для инъекцииПрототип поля А...
Это матрешка, угадайте что?StackOverflowвсе ещеOutOfMemory?
Весна боится, что не угадаешь, поэтому бросает первойBeanCurrentlyInCreationException
Циклические зависимости на основе конструктора, не говоря уже о том,официальная документацияЭто разборки. Если вы хотите, чтобы внедрение конструктора поддерживало циклические зависимости, его не существует. Лучше изменить код.
Затем сцена внедрения свойства синглтона по умолчанию,SpringКак поддерживается круговая зависимость?
Springразрешить циклические зависимости
Во-первых, Spring внутренне поддерживает триMap, что мы обычно называемКэш L3.
Автор полистал документацию Spring, но не нашел понятия трехуровневого кеша, которое тоже может быть локальным словарем для облегчения понимания.
веснойDefaultSingletonBeanRegistry
В классе вы найдете эти три Карты, висящие над классом:
-
singletonObjectsЭто наш самый знакомый друг, широко известный как "одноэлементный пул""контейнер", кэш, в котором создается одноэлементный компонент.
-
singletonFactoriesОтображение исходной фабрики, создавшей bean-компонент
-
earlySingletonObjectsСопоставление компонентовраноЦитата, то есть боб в этой карте не полный, и даже не может называться "Bean",только одинInstance.
Последние две карты на самом деле "ступенька», он используется только для использования при создании бина, и он будет очищен после завершения создания.
Итак, автор немного запутался со словом «кеш 3-го уровня» в предыдущей статье, вероятно, потому, что все комментарии начинаются с «Кэш оф».
Зачем становиться последними двумя картами какступенька, предполагая, что окончательныйsingletonObjectsБоб - это то, что вы хотите в чашке"классный и белый".
Тогда Весна приготовила две чашки, а именноsingletonFactoriesиearlySingletonObjects«Повернуть» взад-вперед несколько раз, пусть горячая вода сухаяклассный и белый"ставитьsingletonObjectsсередина.
Никаких сплетен, все сжато на картинке.
Выше есть GIF, если вы его не видите, возможно, он еще не загружен.Три секунды один кадр, а не твоя компьютерная карта.
Автор нарисовал 17 рисунковУпрощенное выражениеОсновные шаги Spring, приведенный выше GIF — это только что упомянутый трехуровневый кеш, а нижний дисплей —главныйнесколько методов.
Конечно, в этот момент вы должны объединитьИсходный код SpringДа ладно, может ты не понял.
Если вы просто хотите получить общее представление или интервью, вы можете сначала вспомнить «я упоминал выше».Кэш L3», а суть того, о чем будет сказано ниже.
Природа циклических зависимостей
Поняв, как Spring обрабатывает циклические зависимости выше, давайте выпрыгнем из "Читать исходный код” подумав, допустим, вам разрешено реализовать функцию со следующими характеристиками, что бы вы сделали?
- Сделать некоторые указанные экземпляры класса одноэлементными
- Поля в классе также инстансируются как синглтоны.
- Поддержка циклических зависимостей
Например, предположим, что есть класс A:
public class A {
private B b;
}
Класс Б:
public class B {
private A a;
}
Грубо говоря, позволю себеМимическая весна:притворяться АиBмодифицируется @Component,
и поля в класседелать видОн модифицируется @Autowired и помещается на карту после обработки.
На самом деле это очень просто, автор написал примерный код для ознакомления:
/**
* 放置创建好的bean Map
*/
private static Map<String, Object> cacheMap = new HashMap<>(2);
public static void main(String[] args) {
// 假装扫描出来的对象
Class[] classes = {A.class, B.class};
// 假装项目初始化实例化所有bean
for (Class aClass : classes) {
getBean(aClass);
}
// check
System.out.println(getBean(B.class).getA() == getBean(A.class));
System.out.println(getBean(A.class).getB() == getBean(B.class));
}
@SneakyThrows
private static <T> T getBean(Class<T> beanClass) {
// 本文用类名小写 简单代替bean的命名规则
String beanName = beanClass.getSimpleName().toLowerCase();
// 如果已经是一个bean,则直接返回
if (cacheMap.containsKey(beanName)) {
return (T) cacheMap.get(beanName);
}
// 将对象本身实例化
Object object = beanClass.getDeclaredConstructor().newInstance();
// 放入缓存
cacheMap.put(beanName, object);
// 把所有字段当成需要注入的bean,创建并注入到当前bean中
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// 获取需要注入字段的class
Class<?> fieldClass = field.getType();
String fieldBeanName = fieldClass.getSimpleName().toLowerCase();
// 如果需要注入的bean,已经在缓存Map中,那么把缓存Map中的值注入到该field即可
// 如果缓存没有 继续创建
field.set(object, cacheMap.containsKey(fieldBeanName)
? cacheMap.get(fieldBeanName) : getBean(fieldClass));
}
// 属性填充完成,返回
return (T) object;
}
Эффект этого кода фактически состоит в том, чтобы иметь дело с циклической зависимостью, и после завершения обработки полный «cacheMap» помещается в cacheMap.Bean"
Это"круговая зависимость", а не "Как Spring разрешает циклические зависимости".
Причина для этого примера состоит в том, чтобы обнаружить, что небольшое количество друзей банка попало в «Трясина чтения исходного кода», забыв при этом суть проблемы.
Для того, чтобы увидеть исходный код, я смотрю исходный код, но все время не могу его понять, но забываю, в чем суть.
Если вы действительно этого не понимаете, лучше сначала написать базовую версию и выяснить, почему Spring реализует ее таким образом, и эффект может быть лучше.
какие? Суть проблемы на самом деле две суммы!
После прочтения кода автора он кажется знакомым? да иtwo sumРешение аналогичное.
понятия не имеюtwo sumЧто это такое, познакомит вас автор:
two sumЭто тематический сайтleetcodeВопрос с порядковым номером 1 — это первый вопрос для большинства людей, начинающих работу с алгоритмами.
часто высмеивают,Алгоритмический аспектКомпания была назначена интервьюером, и она сошлась. тогда собирайтесь вместеtwo sumПройдитесь по движениям.
Содержание вопроса: даномассив,данныйчисло. Возвращаемый массив может бытьДобавить, чтобы получить указанный номердвапоказатель.
Например: даноnums = [2, 7, 11, 15], target = 9
затем вернуться[0, 1]
,так как2 + 7 = 9
Оптимальное решение этой проблемы — один обход + HashMap:
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
}
//作者:LeetCode
//链接:https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-2/
//来源:力扣(LeetCode)
Сначала перейдите на карту, чтобы найтитребуемый номер, если нетекущие номераСохранить на карте, если найдететребуемый номер, а затем вернуться вместе.
Это то же самое, что код выше?
сначала зайди в кешBean, если несоздать экземпляр текущего компонентаПоместите на карту, если необходимополагатьсяТекущий Бин можно получить с Карты.
конец
Если Вы упомянуты выше автором"Застрял в трясине чтения исходного кодаЧитатели, вышеизложенное должно вам помочь.
Могут быть некоторые друзья, у которых есть вопросы, почему они вместе?»two-sum", Spring справляется с такой сложностью?
Подумайте о том, сколько функций поддерживает Spring, различные методы экземпляра... различные методы внедрения... различные загрузка компонентов, проверка... различныеcallback, обработка aop и так далее..
Весна не тольковнедрение зависимости, та же Ява не толькоSpring. Если мы попали в «кончик бычьего рога», мы могли бы выпрыгнуть и посмотреть, может быть, это будет яснее.