Puoi usare @Autowired con campi statici?


Risposte:


122

In breve, no. In primavera non è possibile eseguire il collegamento automatico o collegare manualmente i campi statici. Dovrai scrivere la tua logica per farlo.


3
Quando trovi il vecchio codice che fa questo, è un anti-schema. Strizza gli occhi, inclina la testa e trova un modo migliore per risolvere il problema. Sarai contento di averlo fatto.
— Joseph Lust,

2
questa risposta è utile anche su Spring's@AutoWired
— Kevin Meredith, il

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

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

1
qualche idea su come posso usare questo approccio durante l'inizializzazione di un repository?
— kiedysktos

3
L'aspetto negativo: non esiste alcuna garanzia che someThingè stata inizializzata se si accede staticamente: NewClass.staticMethodWhichUsesSomething();potrebbe generare un NPE se utilizzato prima dell'inizializzazione dell'app
— Neeraj,

Puoi evitare l'avvertimento di Instance methods should not write to "static" fields (squid:S2696)?
— user7294900

@ user7294900: disabilitare questo avviso solo per questo caso molto specifico.
— izogfif,

@izogfif continua a rappresentare un problema se scelgo questa soluzione in casi e classi
— generali

67

@Autowired può essere utilizzato con setter in modo da poter avere un setter che modifica un campo statico.

Solo un ultimo suggerimento ... NON


54
Perché suggerisci di non farlo?
— Jon Lorusso,

3
Hmmm .. la mia sensazione sul perché non è raccomandato è, perché quindi l'istanza statica nella classe è al di fuori del controllo della molla. Una volta iniettato, il campo statico è il riferimento per tutte le istanze di oggetti della classe (circostante) corrispondente. Ma questo comportamento potrebbe essere esattamente quello che dovrebbe accadere, quindi potrebbe essere visto come un bug o una funzionalità ...
— matthaeus

1
Sì @matthaeus, è esattamente la funzionalità che mi aspettavo quando dovessi accedere a org.springframework.core.env.Ambiente:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
— user1767316

@JonLorusso e all Perché quando il caricatore di classi carica i valori statici, non è ancora necessario caricare il contesto Spring. Quindi il caricatore di classi non inietterà correttamente la classe statica nel bean e fallirà. Risposta fornita da Andrea T
— Jeril Kuruvila,

14

Iniziare il componente autowired nel metodo @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();
   }
}

Puoi evitare l'avvertimento di Instance methods should not write to "static" fields (squid:S2696)?
— user7294900

Puoi anche farlo direttamente tramite il costruttore.
— gagarwa,

5

Crea un bean che puoi autowire che inizializzerà la variabile statica come effetto collaterale.


4

È possibile ottenere ciò utilizzando la notazione XML e il MethodInvokingFactoryBean. Per un esempio guarda qui .

private static StaticBean staticBean;

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

Dovresti mirare a usare l' iniezione a molla laddove possibile in quanto questo è l'approccio raccomandato ma questo non è sempre possibile in quanto sono sicuro che puoi immaginare come non tutto può essere estratto dal contenitore a molla o forse hai a che fare con sistemi legacy.

Nota che testare può anche essere più difficile con questo approccio.


2

Volevo aggiungere alle risposte che il campo statico (o costante) del cablaggio automatico verrà ignorato, ma non creerà alcun errore:

@Autowired
private static String staticField = "staticValue";

1

È possibile utilizzare ApplicationContextAware

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

    public AppBeans(){
    }

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

poi

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

0

Disclaimer Questo non è affatto standard e potrebbe esserci un modo migliore per farlo. Nessuna delle risposte di cui sopra risolve i problemi legati al cablaggio di un campo statico pubblico.

Volevo realizzare tre cose.

  1. Usa la molla per "Autowire" (Im usando @Value)
  2. Esporre un valore statico pubblico
  3. Prevenire le modifiche

Il mio oggetto si presenta così

private static String BRANCH = "testBranch";

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

public static String BRANCH() {
    return BRANCH;
}

Abbiamo spuntato 1 e 2 già ora come possiamo impedire le chiamate al setter, dal momento che non possiamo nasconderlo.

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

Questo aspetto includerà tutti i metodi che iniziano con final e genererà un errore se vengono chiamati.

Non penso che questo sia particolarmente utile, ma se sei ocd e ti piace tenere separati piselli e carote, questo è un modo per farlo in sicurezza.

Importante Spring non chiama i tuoi aspetti quando chiama una funzione. Reso più facile, peccato che abbia elaborato la logica prima di capirlo.


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

2
Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolva il problema, contribuirebbe davvero a migliorare la qualità del tuo post e probabilmente a dare più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo per la persona che chiede ora. Si prega di modificare la risposta per aggiungere spiegazioni e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni.
— doppio segnale acustico

Penso che questa risposta potrebbe non aver bisogno di alcuna spiegazione.
— Chaklader Asfak Arefe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.