Springの「自動プロキシの対象外」警告の解決
1. 概要
この短いチュートリアルでは、Springの「自動プロキシの対象外」メッセージの原因を突き止める方法と、それを修正する方法を説明します。
まず、アプリケーションの起動時にメッセージを表示する簡単な実際のコード例を作成します。 次に、これが発生する理由を説明します。
最後に、実用的なコード例を示して、問題の解決策を示します。
2. 「自動プロキシの対象外」メッセージの原因
2.1. 構成例
メッセージの原因を説明する前に、アプリケーションの起動時にメッセージが表示される例を作成しましょう。
まず、カスタムRandomIntアノテーションを作成します。 これを使用して、指定した範囲のランダムな整数を挿入する必要があるフィールドに注釈を付けます。
@Retention(RetentionPolicy.RUNTIME)
public @interface RandomInt {
int min();
int max();
}
次に、単純なSpringコンポーネントであるDataCacheクラスを作成しましょう。 たとえば、シャーディングをサポートするために使用される可能性のあるランダムグループをキャッシュに割り当てる必要があります。 そのために、そのフィールドにカスタムアノテーションを付けます。
@Component
public class DataCache {
@RandomInt(min = 2, max = 10)
private int group;
private String name;
}
それでは、RandomIntGeneratorクラスを見てみましょう。 これはSpringコンポーネントであり、RandomIntアノテーションで注釈が付けられたフィールドにランダムなint値を挿入するために使用します。
@Component
public class RandomIntGenerator {
private Random random = new Random();
private DataCache dataCache;
public RandomIntGenerator(DataCache dataCache) {
this.dataCache = dataCache;
}
public int generate(int min, int max) {
return random.nextInt(max - min) + min;
}
}
DataCacheクラスをコンストラクタインジェクションを介してRandomIntGeneratorに自動配線していることに注意してください。
最後に、 RandomIntProcessor クラスを作成して、 RandomInt アノテーションが付けられたフィールドを検索し、それらにランダムな値を挿入します。
public class RandomIntProcessor implements BeanPostProcessor {
private final RandomIntGenerator randomIntGenerator;
public RandomIntProcessor(RandomIntGenerator randomIntGenerator) {
this.randomIntGenerator = randomIntGenerator;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
RandomInt injectRandomInt = field.getAnnotation(RandomInt.class);
if (injectRandomInt != null) {
int min = injectRandomInt.min();
int max = injectRandomInt.max();
int randomValue = randomIntGenerator.generate(min, max);
field.setAccessible(true);
ReflectionUtils.setField(field, bean, randomValue);
}
}
return bean;
}
}
org.springframework.beans.factory.config.BeanPostProcessor インターフェースの実装を使用して、クラスの初期化の直前に注釈付きフィールドにアクセスします。
2.2. 例のテスト
すべてが正しくコンパイルされていても、Springアプリケーションを実行してそのログを監視すると、Springの
INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'randomIntGenerator' of type [com.baeldung.autoproxying.RandomIntGenerator] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
さらに、このメカニズムに依存する DataCache beanが、意図したとおりに初期化されていないことがわかります。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RandomIntProcessor.class, DataCache.class, RandomIntGenerator.class})
public class NotEligibleForAutoProxyingIntegrationTest {
private RandomIntProcessor randomIntProcessor;
@Autowired
private DataCache dataCache;
@Test
public void givenAutowireInBeanPostProcessor_whenSpringContextInitialize_thenNotEligibleLogShouldShow() {
assertEquals(0, dataCache.getGroup());
}
}
ただし、メッセージが表示されても、アプリケーションはクラッシュしないことに注意してください。
2.3. 原因の分析
警告は、RandomIntProcessorクラスとその自動配線された依存関係によって発生します。 BeanPostProcessor interface を実装するクラスは、他のBeanの前に、ApplicationContextの特別な起動フェーズの一部として起動時にインスタンス化されます。
さらに、AOP自動プロキシメカニズムは BeanPostProcessor interface の実装でもあります。その結果、BeanPostProcessorの実装もそれらが直接参照するBeanも適格ではありません。自動プロキシ用。 つまり、自動配線、セキュリティ、トランザクションアノテーションなど、AOPを使用するSpringの機能は、これらのクラスでは期待どおりに機能しません。
私たちの場合、自動配線することができました DataCache インスタンスに RandomIntGenerator 問題なくクラス
3. エラーを修正する方法
「自動プロキシの対象外」メッセージを取り除くには、BeanPostProcessor実装とそのBean依存関係の間のサイクルを中断する必要があります。 この場合、RandomIntGeneratorBeanを遅延初期化するようにIoCコンテナに指示する必要があります。 SpringのLazyアノテーションを使用できます。
public class RandomIntProcessor implements BeanPostProcessor {
private final RandomIntGenerator randomIntGenerator;
@Lazy
public RandomIntProcessor(RandomIntGenerator randomIntGenerator) {
this.randomIntGenerator = randomIntGenerator;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//...
}
}
Springは、RandomIntProcessorがpostProcessBeforeInitializationメソッドで要求すると、RandomIntGeneratorBeanを初期化します。 その時点で、SpringのIoCコンテナーは、自動プロキシの対象でもある既存のすべてのBeanをインスタンス化します。
実際、アプリケーションを実行すると、「自動プロキシの対象外です」メッセージがログに表示されません。 さらに、 DataCache beanには、ランダムな整数が入力されたグループフィールドがあります。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RandomIntProcessor.class, DataCache.class, RandomIntGenerator.class})
public class NotEligibleForAutoProxyingIntegrationTest {
private RandomIntProcessor randomIntProcessor;
@Autowired
private DataCache dataCache;
@Test
public void givenAutowireInBeanPostProcessor_whenSpringContextInitialize_thenGroupFieldShouldBePopulated() {
assertNotEquals(0, dataCache.getGroup());
}
}
4. 結論
この記事では、Springの「自動プロキシの対象外」メッセージの原因を突き止めて修正する方法を学びました。 遅延初期化は、Bean構築中の依存関係のサイクルを中断します。
いつものように、サンプルコードはGitHubでから入手できます。