范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Spring解析之finishBeanFactoryInitialization即初始化单例bean

  七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Spring是如何解决循环依赖?
  今天解读Spring核心方法refresh()中最最重要的一个方法finishBeanFactoryInitialization()方法,该方法负责初始化所有的单例bean。
  finishBeanFactoryInitialization()方法位于refresh()中下标为8的位置。
  到目前为止,应该说是是 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经"手动"注册了一些特殊的 Bean,如  environment  、systemProperties   等。
  剩下的就是初始化 singleton beans 了,大多数我们的业务中都是单例bean,就像我们写的@Controller、@Service的类(没有设置懒加载的)都是在这个地方初始化,以供我们使用,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。
  我们先看一下refresh()的源码,大概看下finishBeanFactoryInitialization(beanFactory)所处的位置。 @Override 	public void refresh() throws BeansException, IllegalStateException { 		synchronized (this.startupShutdownMonitor) { 			// Prepare this context for refreshing. 			//1、刷新前的准备 			prepareRefresh();  			// Tell the subclass to refresh the internal bean factory. 			//2、将会初始化 BeanFactory、加载 Bean、注册 Bean 			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  			// Prepare the bean factory for use in this context. 			//3、设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean 			prepareBeanFactory(beanFactory);  			try { 				//4、模板方法 				// Allows post-processing of the bean factory in context subclasses. 				postProcessBeanFactory(beanFactory);  				// Invoke factory processors registered as beans in the context. 				//执行BeanFactory后置处理器 				invokeBeanFactoryPostProcessors(beanFactory);  				// 5、Register bean processors that intercept bean creation. 				//注册bean后置处理器 				registerBeanPostProcessors(beanFactory);  				// Initialize message source for this context. 				//国际化 				initMessageSource();  				// Initialize event multicaster for this context. 				initApplicationEventMulticaster();  				// Initialize other special beans in specific context subclasses. 				//6、模板方法--springboot实现了这个方法 				onRefresh();  				// Check for listener beans and register them. 				//7、注册监听器 				registerListeners();  				// Instantiate all remaining (non-lazy-init) singletons. 				//8、完成bean工厂的初始化**方法重要********************************************** 				finishBeanFactoryInitialization(beanFactory);  				//9、 Last step: publish corresponding event. 				finishRefresh(); 			} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.
  我们深入finishBeanFactoryInitialization(beanFactory)中,里面的调用线路错综复杂,还望读者可以做好心理准备。 /** 	 * 负责单例bean的初始化 	 * Finish the initialization of this context"s bean factory, 	 * initializing all remaining singleton beans. 	 */ 	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { 		// Initialize conversion service for this context. 		//最先初始化名字为 conversionService的类,conversionService类 它用来将前端传过来的参数和后端的 controller 方法上的参数进行绑定的时候用 		//尤其是用于非基础类型的转换 		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && 				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { 			beanFactory.setConversionService( 					//初始化在getBean()方法中实现 					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); 		}  		// Register a default embedded value resolver if no bean post-processor 		// (such as a PropertyPlaceholderConfigurer bean) registered any before: 		// at this point, primarily for resolution in annotation attribute values. 		if (!beanFactory.hasEmbeddedValueResolver()) { 			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); 		}  		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. 		// 先初始化 LoadTimeWeaverAware 类型的 Bean aop相关注:大概有个印象,以后解析aop会和它串起来。 		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); 		for (String weaverAwareName : weaverAwareNames) { 			getBean(weaverAwareName); 		}  		// Stop using the temporary ClassLoader for type matching. 		beanFactory.setTempClassLoader(null);  		// Allow for caching all bean definition metadata, not expecting further changes. 		//freeze的单词意思是冻结,这个时候已经开始预初始化, bean 定义解析、加载、注册先停止 		beanFactory.freezeConfiguration();  		// Instantiate all remaining (non-lazy-init) singletons. 		//开始初始化 		beanFactory.preInstantiateSingletons(); 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.
  该方法是判断bean的一系列是不是属于某个类型的bean,如果是就调用getBean()方法,如果不是,就调用beanFactory.preInstantiateSingletons()进行初始化,我们先把getBean()放一放,重点看一看beanFactory.preInstantiateSingletons()方法。 @Override 	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. 		// this.beanDefinitionNames 保存了所有的 beanNames  		List beanNames = new ArrayList<>(this.beanDefinitionNames);  		// Trigger initialization of all non-lazy singleton beans... 		//// 下面这个循环,触发所有的非懒加载的 singleton beans 的初始化操作 		for (String beanName : beanNames) { 			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 			// 非抽象、非懒加载的 singletons。如果配置了 "abstract = true",那是不需要初始化的 			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 				// 处理 FactoryBean (负责初始化工厂的bean) 				if (isFactoryBean(beanName)) { 					// FactoryBean 的话,在 beanName 前面加上 ‘&’ 符号 					//此处调用getBean()方法 					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); 					if (bean instanceof FactoryBean) { 						FactoryBean<?> factory = (FactoryBean<?>) bean; 						// 判断当前 FactoryBean 是否是 SmartFactoryBean 的实现 						boolean isEagerInit; 						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 							isEagerInit = AccessController.doPrivileged( 									(PrivilegedAction) ((SmartFactoryBean<?>) factory)::isEagerInit, 									getAccessControlContext()); 						} 						else { 							isEagerInit = (factory instanceof SmartFactoryBean && 									((SmartFactoryBean<?>) factory).isEagerInit()); 						} 						if (isEagerInit) { 							getBean(beanName); 						} 					} 				} 				else { 					// 对于普通的 Bean,只要调用 getBean(beanName) 这个方法就可以进行初始化了 					getBean(beanName); 				} 			} 		}  		// Trigger post-initialization callback for all applicable beans... 		// 到这里说明所有的非懒加载的 singleton beans 已经完成了初始化 		// 如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的,那么在这里得到回调 		//如果你想在单例bean初始化后做一些事 那就实现该接口 		for (String beanName : beanNames) { 			Object singletonInstance = getSingleton(beanName); 			if (singletonInstance instanceof SmartInitializingSingleton) { 				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; 				if (System.getSecurityManager() != null) { 					AccessController.doPrivileged((PrivilegedAction) () -> { 						smartSingleton.afterSingletonsInstantiated(); 						return null; 					}, getAccessControlContext()); 				} 				else { 					smartSingleton.afterSingletonsInstantiated(); 				} 			} 		} 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.
  preInstantiateSingletons()方法的主要任务是进行初始化的,在初始化前同样是一系列判断,如,是否是懒加载的,是否是一个factorybean(一个特别的bean,负责工厂创建的bean),最后调用getBean()方法。
  其中有个插曲是否实现了SmartInitializingSingleton接口,将接口让你可以在bean初始化后做一些事,我们写一个简单的实例测试一下。
  其他地方读者看注释了解一下即可,我们开始继续深入getBean()方法。
  getBean()方法内部调用了doGetBean()我们直接看doGetBean方法。 	 	// 我们在剖析初始化 Bean 的过程,但是 getBean 方法我们经常是用来从容器中获取 Bean 用的,注意切换思路, 	// 已经初始化过了就从容器中直接返回,否则就先初始化再返回 	protected  T doGetBean( 			String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) 			throws BeansException {  		// 获取一个 "正统的" beanName,处理两种情况,一个是前面说的 FactoryBean(前面带 ‘&’), 		// 一个是别名问题,因为这个方法是 getBean,获取 Bean 用的,你要是传一个别名进来,是完全可以的 		String beanName = transformedBeanName(name); 		// 返回值 		Object bean;  		// Eagerly check singleton cache for manually registered singletons. 		// 检查下是不是已经创建过了 		Object sharedInstance = getSingleton(beanName); 		// 这里说下 args ,虽然看上去一点不重要。前面我们一路进来的时候都是 getBean(beanName), 		// 所以 args 传参其实是 null 的,但是如果 args 不为空的时候,那么意味着调用方不是希望获取 Bean,而是创建 Bean 		if (sharedInstance != null && args == null) { 			if (logger.isTraceEnabled()) { 				if (isSingletonCurrentlyInCreation(beanName)) { 					logger.trace("Returning eagerly cached instance of singleton bean "" + beanName + 							"" that is not fully initialized yet - a consequence of a circular reference"); 				} 				else { 					logger.trace("Returning cached instance of singleton bean "" + beanName + """); 				} 			} 			// 下面这个方法:如果是普通 Bean 的话,直接返回 sharedInstance, 			// 如果是 FactoryBean 的话,返回它创建的那个实例对象 			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 		}  		else { 			// Fail if we"re already creating this bean instance: 			// We"re assumably within a circular reference. 			// 创建过了此 beanName 的 prototype 类型的 bean,那么抛异常, 			// 往往是因为陷入了循环引用 哦,原来之前的循环依赖都是在这抛的异常,再有问题就不是无头苍蝇了 			if (isPrototypeCurrentlyInCreation(beanName)) { 				throw new BeanCurrentlyInCreationException(beanName); 			}  			// Check if bean definition exists in this factory. 			// 检查一下这个 BeanDefinition 在容器中是否存在 BeanDefinition既是包含了bean的一系列信息 			BeanFactory parentBeanFactory = getParentBeanFactory(); 			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 				// Not found -> check parent. 				// 如果当前容器不存在这个 BeanDefinition,试试父容器中有没有 				String nameToLookup = originalBeanName(name); 				if (parentBeanFactory instanceof AbstractBeanFactory) { 					return ((AbstractBeanFactory) parentBeanFactory).doGetBean( 							nameToLookup, requiredType, args, typeCheckOnly); 				} 				else if (args != null) { 					// Delegation to parent with explicit args. 					// 返回父容器的查询结果 					return (T) parentBeanFactory.getBean(nameToLookup, args); 				} 				else if (requiredType != null) { 					// No args -> delegate to standard getBean method. 					return parentBeanFactory.getBean(nameToLookup, requiredType); 				} 				else { 					return (T) parentBeanFactory.getBean(nameToLookup); 				} 			}  			if (!typeCheckOnly) { 				// typeCheckOnly 为 false,将当前 beanName 放入一个 alreadyCreated 的 Set 集合中。 				markBeanAsCreated(beanName); 			}  			/* 			 * 稍稍总结一下: 			 * 到这里的话,要准备创建 Bean 了,对于 singleton 的 Bean 来说,容器中还没创建过此 Bean; 			 * 对于 prototype 的 Bean 来说,本来就是要创建一个新的 Bean。 			 */ 			try { 				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 				checkMergedBeanDefinition(mbd, beanName, args);  				// Guarantee initialization of beans that the current bean depends on. 				// 先初始化依赖的所有 Bean,这个很好理解。 				// 注意,这里的依赖指的是 depends-on 中定义的依赖 				String[] dependsOn = mbd.getDependsOn(); 				if (dependsOn != null) { 					for (String dep : dependsOn) { 						// 检查是不是有循环依赖,这里的循环依赖和我们前面说的循环依赖又不一样 						if (isDependent(beanName, dep)) { 							throw new BeanCreationException(mbd.getResourceDescription(), beanName, 									"Circular depends-on relationship between "" + beanName + "" and "" + dep + """); 						} 						// 注册一下依赖关系 						registerDependentBean(dep, beanName); 						try { 							// 先初始化被依赖项 							getBean(dep); 						} 						catch (NoSuchBeanDefinitionException ex) { 							throw new BeanCreationException(mbd.getResourceDescription(), beanName, 									""" + beanName + "" depends on missing bean "" + dep + """, ex); 						} 					} 				}  				// Create bean instance. 				// 如果是 singleton scope 的,创建 singleton 的实例 				if (mbd.isSingleton()) { 					sharedInstance = getSingleton(beanName, () -> { 						try { 							// 执行创建 Bean,详情继续深入 							// 第三个参数 args 数组代表创建实例需要的参数,不就是给构造方法用的参数,或者是工厂 Bean 的参数嘛,不过要注意,在我们的初始化阶段,args 是 null。 							// 这回我们要到一个新的类了 AbstractAutowireCapableBeanFactory,看类名,AutowireCapable?类名是不是也说明了点问题了。 							// 主要是为了以下场景,采用 @Autowired 注解注入属性值: 							return createBean(beanName, mbd, args); 						} 						catch (BeansException ex) { 							// Explicitly remove instance from singleton cache: It might have been put there 							// eagerly by the creation process, to allow for circular reference resolution. 							// Also remove any beans that received a temporary reference to the bean. 							destroySingleton(beanName); 							throw ex; 						} 					}); 					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 				} 				// 如果是 prototype scope 的,创建 prototype 的实例 				else if (mbd.isPrototype()) { 					// It"s a prototype -> create a new instance. 					Object prototypeInstance = null; 					try { 						beforePrototypeCreation(beanName); 						// 执行创建 Bean 						prototypeInstance = createBean(beanName, mbd, args); 					} 					finally { 						afterPrototypeCreation(beanName); 					} 					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 				}  				else { 					String scopeName = mbd.getScope(); 					if (!StringUtils.hasLength(scopeName)) { 						throw new IllegalStateException("No scope name defined for bean  " + beanName + """); 					} 					Scope scope = this.scopes.get(scopeName); 					if (scope == null) { 						throw new IllegalStateException("No Scope registered for scope name "" + scopeName + """); 					} 					try { 						Object scopedInstance = scope.get(beanName, () -> { 							beforePrototypeCreation(beanName); 							try { 								return createBean(beanName, mbd, args); 							} 							finally { 								afterPrototypeCreation(beanName); 							} 						}); 						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 					} 					catch (IllegalStateException ex) { 						throw new BeanCreationException(beanName, 								"Scope "" + scopeName + "" is not active for the current thread; consider " + 								"defining a scoped proxy for this bean if you intend to refer to it from a singleton", 								ex); 					} 				} 			} 			catch (BeansException ex) { 				cleanupAfterBeanCreationFailure(beanName); 				throw ex; 			} 		}  		// Check if required type matches the type of the actual bean instance. 		// 最后,检查一下类型对不对,不对的话就抛异常,对的话就返回了 		if (requiredType != null && !requiredType.isInstance(bean)) { 			try { 				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); 				if (convertedBean == null) { 					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 				} 				return convertedBean; 			} 			catch (TypeMismatchException ex) { 				if (logger.isTraceEnabled()) { 					logger.trace("Failed to convert bean "" + name + "" to required type "" + 							ClassUtils.getQualifiedName(requiredType) + """, ex); 				} 				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 			} 		} 		return (T) bean; 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.
  具体的实例化过程在createBean()方法中,我们继续深入createBean()方法。 @Override 	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 			throws BeanCreationException {  		if (logger.isTraceEnabled()) { 			logger.trace("Creating instance of bean "" + beanName + """); 		} 		RootBeanDefinition mbdToUse = mbd;  		// Make sure bean class is actually resolved at this point, and 		// clone the bean definition in case of a dynamically resolved Class 		// which cannot be stored in the shared merged bean definition. 		// 确保 BeanDefinition 中的 Class 被加载 		Class<?> resolvedClass = resolveBeanClass(mbd, beanName); 		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { 			mbdToUse = new RootBeanDefinition(mbd); 			mbdToUse.setBeanClass(resolvedClass); 		}  		// Prepare method overrides. 		// 准备方法覆写,这里又涉及到一个概念:MethodOverrides,它来自于 bean 定义中的  		// 和 ,如果读者感兴趣,回到 bean 解析的地方看看对这两个标签的解析。 		try { 			mbdToUse.prepareMethodOverrides(); 		} 		catch (BeanDefinitionValidationException ex) { 			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), 					beanName, "Validation of method overrides failed", ex); 		}  		try { 			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 			// 让 InstantiationAwareBeanPostProcessor 在这一步有机会返回代理, 			// 在 《Spring AOP 源码分析》那篇文章中有解释,这里先跳过 			Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 			if (bean != null) { 				return bean; 			} 		} 		catch (Throwable ex) { 			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, 					"BeanPostProcessor before instantiation of bean failed", ex); 		}  		try { 			// 重头戏,创建 bean 			Object beanInstance = doCreateBean(beanName, mbdToUse, args); 			if (logger.isTraceEnabled()) { 				logger.trace("Finished creating instance of bean "" + beanName + """); 			} 			return beanInstance; 		} 		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { 			// A previously detected exception with proper bean creation context already, 			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. 			throw ex; 		} 		catch (Throwable ex) { 			throw new BeanCreationException( 					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); 		} 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.
  我们继续往里看 doCreateBean 这个方法,这个调用过程是真的深。 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 			throws BeanCreationException {  		// Instantiate the bean. 		BeanWrapper instanceWrapper = null; 		if (mbd.isSingleton()) { 			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 		} 		if (instanceWrapper == null) { 			// 说明不是 FactoryBean,这里实例化 Bean,这里非常关键,细节之后再说********** 			instanceWrapper = createBeanInstance(beanName, mbd, args); 		} 		Object bean = instanceWrapper.getWrappedInstance(); 		Class<?> beanType = instanceWrapper.getWrappedClass(); 		if (beanType != NullBean.class) { 			mbd.resolvedTargetType = beanType; 		}  		// Allow post-processors to modify the merged bean definition. 		synchronized (mbd.postProcessingLock) { 			if (!mbd.postProcessed) { 				try { 					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 				} 				catch (Throwable ex) { 					throw new BeanCreationException(mbd.getResourceDescription(), beanName, 							"Post-processing of merged bean definition failed", ex); 				} 				mbd.postProcessed = true; 			} 		}  		// Eagerly cache singletons to be able to resolve circular references 		// even when triggered by lifecycle interfaces like BeanFactoryAware. 		// 下面这块代码是为了解决循环依赖的问题,这是个重头戏,解决循环依赖问题 		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 				isSingletonCurrentlyInCreation(beanName)); 		if (earlySingletonExposure) { 			if (logger.isTraceEnabled()) { 				logger.trace("Eagerly caching bean "" + beanName + 						"" to allow for resolving potential circular references"); 			} 			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 		}  		// Initialize the bean instance. 		Object exposedObject = bean; 		try { 			// 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值*************** 			populateBean(beanName, mbd, instanceWrapper); 			// 还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口? 			// 这里就是处理 bean 初始化完成后的各种回调************** 			exposedObject = initializeBean(beanName, exposedObject, mbd); 		} 		catch (Throwable ex) { 			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { 				throw (BeanCreationException) ex; 			} 			else { 				throw new BeanCreationException( 						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); 			} 		} 	// 下面这块代码是为了解决循环依赖的问题,这是个重头戏,解决循环依赖问题	 		if (earlySingletonExposure) { 				//循环依赖的核心方法调用 			Object earlySingletonReference = getSingleton(beanName, false); 			if (earlySingletonReference != null) { 				if (exposedObject == bean) { 					exposedObject = earlySingletonReference; 				} 				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { 					String[] dependentBeans = getDependentBeans(beanName); 					Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); 					for (String dependentBean : dependentBeans) { 						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { 							actualDependentBeans.add(dependentBean); 						} 					} 					if (!actualDependentBeans.isEmpty()) { 						throw new BeanCurrentlyInCreationException(beanName, 								"Bean with name "" + beanName + "" has been injected into other beans [" + 								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + 								"] in its raw version as part of a circular reference, but has eventually been " + 								"wrapped. This means that said other beans do not use the final version of the " + 								"bean. This is often the result of over-eager type matching - consider using " + 								""getBeanNamesForType" with the "allowEagerInit" flag turned off, for example."); 					} 				} 			} 		}  		// Register bean as disposable. 		try { 			registerDisposableBeanIfNecessary(beanName, bean, mbd); 		} 		catch (BeanDefinitionValidationException ex) { 			throw new BeanCreationException( 					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); 		}  		return exposedObject; 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.
  到这里,我们已经分析完了 doCreateBean 方法,总的来说,我们已经说完了整个初始化流程。
  在实例化bean后有一个特别重要的知识点,也是面试中最常问的,Spring怎么解决循环依赖问题?核心代码就在这个方法里面。
  循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
  doCreateBean 方法有三个核心流程。
  (1)createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
  (2)populateBean:填充属性,这一步主要是多bean的依赖属性进行填充
  (3)initializeBean:调用spring xml中的init 方法。
  从上面讲述的单例bean初始化步骤我们可以知道,循环依赖主要发生在第一、第二步。也就是构造器循环依赖和field循环依赖。
  那么我们要解决循环引用也应该从初始化过程着手,对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。
  我们看一下getSingleton方法。
  该方法还依赖于三个map,这三个map就是三级缓存。 /** Cache of singleton objects: bean name to bean instance. */ //单例对象的cache private final Map singletonObjects = new ConcurrentHashMap<>(256);  /** Cache of singleton factories: bean name to ObjectFactory. */ // 单例对象工厂的cache private final Map> singletonFactories = new HashMap<>(16);  /** Cache of early singleton objects: bean name to bean instance. */ //提前曝光的单例对象的Cache private final Map earlySingletonObjects = new ConcurrentHashMap<>(16); 1.2.3.4.5.6.7.8.9.10.11.@Nullable 	protected Object getSingleton(String beanName, boolean allowEarlyReference) { 		// Quick check for existing instance without full singleton lock 		Object singletonObject = this.singletonObjects.get(beanName); 		 		//判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象 		// 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。 		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 			singletonObject = this.earlySingletonObjects.get(beanName); 			 			// 是否允许从singletonFactories中通过getObject拿到对象 			if (singletonObject == null && allowEarlyReference) { 				synchronized (this.singletonObjects) { 					// Consistent creation of early reference within full singleton lock 					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; 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.
  分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。
  如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则: this.earlySingletonObjects.put(beanName, singletonObject);                         this.singletonFactories.remove(beanName);                          1.2.3.
  从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存。
  从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。
  里就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。
  这样做有什么好处呢?
  让我们来分析一下"A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象"这种循环依赖的情况。
  A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。
  此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。
  知道了这个原理时候,肯定就知道为啥Spring不能解决"A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象"这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
  接下来我们挑 doCreateBean 中的三个细节出来说说。一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。
  这三个方法也是极其复杂的,读者有兴趣可以继续的深入进去。
  1、 createBeanInstance 方法 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { 		// Make sure bean class is actually resolved at this point. 		// 确保已经加载了此 class 		Class<?> beanClass = resolveBeanClass(mbd, beanName);  		// 校验一下这个类的访问权限 		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { 			throw new BeanCreationException(mbd.getResourceDescription(), beanName, 					"Bean class isn"t public, and non-public access not allowed: " + beanClass.getName()); 		}  		Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); 		if (instanceSupplier != null) { 			return obtainFromSupplier(instanceSupplier, beanName); 		}  		if (mbd.getFactoryMethodName() != null) { 			// 采用工厂方法实例化,不熟悉这个概念的读者请看附录,注意,不是 FactoryBean 			return instantiateUsingFactoryMethod(beanName, mbd, args); 		}  		// Shortcut when re-creating the same bean... 		// 如果不是第一次创建,比如第二次创建 prototype bean。 		// 这种情况下,我们可以从第一次创建知道,采用无参构造函数,还是构造函数依赖注入 来完成实例化 		boolean resolved = false; 		boolean autowireNecessary = false; 		if (args == null) { 			synchronized (mbd.constructorArgumentLock) { 				if (mbd.resolvedConstructorOrFactoryMethod != null) { 					resolved = true; 					autowireNecessary = mbd.constructorArgumentsResolved; 				} 			} 		} 		if (resolved) { 			if (autowireNecessary) { 				// 构造函数依赖注入 				return autowireConstructor(beanName, mbd, null, null); 			} 			else { 				// 无参构造函数 				return instantiateBean(beanName, mbd); 			} 		}  		// Candidate constructors for autowiring? 		// 判断是否采用有参构造函数 		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); 		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || 				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { 			// 构造函数依赖注入 			return autowireConstructor(beanName, mbd, ctors, args); 		}  		// Preferred constructors for default construction? 		ctors = mbd.getPreferredConstructors(); 		if (ctors != null) { 			// 构造函数依赖注入 			return autowireConstructor(beanName, mbd, ctors, null); 		}  		// No special handling: simply use no-arg constructor. 		// 调用无参构造函数 		return instantiateBean(beanName, mbd); 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.
  看一下instantiateBean方法是怎么做的。 protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { 		try { 			Object beanInstance; 			if (System.getSecurityManager() != null) { 				beanInstance = AccessController.doPrivileged( 						(PrivilegedAction) () -> getInstantiationStrategy().instantiate(mbd, beanName, this), 						getAccessControlContext()); 			} 			else { 				// 实例化 				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); 			} 			// 包装一下,返回 			BeanWrapper bw = new BeanWrapperImpl(beanInstance); 			initBeanWrapper(bw); 			return bw; 		} 		catch (Throwable ex) { 			throw new BeanCreationException( 					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); 		} 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.
  我们可以看到,关键的地方在于:beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
  里面是具体是实例化过程,我们进去看看。 @Override 	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { 		// Don"t override the class with CGLIB if no overrides. 		// 如果不存在方法覆写,那就使用 java 反射进行实例化,否则使用 CGLIB, 		// 方法覆写 请参见附录"方法注入"中对 lookup-method 和 replaced-method 的介绍 		if (!bd.hasMethodOverrides()) { 			Constructor<?> constructorToUse; 			synchronized (bd.constructorArgumentLock) { 				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; 				if (constructorToUse == null) { 					final Class<?> clazz = bd.getBeanClass(); 					if (clazz.isInterface()) { 						throw new BeanInstantiationException(clazz, "Specified class is an interface"); 					} 					try { 						if (System.getSecurityManager() != null) { 							constructorToUse = AccessController.doPrivileged( 									(PrivilegedExceptionAction>) clazz::getDeclaredConstructor); 						} 						else { 							constructorToUse = clazz.getDeclaredConstructor(); 						} 						bd.resolvedConstructorOrFactoryMethod = constructorToUse; 					} 					catch (Throwable ex) { 						throw new BeanInstantiationException(clazz, "No default constructor found", ex); 					} 				} 			} 			// 利用构造方法进行实例化 			return BeanUtils.instantiateClass(constructorToUse); 		} 		else { 			// Must generate CGLIB subclass. 			// 存在方法覆写,利用 CGLIB 来完成实例化,需要依赖于 CGLIB 生成子类,这里就不展开了。 			// tips: 因为如果不使用 CGLIB 的话,存在 override 的情况 JDK 并没有提供相应的实例化支持 			return instantiateWithMethodInjection(bd, beanName, owner); 		} 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.
  到这里,我们就算实例化完成了。我们开始说怎么进行属性注入。
  2、populateBean 方法 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { 		if (bw == null) { 			if (mbd.hasPropertyValues()) { 				throw new BeanCreationException( 						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); 			} 			else { 				// Skip property population phase for null instance. 				return; 			} 		}  		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the 		// state of the bean before properties are set. This can be used, for example, 		// to support styles of field injection. 		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 			for (BeanPostProcessor bp : getBeanPostProcessors()) { 				if (bp instanceof InstantiationAwareBeanPostProcessor) { 					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { 						return; 					} 				} 			} 		}  		// bean 实例的所有属性都在这里了 		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);  		int resolvedAutowireMode = mbd.getResolvedAutowireMode(); 		// 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系 		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { 			MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 			// Add property values based on autowire by name if applicable. 			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { 				autowireByName(beanName, mbd, bw, newPvs); 			} 			// Add property values based on autowire by type if applicable. 			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { 				autowireByType(beanName, mbd, bw, newPvs); 			} 			pvs = newPvs; 		}  		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); 		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);  		PropertyDescriptor[] filteredPds = null; 		if (hasInstAwareBpps) { 			if (pvs == null) { 				pvs = mbd.getPropertyValues(); 			} 			for (BeanPostProcessor bp : getBeanPostProcessors()) { 				if (bp instanceof InstantiationAwareBeanPostProcessor) { 					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); 					if (pvsToUse == null) { 						if (filteredPds == null) { 							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); 						} 						// 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor 						// 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的 						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 						if (pvsToUse == null) { 							return; 						} 					} 					pvs = pvsToUse; 				} 			} 		} 		if (needsDepCheck) { 			if (filteredPds == null) { 				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); 			} 			checkDependencies(beanName, mbd, filteredPds, pvs); 		}  		if (pvs != null) { 			// 设置 bean 实例的属性值 			applyPropertyValues(beanName, mbd, bw, pvs); 		} 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.
  属性注入完成后,这一步其实就是处理各种回调了,这块代码比较简单。
  3、 initializeBean方法 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { 		if (System.getSecurityManager() != null) { 			AccessController.doPrivileged((PrivilegedAction) () -> { 				invokeAwareMethods(beanName, bean); 				return null; 			}, getAccessControlContext()); 		} 		else { 			// 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调 			invokeAwareMethods(beanName, bean); 		}  		Object wrappedBean = bean; 		if (mbd == null || !mbd.isSynthetic()) { 			// BeanPostProcessor 的 postProcessBeforeInitialization 回调 			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 		}  		try { 			// 处理 bean 中定义的 init-method, 			// 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法 			invokeInitMethods(beanName, wrappedBean, mbd); 		} 		catch (Throwable ex) { 			throw new BeanCreationException( 					(mbd != null ? mbd.getResourceDescription() : null), 					beanName, "Invocation of init method failed", ex); 		} 		if (mbd == null || !mbd.isSynthetic()) { 			// BeanPostProcessor 的 postProcessAfterInitialization 回调 			//BeanPostProcessor 的两个回调都发生在这边,只不过中间处理了 init-method 			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 		}  		return wrappedBean; 	} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.
  自此,Spring实例化单例非懒加载bean的过程也就完成了,这也是Spirng最最重要的方法了。在我们的日常使用Spring中,定义好各个类,然后在上面加上,@Controller,@Service,Autowired等注解,这些注解是怎么起作用的呢?
  想必大部分同学都是知其然,不知其所以然,想必通过本文,读者心中能有一个清楚的认识。
如何分别电脑前情提要该文章前一部分是我从我自己好几个月前的帖子中截出来的,会做一些补充,不在那个帖子继续是因为会被当成坟贴被删。鸽了大家这么久是时候做个总结了(滑稽)本篇文章的内容分布我会在这Libra彻底破产?扎克伯格挑战主权货币完败在美国监管的重压下,扎克伯格雄心勃勃的扎克美元正被彻底瓦解。据彭博社,由Meta(原Facebook)公司支持的Diem加密货币协会(原Libra)正在考虑打包出售其相关资产,以退比亚迪新能源汽车即将涨价,最后几天抓住机会哦比亚迪汽车发布了关于车型价格调整的说明。为了缓解上游原材料大幅上涨以及2022年新能源补贴退坡(在2021年基础上退坡30)的压力,说明确实成本有压力,尤其是2021年原材料涨那么SK海力士计划今年将NAND出货量增加一倍品玩1月30日讯,据市场消息,SK海力士日前表示,公司完成收购英特尔NAND事业的第一阶段后,预计NAND的出货量增加到一倍。SK海力士预计,这笔90亿美元的交易将帮助其吸收英特尔极目锐评春节不打烊成了伪命题,服务做不到就别喊口号极目新闻评论员屈旌快递行业春节不打烊的新闻,曾经在春节前刷了屏,不少人都表示很方便,很感谢。然而,春节期间,不少消费者在网上抱怨称,自己的包裹在春节前就显示已发出,但春节快过完了也TMT时报软银发布三季报,孙正义近期无减持阿里巴巴意愿微信春节发出封面红包50亿个特斯拉对中国产车型减配科创板日报2月8日讯,今日财联社TMT要闻精选有软银发布三季报,孙正义近期无减持阿里巴巴意愿微信2022春节期间带封面的红包收发超50亿个特斯拉对中国产车型减配,工程师认为被移除部美的造芯野望试图在家电汽车领域绝地反击?文螳螂观察作者叶小安连续拿下家电行业第一的美的正大步向前,不断在汽车芯片等领域多元化布局,扩展业务边界。据证券时报报道,1月10日,美的集团在互动平台表示,2018年下半年美的进入富邦股份(300387)数字乡村农村电商,大农业,大数据概念股富邦股份是国内及国际肥料助剂领域龙头企业,在该领域申请的专利和授权的专利处于全球领先地位。去年以来公司向非洲企业转让专有技术收入超亿元。近年来,公司始终聚焦与布局数字农业,坚持用数隆盛科技2021年预计净利9500万104。96新能源汽车产销量增长挖贝网1月26日,隆盛科技(300680)近日发布2021年度业绩预告,预计业绩同向上升。报告期内归属于上市公司股东的净利润9,500万元11,000万元,比上年同期增长77。01第三代比亚迪F3延续经典,无钥匙进入,百公里油耗5。9L,4。49万起如今汽车市场上各个品牌争相发力,技术水平不断提高,我们的国产品牌实力提升显著,已经有不少品牌和车型具有世界领先水平。不过国产品牌的技术提高后,也没有放弃曾经经典的车型,比如比亚迪,新能源汽车迎新年开门红销量增速反超燃油车本报记者黄琳赵毅深圳报道2022年新春伊始,新能源汽车赛道持续火热。不同于传统车企,聚焦新能源汽车的整车厂已迫不及待发布1月取得的销量成绩。据中国经营报记者不完全统计,华南区域包括
全球最挣钱的十大开源公司自从Hadoop生态发展以来,基于开源软件提供服务的盈利公司也越来越多。大家这才发现,开源不仅不会削弱企业竞争力,还可以带来生态,增强企业的竞争力。本文总结全球最挣钱的十大开源公司大厂也难逃困境想要的找不到,找到的招不来,招来的留不住前几天见到老A,一个颇具规模的互联网公司老板,事业风生水起。可是,他很焦虑,见面第一句话就是我需要人才!原来,三个月前,公司战略调整,急需招聘几个算法工程师和硬件工程师,老A提出要电商平台入驻后,营业执照还有什么用?众所周知,如今大多数电商平台入驻时都需要营业执照,尤其是年交易额超10万的商家,更是被电商法明文规定需要办理营业执照。虽然办理时可以在网商云谷在线办理,后续的税务登记银行开户也有专TikTok被禁一年后,印度短视频市场怎么样了?在去年6月中国应用程序被印度政府封禁的那场风波中,字节跳动旗下的TikTok也未能幸免,首当其冲地成为了这场风波中的牺牲品。而在那之前,TikTok曾是印度最火的短视频平台,其总下终于醒悟了?国产科技巨头集体抵制高通,华为不是孤军奋战自从华为海思被限制后,芯片业务暂时停止。而剩下的市场,则肯定会有其他公司进行填补,这其中,高通就是受益者之一,理论上应该可以拿下很大一部分剩下的手机芯片市场,可事实的发展,好像并不业绩大增6倍,却严重跑输宁德时代,赣锋锂业靠什么来翻盘?特斯拉又双叒叕创新高了!美国时间11月1日,电动车之王特斯拉再度大涨8。49,股价突破1200美元股,总市值来到1。21万亿美元。这让马斯克在全球首富的地位上愈发稳固,他把贝索斯比魅族17Pro还可以买吗?大家好我是甜童,昨天有个粉丝问我魅族17Pro现在还可以吗?今天就来好好的聊聊魅族17Pro,甜童说机areyouready。说起魅族甜童真的有说不完的话,我初中用的第一部手机就是数据驱动业务指数级增长的意义Ifyouarenotgrowing,thenyouaredying!(如果企业不在增长,那么就是在衰亡!)一句名言,道出了增长这一企业运营永恒的真理。无论是上市企业,还是创业公司快手宿华30多岁要过半退休生活?互联网CEO们又双叒叕辞任,都太年轻,青春之经难念来源塔木德富豪会近日,快手发布公告称,现年39岁的公司联合创始人宿华辞去CEO一职,由联合创始人程一笑接任该职位,此后,宿华将继续担任快手董事长执行董事薪酬委员会委员,程一笑则作为win10无法连局域网共享打印机,错误代码0X00000709解决本人电脑是win10企业版ltsc,近期突然发现无法连接局域网共享打印机,双击网络打印机就报错为0X00000709,上万能的百度搜解决办法,很多网友说是要卸载掉KB5006670一代更比一代强宝华韦健最新一代飞艇无线蓝牙音箱不管是从当初配套苹果手机而配备崭新的基座推出的第一代飞艇,还是经历从第二代开始至逐步完善的后续几代产品,让人最为惊诧的是,宝华韦健不断在技术上所实现的自我更新的能力。BW宝华韦健飞