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.