@ स्वचालित और स्थैतिक विधि


101

मेरे पास ऐसी @Autowiredसेवा है जिसका उपयोग स्थैतिक पद्धति से किया जाना है। मुझे पता है कि यह गलत है, लेकिन मैं वर्तमान डिज़ाइन को नहीं बदल सकता क्योंकि इसमें बहुत काम की आवश्यकता होगी, इसलिए मुझे इसके लिए कुछ सरल हैक की आवश्यकता है। मैं randomMethod()गैर-स्थिर होने के लिए नहीं बदल सकता और मुझे इस ऑटो-बीन का उपयोग करने की आवश्यकता है। कोई सुराग कि कैसे करना है?

@Service
public class Foo {
    public int doStuff() {
        return 1;
    }
}

public class Boo {
    @Autowired
    Foo foo;

    public static void randomMethod() {
         foo.doStuff();
    }
}

4
एक स्थैतिक विधि एक गैर-स्थैतिक / आवृत्ति क्षेत्र को संदर्भित नहीं कर सकती है।
सोतिरियोस डेलिमोलिसिन जूल

18
यही कारण है कि मैंने इस धागे का निर्माण किया है, क्या कोई ऐसा तरीका है जिससे ऑटोवेयर्ड इंस्टेंस को स्टैटिक मेथड से एक्सेस किया जा सके ...
Taks

@Autowired in static पद्धति का उपयोग क्यों गलत है?
user59290

जवाबों:


152

आप समाधान में से एक का पालन करके ऐसा कर सकते हैं:

निर्माता @Autowired का उपयोग करना

यह दृष्टिकोण बीन का निर्माण करने वाले मापदंडों के रूप में कुछ फलियों की आवश्यकता होगी। कंस्ट्रक्टर कोड के भीतर आप स्टैटिक फ़ील्ड को उस मान के साथ सेट करते हैं, जो कंस्ट्रक्टर निष्पादन के लिए पैरामीटर के रूप में मिला है। नमूना:

@Component
public class Boo {

    private static Foo foo;

    @Autowired
    public Boo(Foo foo) {
        Boo.foo = foo;
    }

    public static void randomMethod() {
         foo.doStuff();
    }
}

@PostConstruct का उपयोग स्थैतिक क्षेत्र पर हाथ मूल्य करने के लिए करें

यहाँ विचार बीन को वसंत द्वारा कॉन्फ़िगर किए जाने के बाद बीन को एक स्थिर क्षेत्र में सौंपना है।

@Component
public class Boo {

    private static Foo foo;
    @Autowired
    private Foo tFoo;

    @PostConstruct
    public void init() {
        Boo.foo = tFoo;
    }

    public static void randomMethod() {
         foo.doStuff();
    }
}

3
क्या यह एक सुरक्षित उपाय है?
taks

2
मैंने पहले समाधान का उपयोग किया और यह एक आकर्षण की तरह काम करता है, धन्यवाद!
जीत

1
पहला समाधान @Qualifier के उपयोग का समर्थन नहीं करता है। कई रिपॉजिटरी का उपयोग करने पर यह समस्याग्रस्त रहता है।
user1767316

16
क्या गारंटी देगा कि स्थिर विधि तक पहुंचने से पहले निर्माणकर्ता को बुलाया जाता है?
डेविड डोंब्रोव्स्की

2
init पद्धति सोनारक्यूब बग का कारण बनेगी क्योंकि गैर-स्थैतिक विधि स्थिर क्षेत्र को संशोधित करती है।
jDub9

45

आपको स्थैतिक अनुप्रयोग संदर्भ अभिगम दृष्टिकोण के माध्यम से इसे हल करना होगा:

@Component
public class StaticContextAccessor {

    private static StaticContextAccessor instance;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void registerInstance() {
        instance = this;
    }

    public static <T> T getBean(Class<T> clazz) {
        return instance.applicationContext.getBean(clazz);
    }

}

फिर आप स्थैतिक तरीके से बीन के उदाहरणों तक पहुंच सकते हैं।

public class Boo {

    public static void randomMethod() {
         StaticContextAccessor.getBean(Foo.class).doStuff();
    }

}

मैं वास्तव में इस समाधान को पसंद करता हूं, हालांकि मुझे यह पूरी तरह से समझ में नहीं आता है .. इम बस वसंत के आसपास मेरा सिर हो रहा है और मुझे जल्दी से कोड के कुछ टुकड़े को रिफलेक्टर करने की आवश्यकता है .. और यह ऑटोवार्ड के साथ स्थिर मिश्रण करने का मुद्दा है .. यह समाधान कितना सुरक्षित है?
१५:५३

2
यह काफी सुरक्षित है अगर स्थिर कॉल आपके नियंत्रण में हैं। सबसे स्पष्ट नकारात्मक पहलू यह है कि ऐसा हो सकता है कि आप getBeanसंदर्भ को आरंभीकृत करने से पहले कॉल करेंगे (एनपीई) या इसके सेम के साथ संदर्भ नष्ट होने के बाद। इस दृष्टिकोण का यह लाभ है कि "बदसूरत" स्थैतिक संदर्भ पहुंच एक विधि / वर्ग में संलग्न है।
पावेल होराल

1
इससे मेरी जान बच गई। अन्य दृष्टिकोण पर यह बहुत उपयोगी है।
फोनिक्स

6

आप जो कर सकते हैं वह @Autowiredएक सेटर विधि है और इसने एक नया स्थैतिक क्षेत्र निर्धारित किया है।

public class Boo {
    @Autowired
    Foo foo;

    static Foo staticFoo;   

    @Autowired
    public void setStaticFoo(Foo foo) {
        Boo.staticFoo = foo;
    }

    public static void randomMethod() {
         staticFoo.doStuff();
    }
}

जब बीन संसाधित हो जाता है, तो स्प्रिंग Fooइंस्टेंस क्षेत्र में कार्यान्वयन उदाहरण को इंजेक्ट करेगा foo। फिर यह उसी Fooउदाहरण को setStaticFoo()तर्क सूची में इंजेक्ट करेगा, जिसका उपयोग स्थैतिक क्षेत्र को सेट करने के लिए किया जाएगा।

यदि आप randomMethod()स्प्रिंग के इंस्टेंस को संसाधित करने से पहले उपयोग करने का प्रयास करते हैं तो यह एक भयानक वर्कअराउंड है और विफल हो जाएगा Boo


@PostConstruct मदद का उपयोग कर सकता है?
17

@ टैकस श्योर, वह भी काम करता है। पर setStaticFoo()कि बिना, है Fooपैरामीटर।
सोतिरियोस डेलिमोलिसिन

सवाल यह है कि यह सुरक्षित कर देगा .. :) मुझे लगा कि वसंत हमें किसी भी तरीके को निष्पादित करने की अनुमति देने से पहले सब कुछ प्रक्रिया करेगा ..
18

1
@ टैक जिस तरह से आपने दिखाया वह काम नहीं करता है (जब तक कि आप छद्म कोड नहीं दिखा रहे थे)। कोई सुराग कि कैसे करना है? आपके द्वारा प्राप्त किए गए कई उत्तर वर्करॉइड हैं, लेकिन उन सभी में एक ही समस्या है कि आप स्थिर फ़ील्ड का उपयोग नहीं कर सकते हैं जब तक कि स्प्रिंग आपकी कक्षा को संसाधित नहीं करता है (वास्तव में एक उदाहरण जो एक साइड-इफ़ेक्ट को संसाधित करता है)। इस अर्थ में, यह सुरक्षित नहीं है।
सोतिरियोस डेलिमोनोलिस

3

यह बेकार है लेकिन आप ApplicationContextAwareइंटरफ़ेस का उपयोग करके बीन प्राप्त कर सकते हैं । कुछ इस तरह :

public class Boo implements ApplicationContextAware {

    private static ApplicationContext appContext;

    @Autowired
    Foo foo;

    public static void randomMethod() {
         Foo fooInstance = appContext.getBean(Foo.class);
         fooInstance.doStuff();
    }

    @Override
    public void setApplicationContext(ApplicationContext appContext) {
        Boo.appContext = appContext;
    }
}

0

यह स्टैटिक गेटबैन विधि से एक्सेस करते समय वसंत संदर्भ की संभावना को हल करने के लिए @ पावेल के उत्तर पर बनाता है :

@Component
public class Spring {
  private static final Logger LOG = LoggerFactory.getLogger (Spring.class);

  private static Spring spring;

  @Autowired
  private ApplicationContext context;

  @PostConstruct
  public void registerInstance () {
    spring = this;
  }

  private Spring (ApplicationContext context) {
    this.context = context;
  }

  private static synchronized void initContext () {
    if (spring == null) {
      LOG.info ("Initializing Spring Context...");
      ApplicationContext context = new AnnotationConfigApplicationContext (io.zeniq.spring.BaseConfig.class);
      spring = new Spring (context);
    }
  }

  public static <T> T getBean(String name, Class<T> className) throws BeansException {
    initContext();
    return spring.context.getBean(name, className);
  }

  public static <T> T getBean(Class<T> className) throws BeansException {
    initContext();
    return spring.context.getBean(className);
  }

  public static AutowireCapableBeanFactory getBeanFactory() throws IllegalStateException {
    initContext();
    return spring.context.getAutowireCapableBeanFactory ();
  }
}

यहां महत्वपूर्ण टुकड़ा initContextविधि है। यह सुनिश्चित करता है कि संदर्भ हमेशा आरंभीकृत हो जाएगा। लेकिन, ध्यान दें कि initContextआपके कोड में विवाद का बिंदु होगा क्योंकि यह सिंक्रनाइज़ है। यदि आपका एप्लिकेशन बहुत अधिक समानांतर है (उदाहरण के लिए: उच्च ट्रैफ़िक साइट का बैकएंड), तो यह आपके लिए एक अच्छा समाधान नहीं हो सकता है।


-2

AppContext का उपयोग करें। सुनिश्चित करें कि आप अपनी संदर्भ फ़ाइल में बीन बनाएँ।

private final static Foo foo = AppContext.getApplicationContext().getBean(Foo.class);

public static void randomMethod() {
     foo.doStuff();
}

यह क्या है?? Whats @ अंतर और getBean के बीच अंतर
madhairsilence

यह सामान्य है जब आप कक्षा को एक नियमित वसंत @ कॉमपॉइंट में नहीं बदल सकते हैं, यह विरासत कोड के साथ बहुत कुछ होता है।
carpinchosaurio
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.