Pouvez-vous utiliser @Autowired avec des champs statiques?

Réponses:

122

En bref, non. Vous ne pouvez pas câbler automatiquement ou câbler manuellement les champs statiques dans Spring. Vous devrez écrire votre propre logique pour ce faire.

skaffman
la source
3
Lorsque vous trouvez un ancien code faisant cela, c'est un anti-pattern. Louchez, inclinez la tête et trouvez une meilleure façon de résoudre le problème. Vous serez heureux de l'avoir fait.
Joseph Lust
2
cette réponse est également utile sur Spring's@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
la source
1
une idée de la façon dont je peux utiliser cette approche lors de l'initialisation d'un référentiel?
kiedysktos
3
L'inconvénient: il n'y a aucune garantie qui someThinga été initialisée en cas d'accès statique: NewClass.staticMethodWhichUsesSomething();peut lancer un NPE s'il est utilisé avant l'initialisation de l'application
Neeraj
Pouvez-vous éviter l'avertissement de Instance methods should not write to "static" fields (squid:S2696)?
user7294900
@ user7294900: désactivez cet avertissement pour ce seul cas très spécifique.
izogfif
@izogfif encore un problème si je choisis cette solution dans des cas et des classes
larges
67

@Autowired peut être utilisé avec des setters afin que vous puissiez avoir un setter modifiant un champ statique.

Juste une dernière suggestion ... NE PAS

Victor Hugo
la source
54
Pourquoi suggérez-vous de ne pas faire cela?
Jon Lorusso du
3
Hmmm .. mon sentiment sur la raison pour laquelle ce n'est pas recommandé est, car alors l'instance statique dans la classe est au-delà du contrôle de spring. Une fois injecté, le champ statique est la référence pour toutes les instances d'objets de la classe correspondante (environnante). Mais, ce comportement pourrait être exactement ce qui devrait se produire, donc pourrait être considéré comme un bogue ou une fonctionnalité ...
matthaeus
1
Oui @matthaeus, c'est exactement la fonctionnalité à laquelle je m'attendais lorsque j'ai besoin d'accéder à org.springframework.core.env.Environment:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316
@JonLorusso et tout Parce que lorsque le chargeur de classe charge les valeurs statiques, le contexte Spring n'est pas encore nécessaire chargé. Ainsi, le chargeur de classe n'injectera pas correctement la classe statique dans le bean et échouera. Réponse fournie par Andrea T
Jeril Kuruvila
14

Initiez votre composant câblé automatiquement dans la méthode @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
la source
Pouvez-vous éviter l'avertissement de Instance methods should not write to "static" fields (squid:S2696)?
user7294900
Vous pouvez également le faire directement via le constructeur.
gagarwa le
5

Créez un bean que vous pouvez câbler automatiquement qui initialisera la variable statique comme un effet secondaire.

Jherico
la source
4

Vous pouvez y parvenir en utilisant la notation XML et le MethodInvokingFactoryBean. Pour un exemple, regardez ici .

private static StaticBean staticBean;

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

Vous devez viser à utiliser l'injection à ressort lorsque cela est possible car c'est l'approche recommandée mais ce n'est pas toujours possible, car je suis sûr que vous pouvez l'imaginer car tout ne peut pas être retiré du conteneur à ressort ou vous avez peut-être affaire à des systèmes hérités.

Les tests de notes peuvent également être plus difficiles avec cette approche.

JARC
la source
2

Je voulais ajouter aux réponses que le champ statique de câblage automatique (ou constante) sera ignoré, mais ne créera également aucune erreur:

@Autowired
private static String staticField = "staticValue";
user7294900
la source
1

Vous pouvez utiliser ApplicationContextAware

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

    public AppBeans(){
    }

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

puis

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

Avertissement de non- Ce n'est en aucun cas une norme et il pourrait très bien y avoir une meilleure façon de procéder au printemps. Aucune des réponses ci-dessus n'aborde les problèmes de câblage d'un champ statique public.

Je voulais accomplir trois choses.

  1. Utilisez le ressort pour "Autowire" (Im using @Value)
  2. Exposez une valeur statique publique
  3. Empêcher la modification

Mon objet ressemble à ceci

private static String BRANCH = "testBranch";

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

public static String BRANCH() {
    return BRANCH;
}

Nous avons déjà coché 1 et 2 comment empêcher les appels au passeur, car nous ne pouvons pas le cacher.

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

Cet aspect encapsulera toutes les méthodes commençant par final et lèvera une erreur si elles sont appelées.

Je ne pense pas que cela soit particulièrement utile, mais si vous avez envie de séparer les pois et les carottes, c'est une façon de le faire en toute sécurité.

Important Spring n'appelle pas vos aspects lorsqu'il appelle une fonction. Rendu cela plus facile, c'est dommage, j'ai élaboré la logique avant de comprendre cela.

jozsef morrissey
la source
-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
Amol Kakade
la source
2
Bien que ce code puisse résoudre la question, inclure une explication sur comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre message et entraînerait probablement plus de votes à la hausse. N'oubliez pas que vous répondez à la question des lecteurs à l'avenir, pas seulement à la personne qui la pose maintenant. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limites et des hypothèses applicables.
double bip
Je pense que cette réponse n'a peut-être pas besoin d'explication du tout.
Chaklader Asfak Arefe