@Autowired'ı statik alanlarla kullanabilir misiniz?


Yanıtlar:


125

Kısacası hayır. Spring'de statik alanları otomatik kablolama veya manuel olarak bağlayamazsınız. Bunu yapmak için kendi mantığınızı yazmanız gerekecek.


3
Bunu yapan eski kodu bulduğunuzda, bu bir anti-modeldir. Şaşı şaşı, başını yana eğ ve sorunu çözmenin daha iyi bir yolunu bul. Yaptığına sevineceksin.
Joseph Şehvet

2
bu cevap Spring's@AutoWired
Kevin Meredith

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

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

1
Bir depoyu başlatırken bu yaklaşımı nasıl kullanabileceğime dair bir fikriniz var mı?
kiedysktos

3
Dezavantajı: someThingStatik olarak erişilirse başlatılan bir garanti yok : NewClass.staticMethodWhichUsesSomething();uygulama başlatılmadan önce kullanılırsa bir NPE atabilir
Neeraj

Uyarısından kaçınabilir misin Instance methods should not write to "static" fields (squid:S2696)?
user7294900

@ user7294900: bu uyarıyı yalnızca bu çok özel durum için devre dışı bırakın.
izogfif

Bu çözümü geniş durumlarda ve sınıflarda seçersem @izogfif hala bir sorun
user7294900

68

@Autowired ayarlayıcılarla birlikte kullanılabilir, böylece statik bir alanı değiştiren bir ayarlayıcıya sahip olabilirsiniz.

Sadece son bir öneri ... YAPMAYIN


57
Neden bunu yapmamayı öneriyorsun?
Jon Lorusso

3
Hmmm .. neden tavsiye edilmediğine dair hislerim, çünkü o zaman sınıftaki statik örnek baharın kontrolü dışındadır. Statik alan bir kez enjekte edildiğinde, karşılık gelen (çevreleyen) sınıfın tüm nesnelerinin örnekleri için referanstır. Ancak, bu davranış tam olarak olması beklenen şey olabilir, bu nedenle bir hata veya özellik olarak görülebilir ...
matthaeus

1
Evet @matthaeus, org.springframework.core.env.Çevreye erişmeye ihtiyaç duyduğumda beklediğim özellik tam olarak budur:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316

1
@JonLorusso ve tümü Sınıf yükleyici statik değerleri yüklediğinde, Spring bağlamı henüz gerekli değildir. Dolayısıyla sınıf yükleyici, statik sınıfı çekirdeğe düzgün şekilde enjekte etmez ve başarısız olur. Cevap Andrea T
Jeril Kuruvila

18

@ PostConstruct yönteminde otomatik kablolu bileşeninizi başlatın

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

Uyarısından kaçınabilir misin Instance methods should not write to "static" fields (squid:S2696)?
user7294900

Bunu doğrudan kurucu aracılığıyla da yapabilirsiniz.
gagarwa

@ user7294900 Sanırım bu uyarı bize bunun neden bir anti-model olarak kabul edildiğini söylüyor. Örnek yöntemleri statik bir değişkene yazarken, statik değişken, sınıfın tüm nesneleri arasında paylaşılan kritik bir kaynak haline gelir ve böylece çok iş parçacıklı ortamlarda problemler için potansiyel yaratır.
rineez

5

Bir yan etki olarak statik değişkeni başlatacak otomatik kablolama yapabileceğiniz bir fasulye oluşturun.


4

Bunu XML gösterimi ve MethodInvokingFactoryBean. Örnek için buraya bakın .

private static StaticBean staticBean;

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

Önerilen yaklaşım bu olduğundan, mümkünse yaylı enjeksiyon kullanmayı hedeflemelisiniz. ancak bu her zaman mümkün değildir, çünkü her şeyin yaylı hazneden çekilemeyeceğini veya eski sistemlerle uğraşabileceğinizi hayal edebileceğinizden eminim.

Not testi, bu yaklaşımla daha zor olabilir.


2

Otomatik kablolama statik alanının (veya sabitinin) yok sayılacağı, ancak aynı zamanda herhangi bir hata oluşturmayacağı yanıtlarına eklemek istendi:

@Autowired
private static String staticField = "staticValue";

1

ApplicationContextAware'i kullanabilirsiniz

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

    public AppBeans(){
    }

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

sonra

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

0

Feragatname Bu hiçbir şekilde standart değildir ve bunu yapmanın daha iyi bir yolu olabilir. Yukarıdaki cevapların hiçbiri bir kamusal statik alanın kablolanmasıyla ilgili sorunları ele almamaktadır.

Üç şeyi başarmak istedim.

  1. Yayı "Autowire" için kullanın (@Value kullanıyorum)
  2. Herkese açık bir statik değeri ortaya çıkarın
  3. Değişikliği önleyin

Benim nesnem buna benziyor

private static String BRANCH = "testBranch";

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

public static String BRANCH() {
    return BRANCH;
}

1 & 2'yi zaten işaretledik, gizleyemeyeceğimiz için ayarlayıcıya gelen çağrıları nasıl engelleyeceğiz.

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

Bu özellik, finalden başlayarak tüm yöntemleri sarmalar ve çağrılırsa bir hata verir.

Bunun özellikle yararlı olduğunu sanmıyorum, ancak eğer okkalıysanız ve sizi bezelye ve havuç ayrı tutmaktan hoşlanıyorsanız, bu güvenli bir şekilde yapmanın bir yoludur.

Önemli Bahar, bir işlevi çağırdığında veçhelerinizi çağırmaz. Bunu daha kolay hale getirdi, kötüye doğru anlamadan önce mantığı çözdüm.


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

2
Bu kod soruyu çözebilirken, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere , gönderinizin kalitesini artırmaya gerçekten yardımcı olur ve muhtemelen daha fazla oy almanıza neden olur. Sadece şimdi soran kişi için değil, gelecekte okuyucular için soruyu yanıtladığınızı unutmayın. Açıklamalar eklemek ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge vermek için lütfen yanıtınızı düzenleyin .
çift ​​bip sesi

1
Sanırım bu cevabın herhangi bir açıklamaya ihtiyacı olmayabilir.
Deadpool
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.