精华内容
下载资源
问答
  • 在第一个for循环里定义的k为double型,如果我在下面每一个for循环里都定义一边会报错,如果我只留第一个double定义却能得到正确答案,这什么啊,不是说for循环的定义的变量局部变量么? ![![图片说明]...
  • Python 一个设计优美解释型高级语言,它提供了很多能让程序员感到舒适功能特性。但有时候 Python 一些输出结果对于初学者来说似乎并不是那么一目了然。GitHub 有个仓库收集 Python 中那些难以理解和...

    Python 是一个设计优美的解释型高级语言,它提供了很多能让程序员感到舒适的功能特性。但有的时候 Python 的一些输出结果对于初学者来说似乎并不是那么一目了然。

    GitHub 有个仓库收集 Python 中那些难以理解和鲜为人知的功能特性,并尝试讨论这些现象背后真正的原理!

    虽然有些例子并不一定会让你觉得“卧槽”(WTF),但它们依然有可能会告诉你一些你所不知道的 Python 有趣特性。我觉得这是一种学习编程语言内部原理的好办法,而且我相信你也会从中获得乐趣!

    如果你是一位经验比较丰富的 Python 程序员,你可以尝试挑战看是否能一次就找到例子的正确答案。你可能对其中的一些例子已经比较熟悉了,那这也许能唤起你当年踩这些坑时的甜蜜回忆。

    for 循环怎么会事儿?

    some_string = "wtf"

    some_dict = {}

    for i, some_dict[i] in enumerate(some_string):

    pass

    Output:

    >>> some_dict # 创建了索引字典.

    {0: 'w', 1: 't', 2: 'f'}

    说明:

    Python 语法[1] 中对 for 的定义是:

    for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]

    其中 exprlist 指分配目标. 这意味着对可迭代对象中的每一项都会执行类似 {exprlist} = {next_value} 的操作.

    一个有趣的例子说明了这一点:

    for i in range(4):

    print(i)

    i = 10

    Output:

    0

    1

    2

    3

    你可曾觉得这个循环只会运行一次?

    说明:

    由于循环在Python中工作方式, 赋值语句 i = 10 并不会影响迭代循环, 在每次迭代开始之前, 迭代器(这里指 range(4)) 生成的下一个元素就被解包并赋值给目标列表的变量(这里指 i)了.

    在每一次的迭代中, enumerate(some_string) 函数就生成一个新值 i (计数器增加) 并从 some_string 中获取一个字符. 然后将字典 some_dict 键 i (刚刚分配的) 的值设为该字符. 本例中循环的展开可以简化为:

    >>> i, some_dict[i] = (0, 'w')

    >>> i, some_dict[i] = (1, 't')

    >>> i, some_dict[i] = (2, 'f')

    >>> some_dict

    展开全文
  • 循环定义变量 tempReportInfo ``` public ArrayList<ReportInfo> getAllReportInfos() { ArrayList<ReportInfo> reportInfos = new ...请问一下,为什么循环定义变量tempReportInfo就得到不一样结果呢?
  • 在Java中不光被允许这样: class A { A a; } ...但是,类没有被定义完整确实不能够被实例化!...原因就是类没有被定义完整不能够被实例化,否则我要有A对象做成员,可A我还没有定义完就实例

    在Java中不光被允许这样:

    class A { A a; }

    还被允许这样:

    class A { A a = new A(); }

    但是,类没有被定义完整确实是不能够被实例化的!
    那为什么上面代码被允许?请往下看。
    在C++中,类成员不能是自身的对象。原因就是类没有被定义完整是不能够被实例化的,否则我要有A的对象做成员,可A我还没有定义完就实例,这样岂不是递归下去了...
    所以在C++中你不能这样:
    class A { A a; };

    但却可以这样:
    class A { A *a; //或者A &a;也行 };

    类成员变量只能是自己类对象的指针或者应用
    好,那么我们将构造函数写上,从而使类定义完整(如果不写,编译器也会为我们造一个差不多功能的默认构造器):
    class A { A *a; A():a(new A()) {} };

    好了,或许大家通过以上的代码已经大概了解原因了。在构造函数中,可以对a指针进行初始化,因为此时类已经定义完整(构造函数是在类定义完后才运行的)。
    而在Java中,除了8种基本类型外,其他都是引用类型。所以在Java中这样写:
    A a;
    相当于在C++中这样写:
    A &a;
    所以在A类中保存的只是自己类型对象的引用值。
    而又由于Java比较奇葩的构造方式,也就是可以直接给类成员赋值初始化,而不是通过构造函数。所以可以这样写:
    class A { A a = new A(); //这里不会在类定义时执行,而是等到构造对象时才被执行! }

    所以,上面那样写给人感觉比较乱。还不如在构造函数里写的清楚。所以我讨厌Java!

    注:转载请注明本文地址。

    展开全文
  • Java for循环和定义变量值的问题 ...按道理应该能进入for循环的因为可能进不去,所以先报错了吗。 int sum; for (int i =1 ;i <= 100;i++){ if (i % 2 != 0){ System.out.println(i); sum = i;

    Java for循环和定义变量值的问题

    下面的代码为什么会进不去for循环而导致最后一行
    报错:java: 可能尚未初始化变量sum
    按道理应该是能进入for循环的,是因为可能进不去,所以先报错了吗。

      int sum;
      for (int i =1 ;i <= 100;i++){ 
           if (i % 2 != 0){                				   
               System.out.println(i);
               sum = i;
            }else{
               sum = 1;
            }
      }
      System.out.println(sum); 
    

    而这个就会进入if-else条件句,进而给sum赋值就不会报错

    int sum;
    if (4 % 2 != 0){
        sum = 1;
    }else{
        sum = 2;
    }
    System.out.println(sum);
    
    展开全文
  • 什么是循环依赖? 顾名思义,循环依赖就是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(".");
    		String className = 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,然后从三级缓存中移除,存入到二级缓存中,最后初始化完毕后存入到一级缓存中。

    展开全文
  • python大大的图图片发自简书App我的图图片发自简书App在复杂的程序中很多不同的事件都会导致程序停止运行,如果在循环中要检查这么多变量就会导致循环的编写变得复杂。这时候我们可以定义一个变量用于判断整个程序...
  • 我知道,有些人(譬如之前我)写jsfor循环时,都不习惯加上var,这当然语法允许
  • 在java中退出循环的语句有break和continue两个,但是单独使用break只能退出一个循环,continue终止此循环,回到循环入口。那么,要一次跳出多个循环要怎么办呢?break da /和continue da解决了这个问题,da自己...
  • 今天看书时,看到一个代码,一个在循环外面没有用变量,后即有了我问题,在后面: 我问题: 变量循环定义,例如:...当然这个好像没有意义,那我还有个问题,它们在出了循环是没有用,GC是什么时候清理...
  • Python 变量-循环一、变量不管什么编程语言或脚本语言 在定义变量时都有一定规则。Python变量定义规则如下:变量名只能字母、数字或下划线任意组合变量名第一个字符不能数字关键字不能当变量名,如下:'...
  • 什么是循环依赖?顾名思义,循环依赖就是A依赖B,B又依赖A,两者之间依赖关系形成了一个圆环,通常由于不正确编码所导致。Spring只能解决属性循环依赖问题,不能解决构造函数循环依赖问题,因为这个问题无解。...
  • 笔者最近做了很多应聘笔试题,其中有一个让我印象特备深刻,关于在一个for循环里边些函数运用到for循环里边定义的变量问题,废话不多说,先上代码,大家可以看看这段代码最后结果是什么:vararray=[];//定义一...
  • Python 中的循环语句有 2 种,分别 while 循环和 for 循环 for 循环语句执行流程如图 1 所示。 for 循环语句执行流程图 图 1 for 循环语句执行流程图 如果我们看一下正式Python语法规范,我们可以看到...
  • Java嵌套循环是指在一个循环语句的循环体中再定义一个循环语句语法结构。whiledo.while、for循环语句都可以进行嵌套,并且它们之间也可以互相嵌套,如最常见在for循环中嵌套for循环, Java嵌套循环格式如下:  ...
  • “变量”在大多的数学教科书中变量被认为一个不必定义的概念。...一个变量v的定义如下:设集合T,集合X,谓词合式公式p(t,x)(注:此处的t,x个体变元,不是变量)。 其中符号“:=”表示“定义为”,“...
  • #include<stdio.h> #include<stdlib.h> typedef struct _node{ int value; struct _node *next; }Node; int main(int argc,char const *argv[]){ Node *head=NULL; int number;...}
  • 使用while循环的优点:减少重复工作量、减少源代码、减少错误,提高质量 循环结构定义:循环结构反复执行一系列指令直到某些特定条件满足的基本程序控制结构 循环三要素:循环变量、循环条件、循环体 循环体如果...
  • 什么是本质文件夹 为什么使用包 函数可以使得同一个文件中代码结构更清晰 模块(py文件)以文件形式来组织代码结构 如果文件越来越多管理起来也不方便,所以需要使用文件夹来管理,从文件夹级别来管理代码 ...
  • 大家好,这里先欢迎一下大家...循环初探 循环是什么,这里可以举几个例子。 早上醒来你看到了时钟上秒针渐渐挪过,秒针转完一圈后分针就会移动6°,随后秒针又回到了0点开始下次一旋转,这是一个循环。当分针走...
  • 从小数点后某一位开始依次不断地重复出现前一个或一节数字十进制无限小数,叫做循环小数,如2.9666..., (在数学中它读作“二点九六,六循环” ), 定义循环小数缩写法将第一个循环节以后数字全部略去,并将...
  • 看问题 #define DL_FOREACH_SAFE2(head,el,tmp,next) for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) 为什么是 (tmp = (el)->next, 1);, 这是什么意思,为什么要, 1呢.
  • 关于“不要在循环体内定义变量”

    千次阅读 2007-01-26 08:51:00
    高人来解释一下,为什么有人推荐“不要在循环体内定义变量这帖子已经这么久了,还没结。kypfos(不在寻梦) 回复最能说明问题:循环体外定义变量不会给循环带来任何性能上提高。如果一定要追究性能话,在循环...
  • 就是人们常常问, 为什么总是留在最后一个值? 此处另一种情况. 如果把obj定义在外面, 内部将它push或者赋值到数组中去, 永远都只能存入最后一个obj. var items = data[0].result.value; var list = $(".js...
  • 编译时,反复提示一个类找不到。吾仔细检查文件,肯定包含到了。... 循环包含无法避免。这个时候,就要正确设计各个头文件了。  把独立类放在不同头文件。  如果依赖过多,干脆放在同一个头文件中。 ...
  • 把setTimeout压栈,放入WebApis,setTimeoutWebApis(浏览器定义的),把定时器放入WebApis后过5秒后放入CallBackQueue里面。 执行完第二行代码后,setTimeout 弹栈 dom操作或setTimeout之类都属于WebApis 第三...
  • C++循环变量定义生命周期

    千次阅读 2011-05-03 21:27:00
    C++与C一个最大不同的是C要求所有变量要在最开始就声明,而C++变量信手拈来,你什么时候想用,你就什么时候声明。这个简单细节其实隐含了C与C++设计逻辑有所区别。 C设计时候其实更多为编译器...
  • 展开全部我这里汇总Python经常用到e69da5e887aa62616964757a686964616f3133343362653027个关键字,希望对正在学Python...在Python1.5新增4 break:用在循环语句,跳转到语句块末尾5 class:用来定义一个类6 c...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,860
精华内容 1,144
关键字:

循环的定义是什么