静的フィールドで@Autowiredを使用できますか?


回答:


122

つまり、いいえ。Springで静的フィールドを自動ワイヤリングまたは手動でワイヤリングすることはできません。これを行うには、独自のロジックを記述する必要があります。


3
古いコードがこれを実行しているのを見つけると、それはアンチパターンです。目を細めて、頭を傾け、問題を解決するより良い方法を見つけてください。よろしくお願いします。
ジョセフ・ラスト

2
この回答は、Spring's@AutoWired
Kevin Meredithに

116
@Component("NewClass")
public class NewClass{
    private static SomeThing someThing;

    @Autowired
    public void setSomeThing(SomeThing someThing){
        NewClass.someThing = someThing;
    }
}

1
リポジトリを初期化するときにこのアプローチをどのように使用できるかについてのアイデアはありますか?
kiedysktos 2017年

3
欠点:someThing静的にアクセスした場合に初期化されている保証はありません。NewClass.staticMethodWhichUsesSomething();アプリの初期化前に使用するとNPEがスローされる可能性があります
Neeraj

の警告を回避できますInstance methods should not write to "static" fields (squid:S2696)か?
user7294900

@ user7294900:この警告は、非常に特殊なケースでのみ無効にしてください。
izogfif

私は広範な例とクラスでこのソリューションを選択した場合、まだ問題@izogfif
user7294900

67

@Autowired 静的フィールドを変更するセッターを使用できるように、セッターと共に使用できます。

最後に1つだけ提案...しないでください


54
なぜこれをしないことを勧めるのですか?
ジョンロルッソ2011

3
うーん..推奨されない理由についての私の感想です。クラスの静的インスタンスは、スプリングの制御を超えているからです。注入後静的フィールドは、対応する(周囲の)クラスのオブジェクトのすべてのインスタンスのための基準。しかし、この動作は
実際

1
はい@matthaeus、それはアクセスorg.springframework.core.env.Environmentに必要とするとき、私は期待まさに機能です:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316

@JonLorusso and allクラスローダーが静的な値をロードするとき、Springコンテキストはまだロードされている必要はありません。そのため、クラスローダーはBeanに静的クラスを適切に挿入せず、失敗します。Andrea Tによる回答
Jeril Kuruvila

14

@PostConstructメソッドで自動配線コンポーネントを初期化する

@Component
public class TestClass {
   private static AutowiredTypeComponent component;

   @Autowired
   private AutowiredTypeComponent autowiredComponent;

   @PostConstruct
   private void init() {
      component = this.autowiredComponent;
   }

   public static void testMethod() {
      component.callTestMethod();
   }
}

の警告を回避できますInstance methods should not write to "static" fields (squid:S2696)か?
user7294900

これは、コンストラクタを介して直接行うこともできます。
ガガルワ

5

副作用として静的変数を初期化する自動配線可能なBeanを作成します。


4

これは、XML表記とを使用して実現できますMethodInvokingFactoryBean。例については、こちらをご覧ください

private static StaticBean staticBean;

public void setStaticBean(StaticBean staticBean) {
   StaticBean.staticBean = staticBean;
}

これは推奨されるアプローチであるため、可能な場合はスプリングインジェクションの使用を目指す必要がありますが、すべてがスプリングコンテナーから引き出せるわけではないか、レガシーシステムを扱っているとは限らないので、これは常に可能とは限りません。

この方法では、テストがさらに困難になる場合があります。


1

あなたはApplicationContextAwareを使うことができます

@Component
public class AppContext implements ApplicationContextAware{
    public static ApplicationContext applicationContext;

    public AppBeans(){
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

その後

static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);

1

自動配線の静的フィールド(または定数)は無視されるが、エラーも発生しないことを回答に追加したい:

@Autowired
private static String staticField = "staticValue";

0

免責事項これは決して標準的なものではなく、これを行うためのより良い春の方法が非常によくあるでしょう。上記の回答のいずれも、パブリック静的フィールドの配線の問題に対処していません。

私は3つのことを達成したかった。

  1. 「Autowire」にスプリングを使用します(@Valueを使用しています)
  2. public static値を公開する
  3. 変更を防ぐ

私のオブジェクトはこのように見えます

private static String BRANCH = "testBranch";

@Value("${content.client.branch}")
public void finalSetBranch(String branch) {
    BRANCH = branch;
}

public static String BRANCH() {
    return BRANCH;
}

1と2はすでに非表示にできないため、セッターへの呼び出しをどのようにして防止するかについてはすでにチェックしました。

@Component
@Aspect
public class FinalAutowiredHelper {

@Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
    throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}

@Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}


public class ModifySudoFinalError extends Error {
    private String msg;

    public ModifySudoFinalError(String msg) {
        this.msg = msg;
    }

    @Override
    public String getMessage() {
        return "Attempted modification of a final property: " + msg;
    }
}

このアスペクトはfinalで始まるすべてのメソッドをラップし、それらが呼び出されるとエラーをスローします。

これは特に便利だとは思いませんが、ocdでエンドウ豆とニンジンを分離しておくのが好きな場合、これは安全に行う方法の1つです。

重要 Springは、関数を呼び出すときにアスペクトを呼び出しません。これを簡単にして、悪いことに私はそれを理解する前にロジックを考え出しました。


-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

2
このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、おそらく投票数が増えることになります。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
ダブルビープ音

この答えは何の説明も必要ないかもしれません。
Chaklader Asfak Arefe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.