Können Sie @Autowired mit statischen Feldern verwenden?

Antworten:

122

Kurz gesagt, nein. Sie können statische Felder in Spring nicht automatisch verdrahten oder manuell verdrahten. Sie müssen Ihre eigene Logik schreiben, um dies zu tun.

Skaffman
quelle
2
Wenn Sie dabei alten Code finden, handelt es sich um ein Anti-Pattern. Schielen Sie, neigen Sie Ihren Kopf und finden Sie einen besseren Weg, um das Problem zu lösen. Du wirst es nicht bereuen.
Joseph Lust
2
Diese Antwort ist auch hilfreich bei 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
quelle
1
Haben Sie eine Idee, wie ich diesen Ansatz beim Initialisieren eines Repositorys verwenden kann?
Kiedysktos
3
Der Nachteil: Es gibt keine Garantie, someThingdie initialisiert wurde, wenn statisch zugegriffen wurde: NewClass.staticMethodWhichUsesSomething();Kann eine NPE auslösen, wenn sie vor der App-Initialisierung verwendet wird
Neeraj
Können Sie die Warnung vermeiden Instance methods should not write to "static" fields (squid:S2696)?
user7294900
@ user7294900: Deaktiviere diese Warnung nur für diesen sehr speziellen Fall.
izogfif
@izogfif immer noch ein Problem, wenn ich diese Lösung in weiten Fällen und Klassen
wähle
67

@Autowired kann mit Setzern verwendet werden, sodass ein Setter ein statisches Feld ändern kann.

Nur ein letzter Vorschlag ... NICHT

Victor Hugo
quelle
54
Warum schlagen Sie vor, dies nicht zu tun?
Jon Lorusso
3
Hmmm .. mein Gefühl, warum es nicht empfohlen wird, ist, weil dann die statische Instanz in der Klasse außerhalb der Kontrolle der Feder liegt. Nach der Injektion ist das statische Feld die Referenz für alle Instanzen von Objekten der entsprechenden (umgebenden) Klasse. Aber dieses Verhalten könnte genau das sein, was erwartet wird, und könnte daher als Fehler oder Feature angesehen werden ...
Matthaeus
1
Ja @matthaeus, es ist genau die Funktion, die ich erwartet hatte, als ich auf org.springframework.core.env.Environment zugreifen musste:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316
@ JonLorusso und alle Denn wenn der Klassenlader die statischen Werte lädt, muss der Spring-Kontext noch nicht geladen werden. Der Klassenlader fügt die statische Klasse daher nicht ordnungsgemäß in die Bean ein und schlägt fehl. Antwort von Andrea T
Jeril Kuruvila
14

Initialisieren Sie Ihre automatisch verdrahtete Komponente in der @ PostConstruct-Methode

@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
quelle
Können Sie die Warnung vermeiden Instance methods should not write to "static" fields (squid:S2696)?
user7294900
Sie können dies auch direkt über den Konstruktor tun.
Gagarwa
5

Erstellen Sie eine Bean, die Sie automatisch verdrahten können, um die statische Variable als Nebeneffekt zu initialisieren.

Jherico
quelle
4

Sie können dies mit der XML-Notation und der erreichen MethodInvokingFactoryBean. Ein Beispiel finden Sie hier .

private static StaticBean staticBean;

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

Sie sollten nach Möglichkeit die Federeinspritzung verwenden, da dies der empfohlene Ansatz ist , dies ist jedoch nicht immer möglich, da Sie sich sicher vorstellen können, dass nicht alles aus dem Federbehälter gezogen werden kann oder Sie sich möglicherweise mit Legacy-Systemen befassen.

Das Testen von Noten kann mit diesem Ansatz auch schwieriger sein.

JARC
quelle
1

Sie können ApplicationContextAware verwenden

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

    public AppBeans(){
    }

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

dann

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

Wollte zu den Antworten hinzufügen, dass das statische Feld (oder die Konstante) der automatischen Verkabelung ignoriert wird, aber auch keinen Fehler erzeugt:

@Autowired
private static String staticField = "staticValue";
user7294900
quelle
0

Haftungsausschluss Dies ist keineswegs Standard und es könnte durchaus einen besseren Frühlingsweg geben, dies zu tun. Keine der obigen Antworten befasst sich mit der Verdrahtung eines öffentlichen statischen Feldes.

Ich wollte drei Dinge erreichen.

  1. Verwenden Sie die Feder für "Autowire" (ich verwende @Value)
  2. Stellen Sie einen öffentlichen statischen Wert bereit
  3. Änderungen verhindern

Mein Objekt sieht so aus

private static String BRANCH = "testBranch";

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

public static String BRANCH() {
    return BRANCH;
}

Wir haben bereits 1 & 2 abgehakt, wie wir Anrufe an den Setter verhindern können, da wir sie nicht ausblenden können.

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

Dieser Aspekt umschließt alle Methoden, die mit final beginnen, und gibt einen Fehler aus, wenn sie aufgerufen werden.

Ich denke nicht, dass dies besonders nützlich ist, aber wenn Sie ok sind und Ihre Erbsen und Karotten getrennt halten möchten, ist dies eine Möglichkeit, dies sicher zu tun.

Wichtig Spring ruft Ihre Aspekte nicht auf, wenn es eine Funktion aufruft. Das wurde einfacher, schade, dass ich die Logik ausgearbeitet habe, bevor ich das herausgefunden habe.

jozsef morrissey
quelle
-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
Amol Kakade
quelle
2
Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten.
Doppel-Piepton
Ich denke, diese Antwort bedarf möglicherweise keiner Erklärung.
Chaklader Asfak Arefe