2014-11-18 15 views
7

Quando utilizzo l'HandlerInterceptor personalizzato e il mio controller restituisce DeferredResult, il metodo preHandle del mio intercettore personalizzato chiamato due volte su ogni richiesta. Considera un esempio di giocattolo.Spring MVC InterceptorHandler ha chiamato due volte con DeferredResult

mio intercettore personalizzato:

public class MyInterceptor implements HandlerInterceptor { 
    static int i = 0; 

    @Override 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
     System.out.println(i++); 
     return true; 
    } 

    @Override 
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
    } 

    @Override 
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 
    } 
} 

la mia primavera Java configurazione:

@Configuration 
@EnableWebMvc 
public class ApplicationConfiguration extends WebMvcConfigurerAdapter { 

    @Override 
    public void addInterceptors(InterceptorRegistry registry) { 
     registry.addInterceptor(new MyInterceptor()); 
    } 
} 

mio controller:

@Controller 
public class MyController { 

    @RequestMapping(value = "/test", method = RequestMethod.GET) 
    public DeferredResult<String> test() { 
     DeferredResult<String> df = new DeferredResult<String>(); 
     df.setResult("blank"); 
     return df; 
    } 
} 

Così, ad ogni caricamento della pagina vedo due uscite da preHandle metodo . Tuttavia, se modifico MyController per restituire solo un modello "vuoto" (anziché DeferredResult con modello "vuoto"), vedo solo un'uscita da preHandle su ogni caricamento di pagina.

Quindi, la mia domanda è perché preHandle chiamato due volte quando uso DeferredResult ed è possibile evitare questo?

+0

vedi [questa] (http://stackoverflow.com/questions/15357990/understanding-the-spring-mvcs-deferredresult-class-in-the-context-of-the-spring), che ha il comportamento spiegato in dettaglio. –

+0

@JavaBond puoi fornire ulteriori dettagli, dal momento che non ho capito la spiegazione di quel post. –

+0

citando dalla [risposta accettata] (http://stackoverflow.com/a/15384965/1910582) 'In parole povere. Un DeferredResult è associato a una richiesta aperta. Una volta completata la richiesta, DeferredResult viene rimosso dalla mappa e, successivamente, il client invia una nuova richiesta di polling lunga, che aggiunge una nuova istanza DeferredResult' che significa che viene emessa una nuova richiesta dal client a cui è associato il 'DeferredResult' risposta. Che a sua volta spiega perché hai due invocazioni intercettore per ogni richiesta. Fammi sapere se hai bisogno di ulteriori spiegazioni. –

risposta

8

è necessario utilizzare org.springframework.web.servlet.AsyncHandlerInterceptor:

public interface AsyncHandlerInterceptor extends HandlerInterceptor { 

    void afterConcurrentHandlingStarted(
      HttpServletRequest request, HttpServletResponse response, Object handler) 
      throws Exception; 

} 

Spring MVC eseguire sequenza:

preHandle 
afterConcurrentHandlingStarted 
preHandle 
postHandle 
afterCompletion 
+0

Non riesco a ottenere il metodo 'afterConcurrentHandlingStarted' da eseguire. La mia app non eseguiva il codice ma eseguiva il 'preHandle'. – SomeGuyOnAComputer

1

Mentre sto esplorando l'aggiunta di filtro e Interceptor, sono sicuro che sia causato da chiamate asincrone. Si utilizza DeferredResult qui, che molla eseguirà il filtro nel thread di origine e lo filtrerà nuovamente in una nuova discussione. Se si imposta il livello di registro su Debug, si noterà un registro come questo.

15:14:06.948 [http-nio-8199-exec-5] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.se[email protected]efe6068 
15:14:06.948 [http-nio-8199-exec-5] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 
15:14:06.948 [http-nio-8199-exec-5] DEBUG o.s.b.w.f.OrderedRequestContextFilter - Cleared thread-bound request context: [email protected] 
15:14:07.148 [http-nio-8199-exec-6] DEBUG o.s.b.w.f.OrderedRequestContextFilter - Bound request context to thread: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ [email protected]]] 

In una parola, è eseguito una volta in un thread, ma here're due fili.

Come ho scavato il google, ho trovato che non c'è una buona soluzione. Se è richiesta un'autenticazione su richiesta, è necessario aggiungere un passaggio security.filter-dispatcher-types = RICHIESTA, ERRORE Quindi il nuovo thread (async) non otterrà il contesto di sicurezza. Devi controllarlo e fermare la catena del filtro al suo interno.

Oppure basta usare la chiamata di sincronizzazione tranditional come:

@RequestMapping(value = "/test", method = RequestMethod.GET) 
public String test() { 
    return "blank"; 
} 

ho trovato un'altra risposta utile. https://jira.spring.io/browse/SPR-12608

Spero che aiuti!

1

Ho seguito quello indicato @thunder controllando il valore di request.getDispatcherType() e questo ha funzionato per me.

public class MyInterceptor extends HandlerInterceptorAdapter { 

    @Override 
    public boolean preHandle(HttpServletRequest request, 
          HttpServletResponse response, 
          Object handler) throws Exception { 
     // only allows the REQUEST dispatcher and ignores the ERROR and any other dispatchers 
     // this prevents the preHandle function from running multiple times 
     if (request.getDispatcherType().name() != "REQUEST") { 
      return true; 
     } 
     // ... continue 
     return true; 
    } 
} 
Problemi correlati