Bisakah Anda menggunakan @Autowired dengan bidang statis?

Jawaban:

122

Singkatnya, tidak. Anda tidak dapat autowire atau secara manual kawat bidang statis di Spring. Anda harus menulis sendiri logika Anda untuk melakukan ini.

skaffman
sumber
3
Ketika Anda menemukan kode lama melakukan ini, ini merupakan anti-pola. Juling, miringkan kepala, dan temukan cara yang lebih baik untuk menyelesaikan masalah. Anda akan senang melakukannya.
Joseph Lust
2
ini jawabannya juga membantu di Spring@AutoWired
Kevin Meredith
116
@Component("NewClass")
public class NewClass{
    private static SomeThing someThing;

    @Autowired
    public void setSomeThing(SomeThing someThing){
        NewClass.someThing = someThing;
    }
}
Sedat Başar
sumber
1
ada ide bagaimana saya bisa menggunakan pendekatan ini ketika menginisialisasi repositori?
kiedysktos
3
Downside: Tidak ada jaminan yang someThingtelah diinisialisasi jika diakses secara statis: NewClass.staticMethodWhichUsesSomething();mungkin melempar NPE jika digunakan sebelum inisialisasi aplikasi
Neeraj
Bisakah Anda menghindari peringatan Instance methods should not write to "static" fields (squid:S2696)?
user7294900
@ user7294900: nonaktifkan peringatan ini hanya untuk kasus ini, sangat spesifik.
izogfif
@izogfif masih menjadi masalah jika saya memilih solusi ini dalam kasus dan kelas yang luas
user7294900
67

@Autowired dapat digunakan dengan setter sehingga Anda bisa memiliki setter memodifikasi bidang statis.

Hanya satu saran terakhir ... JANGAN

victor hugo
sumber
54
Mengapa Anda menyarankan untuk tidak melakukan ini?
Jon Lorusso
3
Hmmm .. perasaan saya tentang mengapa itu tidak direkomendasikan adalah, karena dengan demikian contoh statis di kelas berada di luar kendali pegas. Setelah disuntikkan bidang statis yang acuan bagi semua contoh objek dari kelas yang sesuai (sekitarnya). Tapi, perilaku ini mungkin persis seperti yang diharapkan terjadi, sehingga dapat dilihat sebagai bug atau fitur ...
matthaeus
1
Ya @matthaeus, ini persis fitur yang saya harapkan ketika perlu mengakses org.springframework.core.env.Environment:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316
@ JonLorusso dan semua Karena ketika pemuat kelas memuat nilai statis, konteks Spring belum perlu dimuat. Jadi pemuat kelas tidak akan dengan benar menyuntikkan kelas statis di dalam kacang dan akan gagal. Jawaban diberikan oleh Andrea T
Jeril Kuruvila
14

Masuk komponen autowired Anda dalam metode @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();
   }
}
ak-j
sumber
Bisakah Anda menghindari peringatan Instance methods should not write to "static" fields (squid:S2696)?
user7294900
Anda juga dapat melakukan ini secara langsung melalui konstruktor.
gagarwa
5

Buat kacang yang Anda dapat autowire yang akan menginisialisasi variabel statis sebagai efek samping.

Jherico
sumber
4

Anda dapat mencapai ini menggunakan notasi XML dan MethodInvokingFactoryBean. Sebagai contoh, lihat di sini .

private static StaticBean staticBean;

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

Anda harus berusaha menggunakan injeksi pegas di mana mungkin karena ini adalah pendekatan yang direkomendasikan tetapi ini tidak selalu mungkin karena saya yakin Anda bisa membayangkan karena tidak semuanya bisa ditarik dari wadah pegas atau Anda mungkin berurusan dengan sistem warisan.

Catatan pengujian juga bisa lebih sulit dengan pendekatan ini.

JARC
sumber
2

Ingin menambahkan jawaban bahwa bidang statis perkabelan otomatis (atau konstan) akan diabaikan, tetapi juga tidak akan membuat kesalahan:

@Autowired
private static String staticField = "staticValue";
pengguna7294900
sumber
1

Anda dapat menggunakan ApplicationContextAware

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

    public AppBeans(){
    }

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

kemudian

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

Penafian Ini tidak berarti standar dan mungkin ada cara musim semi yang lebih baik untuk melakukan ini. Tak satu pun dari jawaban di atas mengatasi masalah perkabelan bidang statis publik.

Saya ingin menyelesaikan tiga hal.

  1. Gunakan pegas untuk "Autowire" (Saya menggunakan @Nilai)
  2. Mengekspos nilai statis publik
  3. Cegah modifikasi

Objek saya terlihat seperti ini

private static String BRANCH = "testBranch";

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

public static String BRANCH() {
    return BRANCH;
}

Kami telah memeriksa 1 & 2 sekarang bagaimana cara mencegah panggilan ke setter, karena kami tidak dapat menyembunyikannya.

@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;
    }
}

Aspek ini akan membungkus semua metode mulai dengan final dan melemparkan kesalahan jika mereka dipanggil.

Saya tidak berpikir ini sangat berguna, tetapi jika Anda oCD dan ingin menjaga Anda kacang polong dan wortel dipisahkan ini adalah salah satu cara untuk melakukannya dengan aman.

Pegas Penting tidak memanggil aspek Anda saat memanggil fungsi. Membuat ini lebih mudah, buruk saya mengerjakan logika sebelum mencari tahu itu.

jozsef morrissey
sumber
-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
Amol Kakade
sumber
2
Meskipun kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu untuk meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan dan berikan indikasi tentang batasan dan asumsi apa yang berlaku.
bunyi bip ganda
Saya pikir jawaban ini mungkin tidak memerlukan penjelasan sama sekali.
Chaklader Asfak Arefe