Czy możesz używać @Autowired z polami statycznymi?


Odpowiedzi:


122

Krótko mówiąc, nie. W Spring nie można łączyć automatycznie ani ręcznie łączyć pól statycznych. Aby to zrobić, będziesz musiał napisać własną logikę.


3
Kiedy zauważysz, że robi to stary kod, jest to anty-wzorzec. Zmruż oczy, przechyl głowę i znajdź lepszy sposób rozwiązania problemu. Będziesz zadowolony, że to zrobiłeś.
Joseph Lust

2
ta odpowiedź jest również pomocna w 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
masz pomysł, jak mogę użyć tego podejścia podczas inicjowania repozytorium?
kiedysktos

3
Wadą: Nie ma żadnej gwarancji, że someThingzostał zainicjowany jeśli obejrzano statycznie: NewClass.staticMethodWhichUsesSomething();może rzucić NPE jeśli stosowany przed app inicjalizacji
neeraj

Czy możesz uniknąć ostrzeżenia Instance methods should not write to "static" fields (squid:S2696)?
user7294900

@ user7294900: wyłącz to ostrzeżenie tylko w tym bardzo szczególnym przypadku.
izogfif

@izogfif nadal problem, jeśli wybiorę to rozwiązanie w szerokich przypadkach i klasach
user7294900

67

@Autowired może być używany z ustawiaczami, więc możesz mieć setera modyfikującego pole statyczne.

Jeszcze jedna ostatnia sugestia ... NIE


54
Dlaczego sugerujesz, aby tego nie robić?
Jon Lorusso,

3
Hmmm ... moje przeczucie, dlaczego nie jest to zalecane, jest takie, ponieważ wtedy statyczna instancja w klasie jest poza kontrolą sprężyny. Po wstrzyknięciu pole statyczne odniesienia dla wszystkich przypadkach obiektów odpowiedniego (otaczającym) klasy. Ale to zachowanie może być dokładnie tym, czego się oczekuje, dlatego może być postrzegane jako błąd lub funkcja ...
matthaeus

1
Tak @matthaeus, jest to dokładnie ta funkcja, której oczekiwałem, gdy potrzebowałem uzyskać dostęp do org.springframework.core.env.Environment:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316

@JonLorusso i wszystko Ponieważ gdy moduł ładujący klasy ładuje wartości statyczne, kontekst Spring nie jest jeszcze koniecznie ładowany. Zatem program ładujący klasy nie wprowadzi prawidłowo statycznej klasy do komponentu bean i zawiedzie. Odpowiedź udzielona przez Andrea T
Jeril Kuruvila

14

Zainicjuj swój autowired komponent w metodzie @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();
   }
}

Czy możesz uniknąć ostrzeżenia Instance methods should not write to "static" fields (squid:S2696)?
user7294900

Możesz to również zrobić bezpośrednio przez konstruktora.
gagarwa

5

Utwórz bean, który możesz automatycznie podłączyć, który zainicjuje zmienną statyczną jako efekt uboczny.


4

Możesz to osiągnąć za pomocą notacji XML i MethodInvokingFactoryBean. Na przykład spójrz tutaj .

private static StaticBean staticBean;

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

Należy dążyć do stosowania wtrysku sprężyny, jeśli jest to możliwe, ponieważ jest to zalecane podejście, ale nie zawsze jest to możliwe, ponieważ jestem pewien, że możesz sobie wyobrazić, ponieważ nie wszystko można wyciągnąć z pojemnika sprężyny lub może masz do czynienia ze starszymi systemami.

Przy takim podejściu testowanie notatek może być również trudniejsze.


2

Chciałem dodać do odpowiedzi, że automatyczne podłączanie pola statycznego (lub stałego) zostanie zignorowane, ale także nie spowoduje żadnego błędu:

@Autowired
private static String staticField = "staticValue";

1

Możesz użyć ApplicationContextAware

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

    public AppBeans(){
    }

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

następnie

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

0

Zrzeczenie się Nie jest to bynajmniej standard i może istnieć lepszy wiosenny sposób na zrobienie tego. Żadna z powyższych odpowiedzi nie rozwiązuje problemu okablowania publicznego pola statycznego.

Chciałem osiągnąć trzy rzeczy.

  1. Użyj wiosny do „Autowire” (używam @Value)
  2. Ujawnij publiczną wartość statyczną
  3. Zapobiegaj modyfikacjom

Mój obiekt wygląda tak

private static String BRANCH = "testBranch";

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

public static String BRANCH() {
    return BRANCH;
}

Już teraz odhaczyliśmy 1 i 2, w jaki sposób zapobiegamy wywołaniom ustawiacza, skoro nie możemy tego ukryć.

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

Ten aspekt zawinie wszystkie metody zaczynające się od final i zgłosi błąd, jeśli zostaną wywołane.

Nie sądzę, żeby to było szczególnie przydatne, ale jeśli jesteś ocd i lubisz oddzielać groszek i marchewkę, jest to jeden ze sposobów, aby zrobić to bezpiecznie.

Ważne Wiosna nie wywołuje twoich aspektów, gdy wywołuje funkcję. Ułatwiłem to, a szkoda, że ​​opracowałem logikę, zanim to zrozumiałem.


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

2
Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
podwójny sygnał

Myślę, że ta odpowiedź może nie wymagać żadnego wyjaśnienia.
Chaklader Asfak Arefe
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.