2011-12-06 13 views
7
  1. ServletScopes.scopeRequest() का उपयोग कैसे किया जाता है?
  2. मैं कॉल करने योग्य के अंदर @RequestScoped ऑब्जेक्ट का संदर्भ कैसे प्राप्त करूं?
  3. seedMap का बिंदु क्या है? क्या इसका मतलब डिफ़ॉल्ट बाध्यकारी को ओवरराइड करना है?
  4. इस विधि और ServletScopes.continueRequest() के बीच क्या अंतर है?

उत्तर

12

मेरे अपने प्रश्न का उत्तर देना:

  1. ServletScopes.scopeRequest() एक नई अनुरोध दायरे में एक प्रतिदेय चलाता है। अलग-अलग क्षेत्रों में ऑब्जेक्ट्स का संदर्भ न देने के लिए सावधान रहें, अन्यथा आप थ्रेडिंग समस्याओं के साथ समाप्त हो जाएंगे जैसे डेटाबेस कनेक्शन का उपयोग करने का प्रयास करना जो किसी अन्य अनुरोध से पहले ही बंद हो चुका है। static या शीर्ष-स्तरीय कक्षाएं यहां आपका मित्र हैं।
  2. में ServletScopes.scopeRequest() में जाने से पहले आप इंजेक्ट करते हैं। इस कारण से, आपको सावधान रहना चाहिए कि आपके Callable में फ़ील्ड क्या हैं। नीचे इस पर अधिक।
  3. seedMap आप गुंजाइश में गैर scoped वस्तुओं इंजेक्षन कर सकते हैं। यह खतरनाक है इसलिए आप जो इंजेक्ट करते हैं उससे सावधान रहें।
  4. ServletScopes.continueRequest() समान है कि यह मौजूदा अनुरोध दायरे के अंदर चलाता है। यह वर्तमान HTTP दायरे का एक स्नैपशॉट लेता है और इसे कॉल करने योग्य में लपेटता है। मूल HTTP अनुरोध पूर्ण हो जाता है (आप सर्वर से कुछ प्रतिक्रिया वापस कर देते हैं) लेकिन फिर एक अलग थ्रेड में वास्तविक ऑपरेशन को असीमित रूप से पूरा करें। जब कॉल करने योग्य कुछ बाद के समय (उस अलग थ्रेड में) पर आक्रमण किया जाता है तो उसे मूल HttpServletRequest तक पहुंच होगी, लेकिन HTTP प्रतिक्रिया या सत्र नहीं।

तो, ऐसा करने का सबसे अच्छा तरीका क्या है?

आप Callable में उपभोक्ता-वस्तुओं के पारित करने के लिए की जरूरत है नहीं है: यह ServletScopes.scopeRequest() में पारित अनुरोध दायरे से बाहर Callable सम्मिलित करें, और। Callable केवल Foo के बजाय Provider<Foo> का संदर्भ दे सकता है, अन्यथा आप अनुरोध दायरे के बाहर इंजेक्शन वाले मामलों के साथ समाप्त हो जाएंगे।

यदि आपको Callable में उपयोगकर्ता-ऑब्जेक्ट्स पास करने की आवश्यकता है, तो पढ़ें।

कहें कि आपके पास एक तरीका है जो डेटाबेस में नाम डालता है। Callable में नाम पारित करने के दो तरीके हैं।

दृष्टिकोण 1: पास उपभोक्ता-वस्तुओं के एक बच्चे के मॉड्यूल का उपयोग कर:

  1. परिभाषित InsertName, एक Callable कि डेटाबेस में सम्मिलित करता है:

    @RequestScoped 
    private static class InsertName implements Callable<Boolean> 
    { 
        private final String name; 
        private final Connection connection; 
    
        @Inject 
        public InsertName(@Named("name") String name, Connection connection) 
        { 
        this.name = name; 
        this.connection = connection; 
        } 
    
        @Override 
        public Boolean call() 
        { 
        try 
        { 
         boolean nameAlreadyExists = ...; 
         if (!nameAlreadyExists) 
         { 
         // insert the name 
         return true; 
         } 
         return false; 
        } 
        finally 
        { 
         connection.close(); 
        } 
        } 
    } 
    
  2. बाइंड सभी उपभोक्ता-वस्तुओं में एक बच्चे मॉड्यूल और RequestInjector का उपयोग कर कॉल करने योग्य दायरा।scopeRequest():

    requestInjector.scopeRequest(InsertName.class, new AbstractModule() 
    { 
        @Override 
        protected void configure() 
        { 
        bind(String.class).annotatedWith(Names.named("name")).toInstance("John"); 
        } 
    }) 
    
  3. हम अनुरोध के बाहर एक RequestInjector का दृष्टांत और यह, बारी में, एक दूसरे Callable अनुरोध अंदर injects। दूसरा Callable सीधे Foo संदर्भ (प्रदाता के लिए कोई आवश्यकता नहीं) संदर्भित कर सकता है क्योंकि यह अनुरोध दायरे के अंदर इंजेक्शन दिया गया है।

import com.google.common.base.Preconditions; 
import com.google.inject.Inject; 
import com.google.inject.Injector; 
import com.google.inject.Key; 
import com.google.inject.Module; 
import com.google.inject.servlet.ServletScopes; 
import java.util.Collections; 
import java.util.Map; 
import java.util.concurrent.Callable; 

/** 
* Injects a Callable into a non-HTTP request scope. 
* <p/> 
* @author Gili Tzabari 
*/ 
public final class RequestInjector 
{ 
    private final Map<Key<?>, Object> seedMap = Collections.emptyMap(); 
    private final Injector injector; 

    /** 
    * Creates a new RequestInjector. 
    */ 
    @Inject 
    private RequestInjector(Injector injector) 
    { 
     this.injector = injector; 
    } 

    /** 
    * Scopes a Callable in a non-HTTP request scope. 
    * <p/> 
    * @param <V> the type of object returned by the Callable 
    * @param callable the class to inject and execute in the request scope 
    * @param modules additional modules to install into the request scope 
    * @return a wrapper that invokes delegate in the request scope 
    */ 
    public <V> Callable<V> scopeRequest(final Class<? extends Callable<V>> callable, 
     final Module... modules) 
    { 
     Preconditions.checkNotNull(callable, "callable may not be null"); 

     return ServletScopes.scopeRequest(new Callable<V>() 
     { 
      @Override 
      public V call() throws Exception 
      { 
       return injector.createChildInjector(modules).getInstance(callable).call(); 
      } 
     }, seedMap); 
    } 
} 

दृष्टिकोण 2: अनुरोध संदर्भ Provider<Foo> बाहर एक Callable सम्मिलित करें। call() विधि अनुरोध स्कोप के अंदर वास्तविक मान get() कर सकते हैं।

  1. परिभाषित InsertName, एक Callable कि डेटाबेस में सम्मिलित करता है: वस्तु वस्तुओं एक seedMap के माध्यम से में पारित कर रहे हैं (मैं व्यक्तिगत रूप से इस दृष्टिकोण जवाबी सहज लगता है)। ध्यान दें कि दृष्टिकोण 1 के विपरीत, हम Providers का उपयोग करना चाहिए:

    @RequestScoped 
    private static class InsertName implements Callable<Boolean> 
    { 
        private final Provider<String> name; 
        private final Provider<Connection> connection; 
    
        @Inject 
        public InsertName(@Named("name") Provider<String> name, Provider<Connection> connection) 
        { 
        this.name = name; 
        this.connection = connection; 
        } 
    
        @Override 
        public Boolean call() 
        { 
        try 
        { 
         boolean nameAlreadyExists = ...; 
         if (!nameAlreadyExists) 
         { 
         // insert the name 
         return true; 
         } 
         return false; 
        } 
        finally 
        { 
         connection.close(); 
        } 
        } 
    } 
    
  2. प्रकार आप में पास करना चाहते हैं के लिए फर्जी बाइंडिंग बनाएं यदि आप आप नहीं है मिल जाएगा:। No implementation for String annotated with @com.google.inject.name.Named(value=name) was bound.https://stackoverflow.com/a/9014552/14731 बताते हैं कि ऐसा क्यों की जरूरत है।

  3. वांछित मूल्यों के साथ seedMap भरें:

    ImmutableMap<Key<?>, Object> seedMap = ImmutableMap.<Key<?>, Object>of(Key.get(String.class, Names.named("name")), "john"); 
    
  4. आह्वान ServletScopes.scopeRequest():

    ServletScopes.scopeRequest(injector.getInstance(InsertName.class), seedMap); 
    
संबंधित मुद्दे