NPE隠された春の依存性注入爆弾

免責事項:この記事はブロガーオリジナル記事です、ソースを明記してください。https://blog.csdn.net/u010597819/article/details/89279079

循環依存の問題に対処する上で春「早期露光オブジェクト」を導入しましたが、循環依存になったときにそれが起こるNPEの可能性を避けることができない、このシナリオのブロガーが別の記事で説明しています。https:// blog.csdn.net/u010597819/article/details/86646162
そして、何の循環依存関係は、私たちは安全ではありませんか?ねえ、本当にそれが再び発生した私たちにNPEです

問題の説明

テストは、機能の大部分にわたって測定された、その日の突然の出現は、どのように午後にサービスを取得するために、我々はコードの変更をテストするように求めていないが、我々は任意のコードを提出しなかった、コードが適切にテスト前に変更されていない、それがどのように急に再生されませんまだ出てきますか?私たちの古い友人NPEあり、その後、ログに基づいて、特定のコードを表示するログの表示

Caused by: java.lang.NullPointerException
	at .....spring.boot.autoconfigure.api.AbstractClientCache.queryFromClientCache(AbstractClientCache.java:79) ~[client-cache-support-1.0.0.jar:1.0.0]
	at .......DispatchFilterTypeConfigFullyCache.lambda$buildCache$1(DispatchFilterTypeConfigFullyCache.java:47) ~[classes/:?]
	at java.util.ArrayList.forEach(ArrayList.java:1249) ~[?:1.8.0_131]
	at .......DispatchFilterTypeConfigFullyCache.buildCache(DispatchFilterTypeConfigFullyCache.java:45) ~[classes/:?]
	at .....spring.boot.autoconfigure.api.AbstractClientCache.initCache(AbstractClientCache.java:34) ~[client-cache-support-1.0.0.jar:1.0.0]
	at .....spring.boot.autoconfigure.ClientCacheHandler.afterPropertiesSet(ClientCacheHandler.java:36) ~[client-cache-support-1.0.0.jar:1.0.0]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	... 14 more

問題の原因分析

  1. 我々は問題が発生する前にそれはサイクルに依存しないのですか?だから、問題がある場合、循環依存の内側に次の依存豆を見て急いで見つけると木材。
@Component
public class DispatchFilterInfoFullyCache extends
        AbstractFullyClientCache<String, List<DispatchFilterInfoDTO>, DispatchFilterInfo> {

    @Resource
    private DispatchFilterInfoManager dispatchFilterInfoManager;
  1. 豆、注入された初期の暴露に依存オブジェクトのデフォルト値を参照するので、問題はないバネ仕掛けの豆プロセスの学生がロードされたときに、ことを知っている必要があり学び、もはやNULLポインタが生じてはならない。そして、問題はどこにありますか?
  2. ログ異常な理由でステップを見バイステップに従ってみましょう、明らかに空dispatchFilterInfoFullyCache.cacheによって引き起こされます
  3. その依存性が注入されたが、注入されたキャッシュが創出につながっていません

1.type缓存调用另一个缓存,DispatchFilterTypeConfigFullyCache.lambda$buildCache$1(DispatchFilterTypeConfigFullyCache.java:47)
List<DispatchFilterInfoDTO> dispatchFilterInfoDTOS = dispatchFilterInfoFullyCache.queryFromClientCache(dispatchFilterTypeConfigResultDTO.getId()+"");
2.DispatchFilterInfoFullyCache缓存查询key对应的值
public V queryFromClientCache(K key) {
    return this.cache.getIfPresent(key);
}
  1. この時間のキャッシュ順序リストはDispatchFilterTypeConfigFullyCache、DispatchFilterInfoFullyCacheであれば問題は基本的に、「早期露光オブジェクト」のローカルキャッシュに注入プロパティを一覧表示、そして、ClientCacheHandlerビーンが他のローカルキャッシュの前に初期化した場合、ことを確認した。その後のbuildCache DispatchFilterTypeConfigFullyCacheを呼び出しますDispatchFilterInfoFullyCacheは、ローカルキャッシュを作成しない場合の方法は、DispatchFilterInfoFullyCacheキャッシュを使用してキャッシュするので、キャッシュは、その後、nullポインタ問題が必然がある場合
@Bean
public ClientCacheHandler clientCacheHandler() {
    return new ClientCacheHandler();
}
public class ClientCacheHandler implements InitializingBean {
    @Autowired
    private List<ClientCache> list;

    public void afterPropertiesSet() {
            Iterator var1 = this.list.iterator();

            while(var1.hasNext()) {
                ClientCache clientCache = (ClientCache)var1.next();
								...
                //init缓存中调用了本地缓存的buildCache方法
                Cache cache = clientCache.initCache();
                ...

繰り返し発生する問題

まず、問題を再現しようとする分析結果によります。私たちは、最終のための順序を指定することが必須です@OrderコメントDispatchFilterInfoFullyCacheを、使用しています。そしてDispatchFilterTypeConfigFullyCacheがPriorityOrderedインタフェースは、優先順位の高い負荷を提供し得るか、@Order注釈が最高の優先度を示しており、確かに地域の問題を正常に再現するために使用してみましょう。我々の分析は、証明します

問題解決

問題、解決策と非常に明確な、はい、限り、バッファの確立にDispatchFilterTypeConfigFullyCache依存DispatchFilterInfoFullyCache最初のステップとして、及び@Order(使用できるキャッシュフラッシュを確認した後HIGHEST_PRECEDENCE表の上部にある)注釈が注入された指定リストをDispatchFilterInfoFullyCacheキャッシュをロードするために初期化されているので、問題は自然に解決されるだろう
し、すぐ小さなパートナー、再パッケージのリリース、バグフィックスをテストするためにコードを変更通知します

反射期間

疑問に思う:(デフォルトは最低_LOWEST_PRECEDENCE_です)初めて今だけDispatchFilterInfoFullyCache @Orderとして再指定され、すでに百パーセント再現性が、執筆時点でも再現することはできません、DispatchFilterTypeConfigFullyCache最高の優先度を設定する必要がでしたあなたは再現することができます。これはなぜでしょうか?

それはプロパティのリストを注入された場合、我々は、照合を見てみましょう

  1. populateBean注入性
  2. 式射出autowireByTypeに応じて、
  3. 依存オブジェクトを解決resolveDependency
  4. プロパティリストに注入されます

依存オブジェクトの解析

  1. 分析ファクトリクラス依存DefaultListableBeanFactory.resolveDependency
  2. オプション、ObjectFactoryに、ObjectProvider、javax.inject.Provider場合は、それぞれのプロバイダに基づいて解決されます
  3. あなたは、治療が行われたかどうかを判断するために怠惰な方法ではない場合doResolveDependencyを解決しません
  4. あなたは、マルチマルチ豆と豆解決resolveMultipleBeansリターンを実行する場合
  5. それはCollection型の集合であり、インターフェイスタイプ、Beanを取得するためのキューのリストであれば私たちは、私たちのタイプのリストを見て、対応する要件を指示します
  6. 依存関係およびコンパレータがある場合は、属性の型が一覧で注入される、ソートが後を返します
if (getDependencyComparator() != null && result instanceof List) {
	Collections.sort((List<?>) result, adaptDependencyComparator(matchingBeans));
}
return result;

依存コンパレータは達成します

  1. AnnotatedBeanDefinitionReaderオブジェクトを作成するときに、登録依存コンパレータ、AnnotationConfigUtils。RegisterAnnotationConfigProcessors(this.registry)。
  2. すなわち、実装クラス:AnnotationAwareOrderComparator
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, Object source) {
	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}
  1. AnnotationAwareOrderComparatorの比較が行われます
private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) {
	boolean p1 = (o1 instanceof PriorityOrdered);
	boolean p2 = (o2 instanceof PriorityOrdered);
	if (p1 && !p2) {
		return -1;
	}
	else if (p2 && !p1) {
		return 1;
	}

	// Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation.
	int i1 = getOrder(o1, sourceProvider);
	int i2 = getOrder(o2, sourceProvider);
	return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
  1. P1 P2のタイプがないPriorityOrderedされている場合は、P1優先度の高い、逆に、p2の優先度の高いです
  2. sourceProvider(デフォルトでは空白)が存在する場合、注文sourceProviderによって取得された読み取りが空の場合、getOrderを注文
  3. 何の使用がない場合、オブジェクトのコメントを取得するgetOrderため_LOWEST_PRECEDENCE_
protected int getOrder(Object obj) {
	Integer order = findOrder(obj);
	return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
}

回答:これは私たちの疑問に答え、ノート@Orderが実際に_LOWEST_PRECEDENCEであれば、私は上のコメント初めて唯一の問題を再現する1件の注文が第二、散発例であるので、他の豆の注文は、その同じレベルを指摘していません回意志とても幸運ではありません_

おすすめ

転載: blog.csdn.net/u010597819/article/details/89279079