@Autowired注解能用在static属性吗?autowired注入static属性上为null
@Autowired注解能用在static屬性嗎?
答案是否定的,我們來測試下:
日志信息已經很明確了,表示static不能被@Autowired進行復制。為什么呢?我們現在就來一起了解其原因。
首先將我們的測試環境搭建好,
User1類
@Componentpublic class User1 { @Autowired private static User2 user2; @Autowired private User2 user3; }User2類
@Componentpublic class User2 {}AppConfig類
@Configuration@ComponentScan("staticDemo") /*@EnableAspectJAutoProxy*/ /*@Import(MyImportBeanDefinitionRegistrar.class)*/ public class AppConfig {}Test類
public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(AppConfig.class); } }然后將代碼定位在依賴注入的入口
此時我們的beanName是User1類,我們需要注入User1類,然后我們進入這個方法
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. //Spring判斷你是不是自己實現了InstantiationAwareBeanPostProcessor,如果實現了,而且返回false, // Spring就不會繼續執行了,一般不會用到 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } } //判斷是否已經對屬性賦值 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); //判斷屬性植入的模式,默認NO 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(); 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); } 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) { applyPropertyValues(beanName, mbd, bw, pvs); } }這里有兩個for循環,我們關注第二個for循環,找到后置處理器是
然后點進去
這里第一行代碼就是獲取我們的數據信息,并且用InjectionMetadata的方式進行封裝,獲取InjectionMetadata后就可以通過反射的方式進行屬性注入了,這里在前面的Spring源碼章節我們已經詳細介紹了,就不再敘述。我們進入這個findAutowiringMetadata方法,瞧一瞧他是如何獲取的,
我們看到InjectionMetadata封裝了哪些信息,其中包含了我們的user3這個屬性,注意這個user3是沒有static修飾的,user2是被static修飾了的,而這里確沒有user2這個屬性,先記住這一點,然后我們再看我們的metadata是通過injectionMetadataCache緩存獲取的,說明一個我們的static是在存放緩存的時候就將我們的static屬性屏蔽掉,接下來我們就驗證我們的猜想。
Spring何時屏蔽static屬性?
我們將代碼定位在AbstractAutowireCapableBeanFactory.doCreateBean方法
跟蹤進去
再跟蹤
可以看到已經回到了我們find方法,點進去,注意下面的紅線表示我們這里是找的user1類的屬性
然后這里我們關注的是injectionMetadataCache緩存
此時緩存里并沒有user1的元信息,我們再次跟進
首先看到這里ReflectionUtils.doWithLocalFields,我們點進去
可以看到這里獲取了兩個我們的屬性,一個是靜態屬性一個是常態屬性,然后我們再回到buildAutowiringMetadata方法,注意這里的filed是函數試變成,它會回調這里的代碼
我們就可以看到如果我們的屬性是static,那么Spring會直接拋棄,
可以看到我們已經得到了驗證,Spring就是在這里拋棄了static的屬性,至于為什么要拋棄static屬性呢?筆者猜測這里需要回到JVM的一些知識,我們都知道static是面向類級別,而Spring通常是面向普通的單例對象,如果我們將單例的對象中static屬性賦值,那么就會影響我們這個類的其他對象的值,個人認為這是Spring不希望看到的,這也是不科學的。
總結
以上是生活随笔為你收集整理的@Autowired注解能用在static属性吗?autowired注入static属性上为null的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第四范式上榜《麻省理工科技评论》“50家
- 下一篇: ArrayList类contains方法