精华内容
下载资源
问答
  • 后循环是指什么
    千次阅读
    2021-02-03 13:01:23

    【单选题】__________ sind Sie? Ich bin Studentin.

    【填空题】_______ Internet

    【单选题】()函数可以返回x的整数部分?

    【单选题】_______ kommt sie? Sie kommt aus Beijing.

    【单选题】对于封闭体系来说,当过程的始态与终态确定后,下列各项中哪一个无确定值:

    【填空题】奥地利

    【填空题】欧洲

    【单选题】在等压下,进行一个反应 A + B ® C ,若 ∆ r H m > 0 ,则该反应一定是:

    【填空题】____ Morgen

    【单选题】在一个绝热刚瓶中,发生一个放热的分子数增加的化学反应,那么:

    【单选题】________ ist das? Das ist Frau Euler.

    【单选题】________ Buch auf Englisch Book?

    【单选题】下面代码的执行结果是:

    d = {}

    for i in range(26):

    d[chr(i+ord("a"))] = chr((i+13) % 26 + ord("a"))

    for c in "Python":

    print(d.get(c, c), end="")

    【单选题】关于Python的lambda函数,以下选项中描述错误的是 ( )

    【单选题】Wie geht es Ihnen? Gut, danke. Und _____?

    【单选题】对字符串A="计算机1234"来说,len(A)计算的结果是( )。

    【填空题】____ Heft

    【单选题】x 为状态函数,下列表述中不正确的是:

    【填空题】图中11指的是?

    【单选题】

    【多选题】逆变器可适用于下面哪些领域?

    【单选题】因 Q P = Δ H , Q V = Δ U ,所以 Q P 与 Q V 都是状态函数。

    【填空题】____ Kugelschreiber

    【单选题】对某纯理想气体的任一变温过程,下列关系中正确的是:

    【单选题】使用SELECT语句进行分组检索时,为了去掉不满足条件的分组,应当:

    【单选题】在SELECT 语句中使用“GROUP BY 学号” 时,“学号” 必须出现在哪里?

    【多选题】光伏电站岗位有哪些?

    【单选题】第一次数学课老师让大家下载了( )工具软件

    【单选题】s="一二三四",s.replace("四","五六七")结果是什么?

    【单选题】体系的下列各组物理量中都是状态函数的是:

    【单选题】_______ heißt das auf Deutsch?

    【单选题】关于 Python 的分支结构,以下选项中描述错误的是

    【填空题】____ Kamera

    【单选题】下述说法中,哪一种不正确:

    【单选题】continue语句只结束本次循环。

    【填空题】图中5指的是?

    【单选题】____ wohnen Sie?

    【单选题】

    【单选题】_______ sie aus Frankreich?

    【单选题】理想气体向真空膨胀,当一部分气体进入真空容器后,余下的气体继续膨胀,则气体所做的体积功:

    【单选题】定义函数时,即使该函数不需要接收任何参数,也必须保留一对空的圆括号来表示这是一个函数。

    【单选题】______ ist Ihre Adresse?

    【单选题】一定量的单原子理想气体,从 A 态变化到 B 态,变化过程不知道,但若 A 态 与 B 态两点的压强、体积和温度都已确定,那就可以求出:

    【单选题】while循环属于不确定次数循环。

    【填空题】________ Bleistift

    【单选题】关于Python程序格式框架的描述,错误的是( )

    【单选题】在循环语句中,break语句的作用是提前结束循环。

    【单选题】________ Sie Frau Bauer?

    【单选题】"an apple a day".count("a")的结果是( )。

    【单选题】在Python中,用于获取用户输入的函数是( )

    更多相关内容
  • 什么循环依赖? 顾名思义,循环依赖就是A依赖B,B又依赖A,两者之间的依赖关系形成了一个圆环,通常是由于不正确的编码所导致。Spring只能解决属性循环依赖问题,不能解决构造函数循环依赖问题,因为这个问题无解...

    什么是循环依赖?

    顾名思义,循环依赖就是A依赖B,B又依赖A,两者之间的依赖关系形成了一个圆环,通常是由于不正确的编码所导致。Spring只能解决属性循环依赖问题,不能解决构造函数循环依赖问题,因为这个问题无解。

    接下来我们首先写一个Demo来演示Spring是如何处理属性循环依赖问题的。

    Talk is cheap. Show me the code

    第一步:定义一个类ComponentA,其有一个私有属性componentB。

    package com.tech.ioc;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @author 君战
     * **/
    @Component
    public class ComponentA {
    
    	@Autowired
    	private ComponentB componentB;
    
    	public void say(){
    		componentB.say();
    	}
    
    }
    
    

    第二步:定义一个类ComponentB,其依赖ComponentA。并定义一个say方法便于打印数据。

    package com.tech.ioc;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    /**
     * @author 君战
     * **/
    @Component
    public class ComponentB {
    
    	@Autowired
    	private ComponentA componentA;
    
    	public void say(){
    		System.out.println("componentA field " + componentA);
    		System.out.println(this.getClass().getName() + " -----> say()");
    	}
    
    }
    
    

    第三步:重点,编写一个类-SimpleContainer,模仿Spring底层处理循环依赖。如果理解这个代码,再去看Spring处理循环依赖的逻辑就会很简单。

    package com.tech.ioc;
    
    import java.beans.Introspector;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 演示Spring中循环依赖是如何处理的,只是个简版,真实的Spring依赖处理远比这个复杂。
     * 但大体思路都相同。另外这个Demo很多情况都未考虑,例如线程安全问题,仅供参考。
     * @author 君战
     *
     * **/
    public class SimpleContainer {
    
    	/***
    	 * 用于存放完全初始化好的Bean,Bean处于就绪状态
    	 * 这个Map定义和Spring中一级缓存命名一致
    	 * */
    	private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    
    	/***
    	 * 用于存放刚创建出来的Bean,其属性还没有处理,因此存放在该缓存中的Bean还不可用。
    	 * 这个Map定义和Spring中三级缓存命名一致
    	 * */
    	private final Map<String, Object> singletonFactories = new HashMap<>(16);
    
    
    	public static void main(String[] args) {
    		SimpleContainer container = new SimpleContainer();
    		ComponentA componentA = container.getBean(ComponentA.class);
    		componentA.say();
    	}
    
    	public <T> T getBean(Class<T> beanClass) {
    		String beanName = this.getBeanName(beanClass);
    		// 首先根据beanName从缓存中获取Bean实例
    		Object bean = this.getSingleton(beanName);
    		if (bean == null) {
    			// 如果未获取到Bean实例,则创建Bean实例
    			return createBean(beanClass, beanName);
    		}
    		return (T) bean;
    	}
    	/***
    	 * 从一级缓存和二级缓存中根据beanName来获取Bean实例,可能为空
    	 * */
    	private Object getSingleton(String beanName) {
    		// 首先尝试从一级缓存中获取
    		Object instance = singletonObjects.get(beanName);
    		if (instance == null) { // Spring 之所以能解决循环依赖问题,也是靠着这个三级缓存--singletonFactories
    			instance = singletonFactories.get(beanName);
    		}
    		return instance;
    	}
    
    	/***
    	 * 创建指定Class的实例,返回完全状态的Bean(属性可用)
    	 *
    	 * */
    	private <T> T createBean(Class<T> beanClass, String beanName) {
    		try {
    			Constructor<T> constructor = beanClass.getDeclaredConstructor();
    			T instance = constructor.newInstance();
    			// 先将刚创建好的实例存放到三级缓存中,如果没有这一步,Spring 也无法解决三级缓存
    			singletonFactories.put(beanName, instance);
    			Field[] fields = beanClass.getDeclaredFields();
    			for (Field field : fields) {
    				Class<?> fieldType = field.getType();
    				field.setAccessible(true); 
    				// 精髓是这里又调用了getBean方法,例如正在处理ComponentA.componentB属性,
    				// 执行到这里时就会去实例化ComponentB。因为在getBean方法首先去查缓存,
    				// 而一级缓存和三级缓存中没有ComponentB实例数据,所以又会调用到当前方法,
    				// 而在处理ComponentB.componentA属性时,又去调用getBean方法去缓存中查找,
    				// 因为在前面我们将ComponentA实例放入到了三级缓存,因此可以找到。
    				// 所以ComponentB的实例化结束,方法出栈,返回到实例化ComponentA的方法栈中,
    				// 这时ComponentB已经初始化完成,因此ComponentA.componentB属性赋值成功!
    				field.set(instance, this.getBean(fieldType));
    			}
    			// 最后再将初始化好的Bean设置到一级缓存中。
    			singletonObjects.put(beanName, instance);
    			return instance;
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		throw new IllegalArgumentException();
    	}
    
    	/**
    	 * 将类名小写作为beanName,Spring底层实现和这个差不多,也是使用javaBeans的
    	 * {@linkplain Introspector#decapitalize(String)}
    	 **/
    	private String getBeanName(Class<?> clazz) {
    		String clazzName = clazz.getName();
    		int index = clazzName.lastIndexOf(".");
    		clazzName = clazzName.substring(index);
    		return Introspector.decapitalize(className);
    	}
    }
    

    如果各位同学已经阅读并理解上面的代码,那么接下来我们就进行真实的Spring处理循环依赖问题源码分析,相信再阅读起来就会很容易。

    底层源码分析

    分析从AbstractBeanFactory的doGetBean方法着手。可以看到在该方法首先调用transformedBeanName(其实就是处理BeanName问题),和我们自己写的getBeanName方法作用是一样的,但Spring考虑的远比这个复杂,因为有FactoryBean、别名问题。

    // AbstractBeanFactory#doGetBean
    protected <T> T doGetBean(
    			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    			throws BeansException {
    
    		String beanName = transformedBeanName(name);
    		Object bean;
    
    		// !!!重点是这里,首先从缓存中beanName来获取对应的Bean。
    		Object sharedInstance = getSingleton(beanName);
    		if (sharedInstance != null && args == null) {
    			// 执行到这里说明缓存中存在指定beanName的Bean实例,getObjectForBeanInstance是用来处理获取到的Bean是FactoryBean问题
    			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    		else {
    			try {
    				// 删除与本次分析无关代码....
    				// 如果是单例Bean,则通过调用createBean方法进行创建
    				if (mbd.isSingleton()) {
    					sharedInstance = getSingleton(beanName, () -> {
    						try {
    							return createBean(beanName, mbd, args);
    						} catch (BeansException ex) {
    							destroySingleton(beanName);
    							throw ex;
    						}
    					});
    				
    				}	
    			catch (BeansException ex) {
    				cleanupAfterBeanCreationFailure(beanName);
    				throw ex;
    			}
    		}
    		return (T) bean;
    	}
    

    getSingleton方法存在重载方法,这里调用的是重载的getSingleton方法,注意这里传递的boolean参数值为true,因为该值决定了是否允许曝光早期Bean。

    // DefaultSingletonBeanRegistry#getSingleton
    public Object getSingleton(String beanName) {
    	return getSingleton(beanName, true);
    }
    
    // DefaultSingletonBeanRegistry#getSingleton
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    		// 首先从一级缓存中获取
    		Object singletonObject = this.singletonObjects.get(beanName);
    		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    			// 如果一级缓存中未获取到,再从二级缓存中获取
    			singletonObject = this.earlySingletonObjects.get(beanName);
    			// 如果未从二级缓存中获取到并且allowEarlyReference值为true(前面传的为true)
    			if (singletonObject == null && allowEarlyReference) {
    				synchronized (this.singletonObjects) {
    				   //Double Check 
    					singletonObject = this.singletonObjects.get(beanName);
    					if (singletonObject == null) {
    						singletonObject = this.earlySingletonObjects.get(beanName);
    						if (singletonObject == null) {
    							// 最后尝试去三级缓存中获取
    							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    							if (singletonFactory != null) {
    								singletonObject = singletonFactory.getObject();
    								// 保存到二级缓存
    								this.earlySingletonObjects.put(beanName, singletonObject);
    								// 从三级缓存中移除
    								this.singletonFactories.remove(beanName);
    							}
    						}
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}
    

    ok,看完Spring是如何从缓存中获取Bean实例后,那再看看creatBean方法是如何创建Bean的

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    		throws BeanCreationException {
    	// 删除与本次分析无关的代码...
    	try {// createBean方法底层是通过调用doCreateBean来完成Bean创建的。
    		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    		if (logger.isTraceEnabled()) {
    			logger.trace("Finished creating instance of bean '" + beanName + "'");
    		}
    		return beanInstance;
    	} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
    		throw ex;
    	} catch (Throwable ex) {
    		throw new BeanCreationException(
    				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    	}
    }
    
    // AbstractAutowireCapableBeanFactory#doCreateBean
    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    
    		BeanWrapper instanceWrapper = null;
    		if (mbd.isSingleton()) {
    			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    		}
    		if (instanceWrapper == null) {
    			// 创建Bean实例
    			instanceWrapper = createBeanInstance(beanName, mbd, args);
    		}
    		Object bean = instanceWrapper.getWrappedInstance();
    		// 如果允许当前Bean早期曝光。只要Bean是单例的并且allowCircularReferences 属性为true(默认为true)
    		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    				isSingletonCurrentlyInCreation(beanName));
    		if (earlySingletonExposure) {
    			// 这里调用了addSingletonFactory方法将刚创建好的Bean保存到了三级缓存中。
    			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		}
    
    		// 删除与本次分析无关的代码.....
    		Object exposedObject = bean;
    		try {// Bean属性填充
    			populateBean(beanName, mbd, instanceWrapper);
    			// 初始化Bean,熟知的Aware接口、InitializingBean接口.....都是在这里调用
    			exposedObject = initializeBean(beanName, exposedObject, mbd);
    		} catch (Throwable ex) {
    			
    		}
    		// 删除与本次分析无关的代码.....
    		return exposedObject;
    	}
    

    先分析addSingletonFactory方法,因为在该方法中将Bean保存到了三级缓存中。

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    	Assert.notNull(singletonFactory, "Singleton factory must not be null");
    	synchronized (this.singletonObjects) {
    		// 如果一级缓存中不存在指定beanName的key
    		if (!this.singletonObjects.containsKey(beanName)) {
    			// 将刚创建好的Bean实例保存到三级缓存中
    			this.singletonFactories.put(beanName, singletonFactory);
    			// 从二级缓存中移除。
    			this.earlySingletonObjects.remove(beanName);
    			this.registeredSingletons.add(beanName);
    		}
    	}
    }
    

    处理Bean的依赖注入是由populateBean方法完成的,但整个执行链路太长了,这里就不展开讲了,只说下IoC容器在处理依赖时是如何一步一步调用到getBean方法的,这样就和我们自己写的处理字段注入的逻辑对上了。

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    	// 删除与本次分析无关代码...
    	PropertyDescriptor[] filteredPds = null;
    	if (hasInstAwareBpps) {
    		if (pvs == null) {
    			pvs = mbd.getPropertyValues();
    		}
    		// 遍历所有已注册的BeanPostProcessor接口实现类,如果实现类是InstantiationAwareBeanPostProcessor接口类型的,调用其postProcessProperties方法。
    		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    			if (bp instanceof InstantiationAwareBeanPostProcessor) {
    				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    				// 删除与本次分析无关代码...
    				pvs = pvsToUse;
    			}
    		}
    		// 删除与本次分析无关代码...
    	}
    	
    }
    

    在Spring 中,@Autowired注解是由AutowiredAnnotationBeanPostProcessor类处理,而@Resource注解是由CommonAnnotationBeanPostProcessor类处理,这两个类都实现了InstantiationAwareBeanPostProcessor接口,都是在覆写的postProcessProperties方法中完成了依赖注入。这里我们就分析@Autowired注解的处理。

    // AutowiredAnnotationBeanPostProcessor#postProcessProperties
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    		// 根据beanName以及bean的class去查找Bean的依赖元数据-InjectionMetadata 
    		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    		try {// 调用inject方法
    			metadata.inject(bean, beanName, pvs);
    		} catch (BeanCreationException ex) {
    			throw ex;
    		} catch (Throwable ex) {
    			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    		}
    		return pvs;
    	}
    

    在InjectionMetadata的inject方法中,获取当前Bean所有需要处理的依赖元素(InjectedElement),这是一个集合,遍历该集合,调用每一个依赖注入元素的inject方法。

    // InjectionMetadata#inject
    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    	// 获取当前Bean所有的依赖注入元素(可能是方法,也可能是字段)
    	Collection<InjectedElement> checkedElements = this.checkedElements;
    	Collection<InjectedElement> elementsToIterate =
    			(checkedElements != null ? checkedElements : this.injectedElements);
    	if (!elementsToIterate.isEmpty()) {
    		// 如果当前Bean的依赖注入项不为空,遍历该依赖注入元素
    		for (InjectedElement element : elementsToIterate) {
    			// 调用每一个依赖注入元素的inject方法。
    			element.inject(target, beanName, pvs);
    		}
    	}
    }
    

    在AutowiredAnnotationBeanPostProcessor类中定义了两个内部类-AutowiredFieldElement、AutowiredMethodElement继承自InjectedElement,它们分别对应字段注入和方法注入。

    以大家常用的字段注入为例,在AutowiredFieldElement的inject方法中,首先判断当前字段是否已经被处理过,如果已经被处理过直接走缓存,否则调用BeanFactory的resolveDependency方法来处理依赖。
    // AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    		Field field = (Field) this.member;
    		Object value;
    		if (this.cached) {// 如果当前字段已经被处理过,直接从缓存中获取
    			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    		} else {
    			// 构建依赖描述符
    			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
    			desc.setContainingClass(bean.getClass());
    			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
    			Assert.state(beanFactory != null, "No BeanFactory available");
    			TypeConverter typeConverter = beanFactory.getTypeConverter();
    			try {// 调用BeanFactory的resolveDependency来解析依赖
    				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    			} catch (BeansException ex) {
    				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
    			}
    			// 删除与本次分析无关代码....
    		}
    		if (value != null) {
    			// 通过反射来对属性进行赋值
    			ReflectionUtils.makeAccessible(field);
    			field.set(bean, value);
    		}
    	}
    }
    

    在DefaultListableBeanFactory实现的resolveDependency方法,最终还是调用doResolveDependency方法来完成依赖解析的功能。在Spring源码中,如果存在do什么什么方法,那么该方法才是真正干活的方法。

    // DefaultListableBeanFactory#resolveDependency
    public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    		// .....
    		// 如果在字段(方法)上添加了@Lazy注解,那么在这里将不会真正的去解析依赖
    		Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
    				descriptor, requestingBeanName);
    		if (result == null) {
    			// 如果未添加@Lazy注解,那么则调用doResolveDependency方法来解析依赖
    			result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    		}
    		return result;
    }
    
    // DefaultListableBeanFactory#doResolveDependency
    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
    			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    
    	//.....
    	try {
    		// 根据名称以及类型查找合适的依赖
    		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    		if (matchingBeans.isEmpty()) {// 如果未找到相关依赖
    			if (isRequired(descriptor)) { // 如果该依赖是必须的(例如@Autowired的required属性),直接抛出异常
    				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
    			}
    			return null;
    		}
    
    		String autowiredBeanName;
    		Object instanceCandidate;
    		// 如果查找到的依赖多于一个,例如某个接口存在多个实现类,并且多个实现类都注册到IoC容器中。
    		if (matchingBeans.size() > 1) {// 决定使用哪一个实现类,@Primary等方式都是在这里完成
    			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
    			if (autowiredBeanName == null) {
    				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
    					return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
    				} else { 
    					return null;
    				}
    			}
    			instanceCandidate = matchingBeans.get(autowiredBeanName);
    		} else {
    			// We have exactly one match.
    			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
    			autowiredBeanName = entry.getKey();
    			instanceCandidate = entry.getValue();
    		}
    
    		if (autowiredBeanNames != null) {
    			autowiredBeanNames.add(autowiredBeanName);
    		}
    		// 如果查找到的依赖是某个类的Class(通常如此),而不是实例,
    		//调用描述符的方法来根据类型resolveCandidate方法来获取该类型的实例。
    		if (instanceCandidate instanceof Class) {
    			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    		}
    		//...
    }
    

    在依赖描述符的resolveCandidate方法中,是通过调用BeanFactory 的getBean方法来完成所依赖Bean实例的获取。

    // DependencyDescriptor#resolveCandidate
    public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
    			throws BeansException {
    
    	return beanFactory.getBean(beanName);
    }
    

    而在getBean方法实现中,依然是通过调用doGetBean方法来完成。这也和我们自己写的依赖处理基本一致,只不过我们自己写的比较简单,而Spring要考虑和处理的场景复杂,因此代码比较繁杂,但大体思路都是一样的。

    // AbstractBeanFactory#getBean
    public Object getBean(String name) throws BeansException {
    	return doGetBean(name, null, null, false);
    }
    

    重点是前面我们写的处理循环依赖的Demo,如果理解那个代码,再看Spring的循环依赖处理,就会发现很简单。

    总结

    循环依赖就是指两个Bean之间存在相互引用关系,例如A依赖B,B又依赖A,但Spring只能解决属性循环依赖,不能解决构造函数循环依赖,这种场景也无法解决。

    Spring解决循环依赖的关键就是在处理Bean的属性依赖时,先将Bean存到三级缓存中,当存在循环依赖时,从三级缓存中获取到相关Bean,然后从三级缓存中移除,存入到二级缓存中,最后初始化完毕后存入到一级缓存中。

    展开全文
  • 姐: s->next = p;s->prior = p->prior;p->prior->next = s;p->prior = s

    姐:

    s->next = p;s->prior = p->prior;p->prior->next = s;p->prior = s
    在这里插入图片描述

    展开全文
  • 在双向循环链表中,在p所的结点之后插入s指针所的结点,其操作是( D ) A p->next=s; s->prior=p; p->next->prior=s; s->next=p->next; B s->prior=p; s->next=p->next; p->next...

    题目:

    在双向循环链表中,在p所指的结点之后插入s指针所指的结点,其操作是( D )

     

    A p->next=s; s->prior=p; p->next->prior=s; s->next=p->next;

    B s->prior=p; s->next=p->next; p->next=s; p->next->prior=s;

    C p->next=s; p->next->prior=s; s->prior=p; s->next=p->next;

    D s->prior=p; s->next=p->next; p->next->prior=s; p->next=s;

     

     

     

     

    展开全文
  • Java每日一题——>剑 Offer II 029. 排序的循环链表

    千次阅读 多人点赞 2021-12-20 18:06:45
    如果有多个满足条件的插入位置,可以选择任意一个位置插入新的值,插入整个列表仍然保持有序。 如果列表为空(给定的节点是 null),需要创建一个循环有序列表并返回这个节点。否则。请返回原先给定的节点。 示例 ...
  • 1。...之间 3、保存,点击首页进行预览,不仅仅可以听到背景音乐,如果使用主流浏览器,还能看到标签栏上有背景音乐播放的图标 三、通过以上操作,使网站上能自动循环的背景音乐的操作就完成了
  • 以下可以终结一个循环的保留字是

    千次阅读 2020-12-23 18:01:26
    以下可以终结一个循环的保留字是答:break脂肪动员是:答:脂肪组织中的脂肪水解为脂肪酸和甘油释放入血供其他组织利用在建筑布局上布达拉宫实际上采用的是()教的“曼荼罗”(坛城)模式。答:佛下列选项中,哪些是党...
  • JS事件循环机制

    千次阅读 2022-05-29 13:12:20
    JS事件循环
  • 二、什么循环神经网络RNN 三、什么是递归神经网络RNN 前言: 这是一个很容易混淆的概念,网上充斥了大量混用的情形,在学习RNN之前,我们不妨先做个简单的澄清。 一、什么是RNN NN表示神经网络neural ...
  • 通过break跳出所有循环
  • Spring中的循环依赖

    千次阅读 多人点赞 2022-02-09 13:06:57
    目录一、什么循环依赖?二、Bean的生命周期2.1 Spring Bean 的生命周期2.2 Bean 的生成步骤三、三级缓存3.1三个缓存分别有什么作用四、思路分析4.1 为什么 Spring 中还需要 singletonFactories 呢?五、Spring解决...
  • 当变成循环队列之后,删除元素的空间仍然可以利用,最大限度的利用空间。 判断方式: 1、采用计数器来判断,空时,计数器为0,满时,计数器为maxsize。 2、另设一个布尔变量以匹别队列的空和满。 3、少用一个...
  • js中那么多循环,for for…in for…of forEach,有些循环感觉上是大同小异今天我们讨论下for循环和forEach的差异。我们从几个维度展开讨论:1.for循环和forEach的本质区别。2.for循环和forEach的语法区别。3.for循环...
  • 所谓的循环无关代码(Loop-invariant Code),的是循环中值不变的表达式。 如果能够在不改变程序语义的情况下,将这些循环无关代码提出循环之外,那么程序便可以避免重复执行这些表达式,从而达到性能提升的效果。...
  • 有了for循环什么还要forEach?

    千次阅读 2021-12-25 01:27:01
    大家好,我是 漫步,喜欢记得关注我并设为星标哦。js中那么多循环,for for...in for...of forEach,有些循环感觉上是大同小异今天我们讨论下for循环和forEac...
  • 嵌套循环

    千次阅读 2021-01-20 20:04:21
    嵌套循环 所谓嵌套循环,是一个循环循环体是另一个循环。比如for循环里面还有一个for循环,就是嵌套循环。 **总共的循环次数=外循环次数 * 内循环次数 外层循环执行一次、内层循环执行多次 ** ...
  • nodejs事件和事件循环简介

    万次阅读 2020-12-06 21:37:03
    我们在javascript中监听这些事件,从而触发相应的处理。 同样的nodejs中也有事件,并且还有一个专门的events模块来进行专门的...同时事件和事件循环也是nodejs构建异步IO的非常重要的概念。 今天我们来详细了解一下。
  • 循环淘汰赛什么意思?

    千次阅读 2020-12-22 12:20:46
    在体育比赛中,经常会听到单场淘汰赛、单循环淘汰赛,这是什么意思?单场淘汰赛,在比赛中进行一轮比赛,败北即被淘汰,是一种节省时间但却残酷的竞争方式。单循环淘汰赛是所有参加比赛的队均能相遇一次,最后按各...
  • Offer II 029. 排序的循环链表

    千次阅读 2021-10-11 22:27:33
    如果有多个满足条件的插入位置,可以选择任意一个位置插入新的值,插入整个列表仍然保持有序。 如果列表为空(给定的节点是 null),需要创建一个循环有序列表并返回这个节点。否则。请返回原先给定
  • python中死循环

    千次阅读 2020-11-24 00:16:58
    循环循环重复执行一段代码若干次,为什么要有循环? 因为循环可以避免大量的代码重复。 死循环当一个循环可以执行无限次,也就是没有终止条件,我们称这个循环是死循环。 编写死循环程序实际上是不对的,一旦写...
  • python循环

    万次阅读 2021-07-10 18:33:04
    1. 循环简介 1.1 循环的作用 1.2 循环的分类 2. while循环 2.1 语法 2.2 示例 3. break和continue 3.1示例 3.1.1continue 3.1.1brake 4. while循环嵌套 4.1 语法 4.2 示例 4.3 执⾏流程 4.4 while循环嵌套应⽤ 5. ...
  • Python里while True是什么意思?

    千次阅读 2020-12-17 12:45:02
    while 是循环语句,True 在while 后面表示 while 开始循环的条件如:responses = {}active = Truewhile active:name = input("\nWhat's your name:")response = input('\nWhich mountain would you like to climb ...
  • Python for死循环

    千次阅读 2020-11-24 00:17:02
    循环循环重复执行一段代码若干次,为什么要有循环?因为循环可以避免大量的代码重复。死循环当一个循环可以执行无限次,也就是没有终止条件,我们称这个循环是死循环。编写死循环程序实际上是不对的,一旦写出来...
  • 队列及循环队列为什么用空一个元素的位置

    千次阅读 多人点赞 2020-07-09 10:25:41
    队列,循环队列为什么用空一个元素的位置 队列介绍 1)队列是一个有序列表,可以用数组或是链表表示。 2)遵循先入先出的原则。即:先存入队列的数据,要先取出。存入的要取出。 front及rear分别记录队列前后端...
  • JavaScript for循环 双重循环

    千次阅读 2020-09-21 16:32:21
    for循环 语法结构 for(初始化变量;条件表达式;操作表达式){ //循环体 } 初始化变量: 通常被用于初始化一个计数器,该表达式可以使用var关键字声明新的变量这个变量帮我妈来记录次数。 条件表达式: 用于确定每一次...
  • 理解 Python 的 for 循环

    千次阅读 2020-12-08 17:12:02
    在本篇博客中,我们将讨论 Python 中 for 循环的原理。我们将从一组基本例子和它的语法开始,还将讨论与 for 循环关联的 else 代码块的用处。然后我们将介绍迭代对象、迭代器和迭代器协议,还会学习如何创建自己的...
  • 首先你要确定for和while里面的各个字段分别表示什么含义: Python 中的循环语句有 2 种,分别是 while 循环和 for 循环 for 循环语句的执行流程如图 1 所示。 for 循环语句的执行流程图 图 1 for 循环语句的执行...
  • Spring如何解决循环依赖问题

    万次阅读 多人点赞 2020-12-09 02:23:10
    1、什么循环依赖:类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。 2、循环依赖问题在Spring中主要有三种情况: (1)通过构造方法进行依赖注入时产生的循环依赖问题。 (2)通过setter方法进行...
  • switch&循环语句

    万次阅读 多人点赞 2020-12-22 08:49:26
    水仙花数,的是一个三位数,个位、十位、百位的数字立方和等于原数 例如153 3*3*3 + 5*5*5 + 1*1*1 = 153 思路: 获取所有的三位数,准备进行筛选,最小的三位数为100,最大的三位数为999,使用for循环获取 获取...
  • 在成功的加密项目中,激励循环(Incentive Loops)是很常见的。最棒的加密货币平台或代币通常都内置了鲁棒性(Robust)很好的激励循环(机制)。通过有机增长方式(译者注:Organic growth-有机增长,是一个公司...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 791,338
精华内容 316,535
关键字:

后循环是指什么