最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?web開發(fā)教程之Request獲取3種方式

 更新時間:2023年11月22日 16:06:23   作者:lzzyok  
這篇文章主要給大家介紹了關(guān)于Spring?web開發(fā)教程之Request獲取3種方式的相關(guān)資料,request對象是從客戶端向服務(wù)器發(fā)出請求,包括用戶提交的信息以及客戶端的一些信息,需要的朋友可以參考下

前言

在開發(fā) Java Web 項目中,我們經(jīng)常使用 HttpServletRequest 獲取請求參數(shù)、請求頭等信息。在Spring項目,我們通常會使用 Spring 提供的注解獲取參數(shù),如 @RequestParam、@RequestHeader。

不過在某些場景下,我們可能需要從 HttpServletRequest 對象中取得更多的能力,如獲取請求 IP,獲取請求域名等。這篇我們來學(xué)習(xí)如何在 Spring MVC 環(huán)境下獲取 HttpServletRequest,以及它們的實現(xiàn)方式,做到知其所以然。

Controller 方法參數(shù)

使用注解后的 Spring MVC controller 方法可以作為 handler 處理請求,如果想獲取 request 對象,只需要在方法中添加 ServletRequest 或 HttpServletRequest 類型參數(shù)即可。代碼如下

@RestController
public class UserController {

    @GetMapping("/getUser")
    public String getUser(HttpServletRequest request) {
        return "request ip is : " + request.getRemoteHost();
    }

}

擴(kuò)展:如何要獲取reponse,同例只要在方法中增加 ServletResponse 或 HttpServletResponse 類型參數(shù)即可。

Controller 方法參數(shù)實現(xiàn)原理

通過上面的代碼我們很容易就實現(xiàn)了,那spring是怎么幫我們搞定的呢?

  • 在spring mvc中,所有瀏覽器發(fā)起的請求都會先交給DispatcherServlet 處理。
  • DispatcherServlet 根據(jù)用戶或默認(rèn)的配置使用 HandlerMapping 查找可處理請求的處理器。
  • DispatcherServlet 拿到 HandlerMapping 返回的處理器鏈 HandlerExecutionChain。整個處理器鏈包含攔截器和處理。
  • DispatcherServlet 將處理器適配為 HandlerAdapter。
  • DispatcherServlet 使用攔截器進(jìn)行請求前置處理。
  • DispatcherServlet 使用處理器進(jìn)行請求處理。
  • DispatcherServlet 使用攔截器進(jìn)行請求后置處理。
  • DispatcherServlet 從攔截器或處理器中提取到模型及視圖 ModelAndView。
  • DispatcherServlet 使用視圖解析器 ViewResolver 解析視圖出視圖 View。
  • DispatcherServlet 渲染視圖,響應(yīng)請求返回給瀏覽器。

在上面第6步【DispatcherServlet 使用處理器進(jìn)行請求處理】時,在調(diào)用我們自己的controller方法之前,Spring通過
HandlerMethodArgumentResolver向我們的controller方法注入對應(yīng)的參數(shù)。

靜態(tài)方法

除了通過 controller 方法參數(shù)獲取 HttpServletRequest 對象,Spring 還允許通過其提供的工具類的靜態(tài)方法來獲取 HttpServletRequest。示例如下。

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

靜態(tài)方法實現(xiàn)原理

上面的示例中,RequestContextHolder 表示一個請求上下文的持有者,內(nèi)部將每個請求上下文信息存儲到 ThreadLocal 中。

public abstract class RequestContextHolder {

  /**
   * 線程上下文 RequestAttributes
   */
  private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
      new NamedThreadLocal<>("Request attributes");

  /**
   * 支持繼承的線程上下文 RequestAttributes
   */
  private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
      new NamedInheritableThreadLocal<>("Request context");

}

DispatcherServlet 處理請求前會將 request 存至 ServletRequestAttributes,然后放到 RequestContextHolder 中,具體可見DispatcherServlet的父類
FrameworkServlet.processRequest()。

直接注入

還可以將 HttpServletRequest 當(dāng)做普通的 bean 注入。代碼如下

@RestController
public class UserController {

    @Autowired
    private HttpServletRequest request;

    @GetMapping("/getIP")
    public String getIP() {
        return "request ip is : " + request.getRemoteHost();
    }

}

直接注入分析

通過 @Autowired 的方式引入 request 也很簡單,想想這里會有問題嗎?.......

Controller 不是一個單例 bean 對象嗎?在一個 Spring 容器內(nèi)只有一個實例,而每次請求都對應(yīng)一個 request 對象,Spring 是怎樣做到使用一個 request 表示多個請求的?

經(jīng)過仔細(xì)分析,我們可以發(fā)現(xiàn) Spring 注入 bean 時使用了底層的 
DefaultListableBeanFactory 獲取 bean 實例,相關(guān)代碼如下。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
  // 不依賴關(guān)系
  private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
   // 查找候選 bean
  protected Map<String, Object> findAutowireCandidates(
      @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {  
    //部分代碼省略
    Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
    
    for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
      Class<?> autowiringType = classObjectEntry.getKey();
      if (autowiringType.isAssignableFrom(requiredType)) {
        Object autowiringValue = classObjectEntry.getValue();
        // 解析 ObjectFactory
        autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
        if (requiredType.isInstance(autowiringValue)) {
          result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
          break;
        }
      }
    }
    //部分代碼省略
    }
}

DefaultListableBeanFactory 查找候選 bean 時會先從 resolvableDependencies 中查找,找到后調(diào)用 AutowireUtils.resolveAutowiringValue方法再次解析。

resolvableDependencies中對象是 Spring 中特殊的存在,不屬于 Spring 管理的 bean,需要手動注冊到 
DefaultListableBeanFactory。

我們繼續(xù)跟蹤源碼。

abstract class AutowireUtils {
  public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
    if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
      // ObjectFactory 類型值和所需類型不匹配,創(chuàng)建代理對象
      ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
      if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
        // 創(chuàng)建代理對象,可用于處理 HttpServletRequest 注入等問題
        autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
            new Class<?>[]{requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
      } else {
        return factory.getObject();
      }
    }
    return autowiringValue;
  }
}

當(dāng)resolvableDependencies中對象是ObjectFactory 類型,并且與所需的類型不匹配,Spring 使用 ObjectFactory 創(chuàng)建了一個 JDK 代理對象:

private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {

    private final ObjectFactory<?> objectFactory;

    public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {
      this.objectFactory = objectFactory;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       try {
        return method.invoke(this.objectFactory.getObject(), args);
      } catch (InvocationTargetException ex) {
        throw ex.getTargetException();
      }
    }
  }

代理的實現(xiàn)簡單,每當(dāng)所需類型的方法調(diào)用時,就調(diào)用 ObjectFactory 中獲取的實例對象的對應(yīng)方法。

那怎么與HttpServletRequest關(guān)聯(lián)啟來呢?

Spring 在啟動時會注冊 Web 環(huán)境相關(guān)的依賴對象

public abstract class WebApplicationContextUtils {

  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
                          @Nullable ServletContext sc) {

    beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
    beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
    if (sc != null) {
      ServletContextScope appScope = new ServletContextScope(sc);
      beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
      // Register as ServletContext attribute, for ContextCleanupListener to detect it.
      sc.setAttribute(ServletContextScope.class.getName(), appScope);
    }
    // ServletRequest 類型對應(yīng) ObjectFactory 注冊
    beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
    beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
    if (jsfPresent) {
      FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
    }
  }
  
}

可以看到:Spring 為 ServletRequest 注入的是 RequestObjectFactory 類型,那再看看它的實現(xiàn):

public abstract class WebApplicationContextUtils {

  private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {

    @Override
    public ServletRequest getObject() {
      return currentRequestAttributes().getRequest();
    }
	/**
	 * Return the current RequestAttributes instance as ServletRequestAttributes.
	 * @see RequestContextHolder#currentRequestAttributes()
	 */
	private static ServletRequestAttributes currentRequestAttributes() {
		RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
		if (!(requestAttr instanceof ServletRequestAttributes)) {
			throw new IllegalStateException("Current request is not a servlet request");
		}
		return (ServletRequestAttributes) requestAttr;
	}
    @Override
    public String toString() {
      return "Current HttpServletRequest";
    }
  }
}

可以看到,和前面介紹的【靜態(tài)方法】思路一樣。

以上就是3種在spring場景中,獲取request的方法,get到了嗎?

總結(jié)

到此這篇關(guān)于Spring web開發(fā)教程之Request獲取3種方式的文章就介紹到這了,更多相關(guān)Spring web獲取Request內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解析SpringCloud簡介與微服務(wù)架構(gòu)

    解析SpringCloud簡介與微服務(wù)架構(gòu)

    這篇文章主要介紹了SpringCloud簡介與微服務(wù)架構(gòu),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • JavaWeb使用mvc模式實現(xiàn)登錄功能

    JavaWeb使用mvc模式實現(xiàn)登錄功能

    本文主要介紹了JavaWeb使用mvc模式實現(xiàn)登錄功能,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • SSH框架網(wǎng)上商城項目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示

    SSH框架網(wǎng)上商城項目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示

    SSH框架網(wǎng)上商城項目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示,提供了豐富的選擇、排序、分組和編輯數(shù)據(jù)的功能支持,感興趣的小伙伴們可以參考一下
    2016-05-05
  • SpringBoot集成WebService(wsdl)實踐

    SpringBoot集成WebService(wsdl)實踐

    文章介紹了Spring Boot項目中通過緩存IWebService接口實現(xiàn)類的泛型入?yún)㈩愋?減少反射調(diào)用提升性能的實現(xiàn)方案,包含依賴配置、工具類封裝、接口定義及soapUI調(diào)用參數(shù)說明
    2025-09-09
  • 通過MyBatis讀取數(shù)據(jù)庫數(shù)據(jù)并提供rest接口訪問

    通過MyBatis讀取數(shù)據(jù)庫數(shù)據(jù)并提供rest接口訪問

    這篇文章主要介紹了通過MyBatis讀取數(shù)據(jù)庫數(shù)據(jù)并提供rest接口訪問 的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • Netty分布式客戶端接入流程初始化源碼分析

    Netty分布式客戶端接入流程初始化源碼分析

    這篇文章主要介紹了Netty分布式客戶端接入流程初始化源碼分析,有關(guān)channelConfig有關(guān)的初始化過程剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-03-03
  • Java中InputStream重復(fù)使用問題的幾種解決方案

    Java中InputStream重復(fù)使用問題的幾種解決方案

    在Java開發(fā)中,InputStream是用于讀取字節(jié)流的類,在許多場景下,我們可能需要重復(fù)讀取InputStream中的數(shù)據(jù),這篇文章主要介紹了Java中InputStream重復(fù)使用問題的幾種解決方案,需要的朋友可以參考下
    2025-08-08
  • java實現(xiàn)多線程文件的斷點續(xù)傳

    java實現(xiàn)多線程文件的斷點續(xù)傳

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)多線程文件的斷點續(xù)傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Spring Boot集成Mybatis中如何顯示日志的實現(xiàn)

    Spring Boot集成Mybatis中如何顯示日志的實現(xiàn)

    這篇文章主要介紹了Spring Boot集成Mybatis中如何顯示日志的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java多線程ThreadForge的實現(xiàn)

    Java多線程ThreadForge的實現(xiàn)

    本文主要介紹了Java多線程ThreadForge的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-05-05

最新評論

射阳县| 绥德县| 新建县| 嘉黎县| 哈巴河县| 卢龙县| 宁强县| 大余县| 准格尔旗| 图木舒克市| 英德市| 堆龙德庆县| 新干县| 达尔| 盐山县| 探索| 平湖市| 甘肃省| 闽清县| 壶关县| 汉川市| 虞城县| 余江县| 九江市| 民权县| 兴安盟| 武威市| 咸阳市| 全州县| 缙云县| 浑源县| 兴文县| 辽中县| 富顺县| 蒙阴县| 高碑店市| 横峰县| 东丰县| 资中县| 东乡族自治县| 南昌县|