<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
做Java都有很多年了,一直有一個疑惑: Spring 如何初始化bean,怎麼呼叫反射範例化物件的,自己動手來解除這個疑惑。 過去我認為spring bean物件範例化一直都是由BeanPostProcessor介面實現類去做的,我就是不知道具體那個實現類,下面就去驗證下這個猜想。
為什麼面試官特別喜歡問建立bean的三級快取,主要是因為bean建立都是伴隨著三級快取之間的轉換完成的,物件不同狀態分別存在不同快取中,下面我會在分析程式碼時,順便支援物件如何在快取中流轉的。 先了解下spring 三級快取。
/** 一級快取 用於存放完全可以使用單例bean,也就是初始化完成並且注入所有依賴 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** 二級快取 過早暴露單例物件,此時bean剛剛完成初始化,未完成屬性注入和執行 init 方法 */ private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); /** 三級快取 裝載建立bean的工廠物件 */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16)
三級快取主要作用: 建立物件ObjectFactory首先放入三級換快取中,當呼叫getObject 建立範例時,會將建立好物件加入二級快取中,並且刪除三級中快取,當物件已經完成初始化方法和屬性注入,再將快取新增到一級快取中,並且刪除二級快取。
從源頭開始找,所有spring bean 初始化都是由AbstractBeanFactory.doGetBean
方法實現的。下面我將原始碼減除臃腫部分,貼出來。
protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { //name 字首處理 beanFactory beanName 帶有&開頭 String beanName = transformedBeanName(name); Object beanInstance; //從三級快取去取bean,三級中都沒有則返回null,說明物件還沒有建立 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { //如果快取中bean 是FactoryBean範例,要通過介面獲取到實際bean beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //判斷bean物件標記是否正在建立中,如果正在建立中則不應該繼續下去,出現依賴迴圈就會出現這個錯誤 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } BeanFactory parentBeanFactory = getParentBeanFactory(); // 檢查父容器是否存在,嘗試從父容器中獲取 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } if (!typeCheckOnly) { //快取中標記beanName 正在被建立 markBeanAsCreated(beanName); } StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") .tag("beanName", name); try { if (requiredType != null) { beanCreation.tag("beanType", requiredType::toString); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { //bean 中@DependsOn 資訊,用於標記bean之間初始化順序,優先建立@DependsOn 中bean 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); } } } //建立單例物件 if (mbd.isSingleton()) { //重點就在這裡範例化物件 ,getSingleton 就是在這裡將建立完成物件加入到一級快取中 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) destroySingleton(beanName); throw ex; } }); //如果生成bean 是FactoryBean ,再獲取真正的物件 beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //作用域 = prototype,因為不會放入快取中,每次獲取都要重新建立 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { // session request 這些作用域,由作用域容器去管理這些物件 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); } }); beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new ScopeNotActiveException(beanName, scopeName, ex); } } } catch (BeansException ex) { beanCreation.tag("exception", ex.getClass().toString()); beanCreation.tag("message", String.valueOf(ex.getMessage())); cleanupAfterBeanCreationFailure(beanName); throw ex; } finally { beanCreation.end(); } } //返回初始化成功的物件,一個物件初始化就這樣完成的了 return adaptBeanInstance(name, beanInstance, requiredType); }
大概總結一下上面程式碼流程:
org.springframework.context.annotation.@DependsOn
這個註解。下一步按照不同scope 進行bean 物件初始化。初始化流程就是這樣,我們將目光放在單例bean 如何範例化,集中關注AbstractAutowireCapableBeanFactory.createBean
獲取註冊一個單例物件@DependsOn
註解意思是範例化某個物件依賴於某一個範例化,但是不需要持有這個範例物件。比如bean A上 需要依賴bean b才能範例化,但是bean b 不需要作為他的屬性,常常用於不同範例範例化順序標記。
看下getSingleton方法
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { //標記bean 是否在銷燬 throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { } catch (BeanCreationException ex) { throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); //就是在這裡刪除二三級快取,提交到一級快取 } } return singletonObject; } } protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
新增到一級快取則說明bean已經完成範例化,可以正常使用了。下面看下如何進行範例化和屬性注入的。
下面進入AbstractAutowireCapableBeanFactory.createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; //克隆一份mbd => mbdToUse Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. 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. //通過BeanPostProcessors 增強返回一個代理物件,這個生成AOP的代理物件,使用多個BeanPostProcessors來處理 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); return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); } }
這裡邏輯就比較簡單了 ,克隆一份RootBeanDefinition用於初始化物件,resolveBeforeInstantiation 主要用於初始化代理物件情況,主要使用BeanPostProcessor子類InstantiationAwareBeanPostProcessor實現方法去實現物件初始化,並且在範例化成功後在呼叫後置方法進行物件依賴注入,這裡可以看見此方法返回物件直接跳出方法棧,這裡可以看出單例和代理物件還是有區別的。單例物件初始化就在doCreateBean 實現了
下面就是AbstractAutowireCapableBeanFactory.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) { instanceWrapper = createBeanInstance(beanName, mbd, args); //這個就是範例化方法 } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // 使用BeanDefinitionPostProcessors 對合並bean進行範例化 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; } } // 這裡就需要用到上面說的三級快取知識了 // 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)); //將已經範例化的物件加入到第三級快取 singletonFactories } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); //對屬性進入注入,下面會具體分析的 exposedObject = initializeBean(beanName, exposedObject, mbd); //執行初始化方法,或者注入Aware 介面bean } 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); } } //下面程式碼省略 //主要就是對設定了DisposableBean 介面銷燬勾點方法處理 }
這裡程式碼主要分成三部分
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. 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) {// 有實現Supplier 介面,由instanceSupplier.get() 方法建立範例 return obtainFromSupplier(instanceSupplier, beanName); } //factoryName 使用工廠模式建立bean,呼叫工廠方法去建立,這個支援靜態方法和factoryBean.invoke if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same 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); } } // 獲取建構函式引數 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); }
範例化方法instantiateBean最終會呼叫SimpleInstantiationStrategy.instantiate 進行範例化
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. 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<Constructor<?>>) 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. return instantiateWithMethodInjection(bd, beanName, owner); } }
@Override public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. 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<Constructor<?>>) 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. return instantiateWithMethodInjection(bd, beanName, owner); } }
這裡要注意下先判斷bean是否有方法重寫的,沒有則使用反射生成的構造器,有就使用gclib方式建立代理物件,具體實現方式就在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate
,有興趣同學可以去學習下。 到此一個簡單bean範例化完成了。
下面進入IOC另一個特點,bean注入,先從AbstractAutowireCapableBeanFactory.populateBean
方法開始
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // 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. //通過InstantiationAwareBeanPostProcessors.postProcessAfterInstantiation 如果返回true,目標範例內部的返回值會被populate,否則populate這個過程會被忽視 //翻譯說如果返回true可以執行欄位注入 真的6666啊 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); //獲取注入方式分佈有4種 int resolvedAutowireMode = mbd.getResolvedAutowireMode(); 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(); //依賴方式,模式都是沒有型別檢查,這種依賴方式一般都是xml 設定用得比較多,沒有設定這裡都是返回false boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); / PropertyDescriptor[] filteredPds = null; if (hasInstAwareBpps) { if (pvs == null) { pvs = mbd.getPropertyValues(); } for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); //獲取註解標註需要注入方法或者是欄位,並且進行注入 if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = bp.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) { applyPropertyValues(beanName, mbd, bw, pvs); } }
小知識點: AutowireCapableBeanFactory.AUTOWIRE_NO 表明不會對當前Bean進行外部類的注入,常規使用@Autowire、@Resource 都是這型別 剩下三種都是通過xml 或者 AutowireCapableBeanFactory.autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) 進行設定autowireMode 。
根據上面程式碼可以知道主流程bean注入都是由InstantiationAwareBeanPostProcessor 進行處理的,簡單說明介面方法
方法 | 描述 |
---|---|
postProcessBeforeInitialization | 方法是最 先執行的方法,它在目標物件範例化之前呼叫,該方法的返回值型別是Object,我們可以返回任何型別的值。由於這個時候目標物件還未範例化,所以這個返回值可以用來代替原本該生成的目標物件的範例(比如代理物件)。如果該方法的返回值代替原本該生成的目標物件,後續只有postProcessAfterInitialization方法會呼叫,其它方法不再呼叫;否則按照正常的流程走 |
postProcessAfterInitialization | 方法在目標物件範例化之後呼叫,這個時候物件已經被範例化,但是該範例的屬性還未被設定,都是null。因為它的返回值是決定要不要呼叫postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果返回true,postProcessPropertyValues就會被執行 |
postProcessPropertyValues | 對bean屬性值賦值後呼叫,對屬性值的修改。如果postProcessAfterInstantiation方法返回false,該方法可能不會被呼叫。可以在該方法內對屬性值進行修改 |
postProcessProperties | Bean屬性賦值就是呼叫這個方法的 |
InstantiationAwareBeanPostProcessor 介面實現類主要分3個
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4); @SuppressWarnings("unchecked") public AutowiredAnnotationBeanPostProcessor() { this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); try { this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } }
在初始化時就將支援註解加入集合中,再使用掃描器去掃描方法、構造器、欄位,如果有這些註解就進行注入。
看下怎麼判斷是否需要注入的
@Nullable private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) { MergedAnnotations annotations = MergedAnnotations.from(ao); for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { MergedAnnotation<?> annotation = annotations.get(type); if (annotation.isPresent()) { return annotation; } } return null; }
AccessibleObject 是Method、Field、Constructor 父類別。
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { //獲取需要注入欄位,方法 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { 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 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // 快速從快取中獲取,如果沒有加鎖去解析,然後在結果放入快取中 InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { //雙重檢查 metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; }
看下如何去掃描方法、欄位的
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { //從給定註解中判斷class 是否攜帶這個註解 if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); //遍歷所有Field,找出掃描的註解,特意標註不支援static 修飾field ReflectionUtils.doWithLocalFields(targetClass, field -> { MergedAnnotation<?> ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; } // 獲取註解內 required 值 boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } }); ReflectionUtils.doWithLocalMethods(targetClass, method -> { //獲取方法上橋接方法,因為泛型型別擦除,要對橋接方法進行安全檢查,防止在呼叫是出現異常 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } //獲取註解 MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod); //方法安全檢查 if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { //不支援靜態方法注入 if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static methods: " + method); } return; } if (method.getParameterCount() == 0) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } }); // 這樣寫是為了後面加入排在佇列前面,父類別屬性優先於子類 elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); //這裡寫得很好,向上解析父類別,直到是Object 為止 return InjectionMetadata.forElements(elements, clazz); }
邏輯非常簡單,就是根據給定註解去class獲取指定的註解,從而獲取到需要注入型別,但是幾行簡單的程式碼可以看出強大編碼能力,學習了
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45