2015-03-25 29 views
2

我有很多Spring RestController,其中的方法用RequestMapping註解。我現在想要在這些RequestMapping方法中注入一個自定義對象,併爲每個請求創建一個自定義實例。將一個對象的新實例注入到每個請求處理程序中

我想寫點東西像下面這樣:

@RequestMapping("/search") 
public SomeReturnObject foobar(@RequestParam("query") String query, MyRequestFoo foo) { 
    // ... 
} 

現在我想建立一種機制,在每次調用該方法(即每個請求)獲得創建和注入的MyRequestFoo一個新實例進入方法。如果使用參數註釋而不是按類型注入會更好,那也可以(例如@MyRequestInject MyRequestFoo foo)。

我需要知道,如果我現在可以創建特別是對於請求創建的MyRequestFoo一個新實例的方法,如下所示:

public MyRequestFoo createRequestInstanceSomehow(HttpServletRequest request) { 
    // extract some values from the HttpServletRequest and create a 
    // new MyRequestFoo instance from that and return it 
} 

這是可以通過任何手段來創造這樣一個機制,以便我可以將自定義每個請求對象注入到我的請求處理方法中?

回答

3

Spring MVC有一個參數解析器構造,它直接支持你的請求。每個使用@RequestMapping註解的處理程序方法都將受參數解析的影響,其中框架掃描處理程序參數,檢查類型並實例化適當的對象。這是注入請求,模型和許多其他類型的機制,只需在處理程序的方法簽名中聲明對象即可。

您可以編寫自定義參數解析器,以使自定義類型在方法中解析並可用。這個過程很簡單的三個步驟

  1. 做一個POJO類,你的情況MyRequestFoo

  2. 做一個解析,例如

    public class MyRequestFooResolver implements HandlerMethodArgumentResolver { 
    
         @Override 
         public boolean supportsParameter(MethodParameter parameter) { 
    
          return parameter.getParameterType().equals(MyRequestFoo.class); 
         } 
    
         @Override 
         public Object resolveArgument(MethodParameter parameter, 
                 ModelAndViewContainer mavContainer, 
                 NativeWebRequest webRequest, 
                 WebDataBinderFactory binderFactory) 
         throws Exception { 
    
          return new MyRequestFoo(); 
         } 
        } 
    

3.Register解析器

<mvc:annotation-driven> 
    <mvc:argument-resolvers> 
     <bean class="your.package.MyRequestFooResolver "></bean> 
    </mvc:argument-resolvers> 
</mvc:annotation-driven> 

或Java的配置

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void addArgumentResolvers(List<Handlermethodargumentresolver> argumentResolvers) { 
     MyRequestFooResolver myRequestFooResolver = new MyRequestFooResolver(); 
     argumentResolvers.add(myRequestFooResolver); 
    } 
} 

比你使用它,通過添加類型的處理方法參數

@RequestMapping("/search") 
public SomeReturnObject search(MyRequestFoo foo) { 
    // ... 
} 
+0

我現在也發佈了一個可行的答案。你能否從你的(或彈簧)角度闡述什麼是更乾淨和「更好」的方法? – 2015-03-25 08:57:55

+1

我已經看到了討論併發布了一個答案,因爲自定義參數解析是一個直接支持您的需求的概念。我會避免爭論什麼更好,但這是我會用的方法。 – 2015-03-25 09:04:22

1

如何在Controller類上放置MyRequestFoo類型的實例變量並Autowire將Bean定義中的默認範圍從「Singleton」更改爲「Request」?

檢出this鏈接或Spring參考表!

+0

但是,這將需要爲每個請求生成新的整個控制器?爲每個請求生成新的控制器看起來並不像是要在Spring中完成的。另外我還需要在創建Autowired實例時訪問HttpServletRequest,我該怎麼做? – 2015-03-25 08:23:52

+0

我相信他建議改變* dependency *的範圍,而不是控制器的範圍。 – chrylis 2015-03-25 08:31:29

+0

@chrylis不幸的是,您不能自動將請求範圍bean自動裝入非請求範圍bean(本例中爲控制器)內的實例變量。 – 2015-03-25 08:38:25

0

我找到了一個解決方案,這就是我正在嘗試做的事情。

剛剛創建MyRequestFoo與範圍「要求」一個bean,你可以通過RequestContextHolder訪問當前請求:

@Component 
@Scope("request") 
public class MyRequestFoo { 
    private final HttpServletRequest request; 

    public MyRequestFoo() { 
     request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); 
    } 

    // do whatever you want with the request 

} 

,現在我可以僅僅通過它的類型注入的這個新實例到任何請求處理程序方法:

@RequestMapping("/search") 
public SomeReturnObject search(MyRequestFoo foo) { 
    // ... 
} 

而且Spring會自動處理實例化一個新實例。

由於您不能自動將請求範圍的bean自動裝入非請求範圍的bean,因此它不適用於自動裝配MyRequestFoo作爲實例變量。

+1

這種通過靜態方法獲得的魔法依賴是一種脆弱的模式。特別是,測試非常困難。 – chrylis 2015-03-25 08:57:37

0

由於您需要將特定於請求的信息傳遞給您的bean,因此我建議將builder bean注入控制器,並從您的方法調用builder.build(request)以創建新的每個請求實例。

+1

我想避免必須將HttpServletRequest注入每個請求處理程序,然後將相同的生成器行寫入每個請求處理方法,因爲我需要它處理所有處理程序。雖然它當然會起作用。 – 2015-03-25 08:56:15

相關問題